Package fr.dyade.aaa.agent

Source Code of fr.dyade.aaa.agent.MessageOutputStream

/*
* Copyright (C) 2008 ScalAgent Distributed Technologies
*
* 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; either
* version 2.1 of the License, or any later version.
*
* 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 fr.dyade.aaa.agent;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamConstants;
import java.io.OutputStream;
import java.util.zip.GZIPOutputStream;

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;

/**
* Class used to send messages through a stream.
* <p>
* This OutputStream is a combination between a ByteArrayOutputStream and a
* BufferedOutputStream. It allows the replacement of the underlying stream and
* the serialization of object through an internal ObjectOutputStream.
* <p>
* Be careful this OutputStream is not synchronized.
*/
public abstract class MessageOutputStream extends OutputStream {
  /**
   * The internal ObjectOutputStream needed to serialize the notification.
   */
  protected ObjectOutputStream oos;

  /**
   * The internal buffer where data is stored.
   */
  protected byte buf[];

  /**
   * The number of valid bytes in the buffer.
   */
  protected int count;

  protected boolean compressedFlows = false;
 
  /**
   * Default logger for MessageOutputStream.
   */
  protected static Logger logmon = null;
 
  /**
   * Returns default logger for MessageOutputStream.
   * @return Default logger for MessageOutputStream.
   */
  protected static Logger getLogger() {
    if (logmon == null)
      logmon = Debug.getLogger("fr.dyade.aaa.agent.MessageOutputStream");
    return logmon;
  }
 
  // ObjectStream constants needed to reinitialize the ObjectOutputStream.
  private static final byte STREAM_MAGIC1 =
    (byte)((ObjectStreamConstants.STREAM_MAGIC >>> 8) & 0xFF);
  private static final byte STREAM_MAGIC2 =
    (byte)((ObjectStreamConstants.STREAM_MAGIC >>> 0) & 0xFF);
  private static final byte STREAM_VERSION1 =
    (byte)((ObjectStreamConstants.STREAM_VERSION >>> 8) & 0xFF);
  private static final byte STREAM_VERSION2 =
    (byte)((ObjectStreamConstants.STREAM_VERSION >>> 0) & 0xFF);

  /**
   *  Creates a new output stream to write data to an unspecified
   * underlying output stream through a buffer with default size.
   */
  public MessageOutputStream() throws IOException {
    this(8192);
  }

  /**
   *  Creates a new output stream to write data to an unspecified
   * underlying output stream through a buffer with specified size.
   *
   * @param size the buffer size.
   * @exception IllegalArgumentException if size is less than 0.
   * @exception IOException if the internal ObjectOutputStream cannot be
   *    correctly initialized.
   */
  public MessageOutputStream(int size) throws IOException {
    if (size <= 0)
      throw new IllegalArgumentException("Buffer size <= 0");
    buf = new byte[size];

    if (! compressedFlows)
      oos = new ObjectOutputStream(this);
    count = 0;
  }

  /**
   * Writes the specified byte to this output stream.
   *
   * @param      b   the byte to be written.
   * @exception  IOException  if an I/O error occurs.
   */
  public abstract void write(int b) throws IOException;

  /**
   * Writes <code>b.length</code> bytes to this output stream.
   * <p>
   * This method calls its <code>write</code> method of three arguments with
   * the  arguments <code>b</code>, <code>0</code>, and <code>b.length</code>.
   *
   * @param      b   the data to be written.
   * @exception  IOException  if an I/O error occurs.
   * @see        write(byte[], int, int)
   */
  public final void write(byte b[]) throws IOException {
    write(b, 0, b.length);
  }

  /**
   * Writes <code>len</code> bytes from the specified byte array starting
   * at offset <code>off</code> to this output stream.
   *
   * @param      b     the data.
   * @param      off   the start offset in the data.
   * @param      len   the number of bytes to write.
   * @exception  IOException  if an I/O error occurs.
   */
  public abstract void write(byte b[], int off, int len) throws IOException;

  /**
   * Writes a short directly to the buffer.
   * Be careful, the buffer must be large enough to contain the short.
   *
   * @param      s     the data.
   */
  protected final void writeShort(short s) {
    buf[count++] = (byte) (s >>>  8);
    buf[count++] = (byte) (s >>>  0);
  }

