Monitor.java :  » Web-Server » simple » simple » http » Java Open Source

Java Open Source » Web Server » simple 
simple » simple » http » Monitor.java
/*
 * Monitor.java February 2001
 *
 * Copyright (C) 2001, Niall Gallagher <niallg@users.sf.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General 
 * Public License along with this library; if not, write to the 
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
 * Boston, MA  02111-1307  USA
 */
 
package simple.http;

import java.io.OutputStream;
import java.io.InputStream;

/**
 * This is a <code>Monitor</code> object that is used to reprocess 
 * a <code>Poller</code>. When a request has been taken from a the
 * <code>Pipeline</code> being polled, and a reponse has been issued,
 * then this means that that <code>Pipeline</code> is no longer being
 * used, and so the <code>Pipeline</code> is ready to be used in the 
 * next request. 
 * <p>
 * If however there was an error in processing the current request 
 * then this <code>Monitor</code> will be notified. In the case that 
 * there was an error in processing a request/response transaction 
 * using this <code>Poller</code> then the <code>Poller</code> will 
 * not be reprocessed. The <code>Poller</code> is only reprocessed 
 * when the transaction is finished, indicated by a 
 * <code>notifyFinished</code> for both the <code>OutputStream</code> 
 * and the <code>InputStream</code> of the <code>Pipeline</code>. 
 * <p>
 * Also if there was a <code>notifyClose</code> event then the 
 * <code>Poller</code> will be closed by calling the <code>close</code> 
 * method. In this case the <code>Poller</code> will not be reprocessed. 
 * <p>
 * In summary this is used to indicate when the next HTTP message 
 * header is the next group of bytes on the <code>Pipeline</code> 
 * and the <code>Pipeline</code>'s output for the previous request 
 * has been made.
 *
 * @author Niall Gallagher
 */ 
final class Monitor implements InputMonitor, OutputMonitor {

   /**
    * A bitwise mask indicating close or error notification.
    */
   private static int CLOSE_STREAM = 0x1; 

   /**
    * This is a bitwise mask indicating input notification.
    */
   private static int INPUT_NOTIFIED = 0x2; 

   /**
    * This is a bitwise mask indicating input notification.
    */
   private static int OUTPUT_NOTIFIED = 0x4; 

   /**
    * A bitwise mask indicating output and input notification.
    */
   private static int BOTH_NOTIFIED = 0x6; 

   /**
    * A bitwise mask indicating close and input notification.
    */
   private static int INPUT_CLOSE = 0x3;  

   /**
    * A bitwise mask indicating output and close notification.
    */
   private static int OUTPUT_CLOSE = 0x5; 

   /**
    * Processes the <code>Poller</code> when its finished.
    */
   private PollerHandler handler;
  
   /**
    * This is the <code>Poller</code> object for this 
    * <code>Monitor</code>.
    */
   private Poller poller;
   
   /**
    * This accumulates the events that this <code>Monitor</code>
    * has recived, for example <code>notifyFinished</code>.
    */
   private int mask;

   /**
    * Creates a monitor to monitor access to the <code>Pipeline</code>. 
    * When an <code>InputStream</code> or <code>OutputStream</code> 
    * gives any event notification to this <code>Monitor</code> it 
    * reprocesses the <code>Poller</code> for that <code>Pipeline</code>.
    * <p>
    * The reprocessing is done only if both the <code>InputStream</code> 
    * and the <code>OutputStream</code> issue <code>notifyFinished</code>. 
    * events. If a <code>notifyError</code> or a <code>notifyClose</code> 
    * event is issued by any of the monitored streams then the 
    * <code>Poller</code> is closed and not reprocessed.
    *
    * @param handler the <code>PollerHandler</code> that will
    * process the <code>Processor</code>
    * @param poller the <code>Poller</code> top be reprocessed
    */ 
   public Monitor(PollerHandler handler, Poller poller) {
      this.handler = handler;
      this.poller = poller;
   }

   /**
    * This will pass the <code>Poller</code> back to the
    * <code>PiplineProcesor</code> when the <code>Poller</code> is 
    * ready. The <code>Poller</code> is considered ready when both 
    * the <code>InputMonitor</code> and the <code>OutputMonitor</code> 
    * recive the <code>notifyFinished</code> notification. The
    * <code>Poller</code> will only be reprocessed if there is no
    * notification of an error using <code>notifyError</code> or
    * close using <code>notifyClose</code>.
    */ 
   private void reprocess() {
      try {
         handler.notifyWait(poller);
      }catch(Exception io) {
         poller.close();
      }
   }