  /**
   * Writes an int directly to the buffer.
   * Be careful, the buffer must be large enough to contain the int.
   *
   * @param      i     the data.
   */
  protected final void writeInt(int i) {
    buf[count++] = (byte) (i >>>  24);
    buf[count++] = (byte) (i >>>  16);
    buf[count++] = (byte) (i >>>  8);
    buf[count++] = (byte) (i >>>  0);
  }

  /**
   * Writes the protocol header to this output stream.
   * This method must be overloaded in subclass.
   */
  abstract protected void writeHeader() throws IOException;

  /**
   * Writes the message header data to the buffer.
   *
   * @param msg The message to write out.
   */
  protected final void writeMessageHeader(Message msg) {
    if (getLogger().isLoggable(BasicLevel.DEBUG))
      getLogger().log(BasicLevel.DEBUG, "writeMessageHeader()");
   
    // Writes sender's AgentId
    writeShort(msg.from.from);
    writeShort(msg.from.to);
    writeInt(msg.from.stamp);
    // Writes adressee's AgentId
    writeShort(msg.to.from);
    writeShort(msg.to.to);
    writeInt(msg.to.stamp);
    // Writes source server id of message
    writeShort(msg.source);
    // Writes destination server id of message
    writeShort(msg.dest);
    // Writes stamp of message
    writeInt(msg.stamp);
   
    if (getLogger().isLoggable(BasicLevel.DEBUG))
      getLogger().log(BasicLevel.DEBUG, "writeMessageHeader returns");
  }

  /**
   * Writes a message to this output stream.
   * This method can be overloaded in subclass.
   *
   * @param msg  The message to write out.
   * @param time The current time in milliseconds, this parameter
   *             is used to the handling of notification expiration.
   */
  protected final void writeMessage(Message msg,
                                    long time) throws IOException {
    if (getLogger().isLoggable(BasicLevel.DEBUG))
      getLogger().log(BasicLevel.DEBUG, "writeMessage()");
   
    // Writes the protocol specific data.
    writeHeader();

    if (msg != null) {
      // Writes the message header data.
      writeMessageHeader(msg);

      if (msg.not == null) {
        if (getLogger().isLoggable(BasicLevel.DEBUG))
          getLogger().log(BasicLevel.DEBUG, "writeMessage - 1");
       
        buf[count++] = Message.NULL;
        flush();
      } else {
        if (getLogger().isLoggable(BasicLevel.DEBUG))
          getLogger().log(BasicLevel.DEBUG, "writeMessage - 2");
       
        // Writes notification attributes
        buf[count++] = msg.optToByte();

        try {
          if (msg.not.expiration > 0)
            msg.not.expiration -= time;

          // Writes a serializable object to this output stream.
          if (compressedFlows) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            GZIPOutputStream gzipos = new GZIPOutputStream(baos);
           
            oos = new ObjectOutputStream(gzipos);
            oos.writeObject(msg.not);

            // Be careful, the reset writes a TC_RESET byte
            oos.reset();
            // The OOS flush call the flush of this output stream.
            oos.flush();
            gzipos.finish();
            gzipos.flush();
           
            if (getLogger().isLoggable(BasicLevel.DEBUG))
              getLogger().log(BasicLevel.DEBUG, "writeNotification - size=" + baos.size());

            writeInt(baos.size());
            baos.writeTo(this);
           
            flush();
           
            oos = null;
          } else {
            // Write the STREAM_MAGIC constant
            buf[count++] = STREAM_MAGIC1;
            buf[count++] = STREAM_MAGIC2;
            // Write the STREAM_VERSION constant
            buf[count++] = STREAM_VERSION1;
            buf[count++] = STREAM_VERSION2;
            oos.writeObject(msg.not);

            // Be careful, the reset writes a TC_RESET byte
            oos.reset();
            // The OOS flush call the flush of this output stream.
            oos.flush();
          }
        } finally {
          if ((msg.not != null) && (msg.not.expiration > 0))
            msg.not.expiration += time;
        }
      }
    } else {
      flush();
    }
   
    if (getLogger().isLoggable(BasicLevel.DEBUG))
      getLogger().log(BasicLevel.DEBUG, "writeMessage returns");
  }
}
TOP

Related Classes of fr.dyade.aaa.agent.MessageOutputStream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.