   /**
    * This method will not do any thing but mark the stream as
    * finished. This indicates that some object is finished with
    * this <code>InputStream</code> this allows the
    * <code>Poller</code> to be reprocessed.
    *
    * @param in this is the <code>InputStream</code> that is being
    * monitored
    */  
   public synchronized void notifyFinished(InputStream in){    
      if((mask & BOTH_NOTIFIED)==BOTH_NOTIFIED) {
         return; 
      } else if((mask & OUTPUT_CLOSE) == OUTPUT_CLOSE){    
         poller.close();
      } else if((mask & OUTPUT_NOTIFIED) >0) {
         reprocess();
      }
      mask |= INPUT_NOTIFIED;
   }


   /**
    * This will notify that the stream in should be closed. The 
    * stream will be closed by the <code>InputMonitor</code> and
    * not the object that is notifying the <code>InputMonitor</code>.
    *
    * @param in this is the <code>InputStream</code> being
    * monitored
    */  
   public synchronized void notifyClose(InputStream in){
      if((mask & BOTH_NOTIFIED) == BOTH_NOTIFIED) {
         return; 
      } else if((mask &OUTPUT_NOTIFIED) >0){
         poller.close();
      }     
      mask |= INPUT_CLOSE; 
   }

   /**
    * This will notify that the stream has encountered an error.
    * There should be no further interaction with the
    * <code>InputStream</code> after this has been invoked. The
    * stream will subsequently be closed by the
    * <code>InputMonitor</code> when both I/O totally ceases.
    *
    * @param in this is the <code>InputStream</code> being
    * monitored
    */ 
   public synchronized void notifyError(InputStream in){
      if((mask &BOTH_NOTIFIED) == BOTH_NOTIFIED) {
         return; 
      } else if((mask & OUTPUT_NOTIFIED) >0){
         poller.close();
      } 
      mask |= INPUT_CLOSE;
   }
   
   /**
    * This will simply mark this stream as finished. This means
    * that the <code>OutputStream</code> or object that was
    * monitoring this <code>OutputStream</code> is now finished
    * using it. The <code>OutputStream</code> out must not be 
    * used by the object that made the invocation from this point
    * on, because the <code>Poller</code> will now control the 
    * stream.
    *
    * @param out this is the <code>OutputStream</code> that is 
    * being monitored
    */ 
   public synchronized void notifyFinished(OutputStream out){
      if((mask & BOTH_NOTIFIED) ==BOTH_NOTIFIED) {
         return; 
      } else if((mask & INPUT_CLOSE) == INPUT_CLOSE){         
         poller.close();
      } else {
         flushOutput(out); 
         if((mask & INPUT_NOTIFIED) >0) {
            reprocess();
         }
      } 
      mask |= OUTPUT_NOTIFIED;
   }

   /**
    * When the monitor has notified that it is finished and that the 
    * <code>Poller</code> is to be reprocessed then the response needs 
    * to be flushed to the client. This will attempt to flush the 
    * response that may be buffered in the <code>OutputStream</code> 
    * to the client. This is an important step.
    *
    * @param out the <code>OutputStream</code> to be flushed
    */     
   private void flushOutput(OutputStream out) {
      try {
         out.flush();
      }catch(Exception io){
         poller.close();         
      }
   }

   /**
    * This will notify that this <code>OutputStream</code> should be
    * closed. It is the task of the <code>OutputMonitor</code> and 
    * not the object that is making the invocation to close the
    * <code>OutputStream</code>.
    *
    * @param out this is the <code>OutputStream</code> being
    * monitored
    */ 
   public synchronized void notifyClose(OutputStream out){
      if((mask & BOTH_NOTIFIED) == BOTH_NOTIFIED) {
         return; 
      } else if((mask & INPUT_NOTIFIED) > 0){
         poller.close();
      }      
      mask |= OUTPUT_CLOSE;
   }

   /**
    * This will notify the monitor that an error occured when
    * writing to the <code>OutputStream</code>. The
    * <code>OutputMonitor</code> will in its own time (mabye
    * asynchronously) close the <code>OutputStream</code>.
    *
    * @param out this is the <code>OutputStream</code> being
    * monitored
    */ 
   public synchronized void notifyError(OutputStream out){
      if((mask & BOTH_NOTIFIED) == BOTH_NOTIFIED) {
         return; 
      } else if((mask & INPUT_NOTIFIED) >0){
         poller.close();
      } 
      mask = OUTPUT_CLOSE;
   }
}

java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.