mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			466 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			466 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Java
		
	
	
	
/* MessageHeader.java -- GIOP message header.
 | 
						|
   Copyright (C) 2005 Free Software Foundation, Inc.
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
GNU Classpath 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
 | 
						|
General Public License for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
 | 
						|
package gnu.CORBA.GIOP;
 | 
						|
 | 
						|
import gnu.CORBA.Minor;
 | 
						|
import gnu.CORBA.Version;
 | 
						|
import gnu.CORBA.CDR.BigEndianInputStream;
 | 
						|
import gnu.CORBA.CDR.BigEndianOutputStream;
 | 
						|
import gnu.CORBA.CDR.LittleEndianInputStream;
 | 
						|
import gnu.CORBA.CDR.LittleEndianOutputStream;
 | 
						|
import gnu.CORBA.CDR.AbstractDataInput;
 | 
						|
import gnu.CORBA.CDR.AbstractDataOutput;
 | 
						|
 | 
						|
import gnu.java.lang.CPStringBuilder;
 | 
						|
 | 
						|
import org.omg.CORBA.MARSHAL;
 | 
						|
import org.omg.CORBA.portable.IDLEntity;
 | 
						|
 | 
						|
import java.io.ByteArrayOutputStream;
 | 
						|
import java.io.EOFException;
 | 
						|
import java.io.IOException;
 | 
						|
import java.io.InputStream;
 | 
						|
import java.io.OutputStream;
 | 
						|
import java.net.Socket;
 | 
						|
import java.util.Arrays;
 | 
						|
 | 
						|
/**
 | 
						|
 * The GIOP message header.
 | 
						|
 *
 | 
						|
 * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
 | 
						|
 */
 | 
						|
public class MessageHeader
 | 
						|
  implements IDLEntity
 | 
						|
{
 | 
						|
  /**
 | 
						|
   * Use serialVersionUID for interoperability.
 | 
						|
   */
 | 
						|
  private static final long serialVersionUID = 1;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Request message.
 | 
						|
   */
 | 
						|
  public static final byte REQUEST = 0;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Reply message
 | 
						|
   */
 | 
						|
  public static final byte REPLY = 1;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Cancel request message.
 | 
						|
   */
 | 
						|
  public static final byte CANCEL_REQUEST = 2;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Locate request message, used to check the server ability to process
 | 
						|
   * requests for the object reference. This message is also used to get the
 | 
						|
   * address where the object reference should be sent.
 | 
						|
   */
 | 
						|
  public static final byte LOCATE_REQUEST = 3;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Locate reply message, sent in response to the {@link #LocateRequest}
 | 
						|
   * message.
 | 
						|
   */
 | 
						|
  public static final byte LOCATE_REPLY = 4;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Instruction to close the connection.
 | 
						|
   */
 | 
						|
  public static final byte CLOSE_CONNECTION = 5;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Error report.
 | 
						|
   */
 | 
						|
  public static final byte MESSAGE_ERROR = 6;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The fragment messge, following the previous message that has more fragments
 | 
						|
   * flag set. Added in GIOP 1.1
 | 
						|
   */
 | 
						|
  public static final byte FRAGMENT = 7;
 | 
						|
 | 
						|
  /**
 | 
						|
   * This must always be "GIOP".
 | 
						|
   */
 | 
						|
  public static final byte[] MAGIC = new byte[] { 'G', 'I', 'O', 'P' };
 | 
						|
 | 
						|
  /**
 | 
						|
   * The message type names.
 | 
						|
   */
 | 
						|
  protected static String[] types = new String[] { "Request", "Reply",
 | 
						|
    "Cancel", "Locate request", "Locate reply", "Close connection", "Error",
 | 
						|
    "Fragment" };
 | 
						|
 | 
						|
  /**
 | 
						|
   * The GIOP version. Initialised to 1.0 .
 | 
						|
   */
 | 
						|
  public Version version;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The flags field, introduced since GIOP 1.1.
 | 
						|
   */
 | 
						|
  public byte flags = 0;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The message type.
 | 
						|
   */
 | 
						|
  public byte message_type = REQUEST;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The message size, excluding the message header.
 | 
						|
   */
 | 
						|
  public int message_size = 0;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Create an empty message header, corresponding version 1.0.
 | 
						|
   */
 | 
						|
  public MessageHeader()
 | 
						|
  {
 | 
						|
    version = new Version(1, 0);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Create an empty message header, corresponding the given version.
 | 
						|
   *
 | 
						|
   * @param major the major message header version.
 | 
						|
   * @param minor the minot message header version.
 | 
						|
   */
 | 
						|
  public MessageHeader(int major, int minor)
 | 
						|
  {
 | 
						|
    version = new Version(major, minor);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Checks if the message is encoded in the Big Endian, most significant byte
 | 
						|
   * first.
 | 
						|
   */
 | 
						|
  public boolean isBigEndian()
 | 
						|
  {
 | 
						|
    return (flags & 0x1) == 0;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Checks if the message is partial, and more subsequent fragments follow.
 | 
						|
   */
 | 
						|
  public boolean moreFragmentsFollow()
 | 
						|
  {
 | 
						|
    return (flags & 0x2) != 0;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Set the encoding to use.
 | 
						|
   *
 | 
						|
   * @param use_big_endian if true (default), the Big Endian encoding is used.
 | 
						|
   * If false, the Little Endian encoding is used.
 | 
						|
   */
 | 
						|
  public void setBigEndian(boolean use_big_endian)
 | 
						|
  {
 | 
						|
    if (use_big_endian)
 | 
						|
      flags = (byte) (flags & ~1);
 | 
						|
    else
 | 
						|
      flags = (byte) (flags | 1);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Get the size of the message header itself. So far, it is always 12 bytes.
 | 
						|
   */
 | 
						|
  public int getHeaderSize()
 | 
						|
  {
 | 
						|
    return 12;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Get the message type as string.
 | 
						|
   *
 | 
						|
   * @param type the message type as int (the field {@link message_type}).
 | 
						|
   *
 | 
						|
   * @return the message type as string.
 | 
						|
   */
 | 
						|
  public String getTypeString(int type)
 | 
						|
  {
 | 
						|
    try
 | 
						|
      {
 | 
						|
        return types[type];
 | 
						|
      }
 | 
						|
    catch (ArrayIndexOutOfBoundsException ex)
 | 
						|
      {
 | 
						|
        return "unknown type (" + type + ")";
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Creates reply header, matching the message header version number.
 | 
						|
   *
 | 
						|
   * @return one of {@link gnu.CORBA.GIOP.v1_0.ReplyHeader},
 | 
						|
   * {@link gnu.CORBA.GIOP.v1_2.ReplyHeader}, etc - depending on the version
 | 
						|
   * number in this header.
 | 
						|
   */
 | 
						|
  public ReplyHeader create_reply_header()
 | 
						|
  {
 | 
						|
    if (version.since_inclusive(1, 2))
 | 
						|
      return new gnu.CORBA.GIOP.v1_2.ReplyHeader();
 | 
						|
    else
 | 
						|
      return new gnu.CORBA.GIOP.v1_0.ReplyHeader();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Creates request header, matching the message header version number.
 | 
						|
   *
 | 
						|
   * @return one of {@link gnu.CORBA.GIOP.v1_0.RequestHeader},
 | 
						|
   * {@link gnu.CORBA.GIOP.v1_2.RequestHeader}, etc - depending on the version
 | 
						|
   * number in this header.
 | 
						|
   */
 | 
						|
  public RequestHeader create_request_header()
 | 
						|
  {
 | 
						|
    if (version.since_inclusive(1, 2))
 | 
						|
      return new gnu.CORBA.GIOP.v1_2.RequestHeader();
 | 
						|
    else
 | 
						|
      return new gnu.CORBA.GIOP.v1_0.RequestHeader();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Create the cancel header, matching the message header version number.
 | 
						|
   */
 | 
						|
  public CancelHeader create_cancel_header()
 | 
						|
  {
 | 
						|
    return new gnu.CORBA.GIOP.v1_0.CancelHeader();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Create the error message.
 | 
						|
   */
 | 
						|
  public ErrorMessage create_error_message()
 | 
						|
  {
 | 
						|
    return new ErrorMessage(version);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Read the header from the stream.
 | 
						|
   *
 | 
						|
   * @param istream a stream to read from.
 | 
						|
   * @throws MARSHAL if this is not a GIOP 1.0 header.
 | 
						|
   */
 | 
						|
  public void read(java.io.InputStream istream)
 | 
						|
    throws MARSHAL, EOFException
 | 
						|
  {
 | 
						|
    try
 | 
						|
      {
 | 
						|
        byte[] xMagic = new byte[MAGIC.length];
 | 
						|
        int r = istream.read(xMagic);
 | 
						|
        int minor;
 | 
						|
        if (! Arrays.equals(xMagic, MAGIC))
 | 
						|
          {
 | 
						|
            CPStringBuilder b = new CPStringBuilder();
 | 
						|
            if (r == - 1)
 | 
						|
              {
 | 
						|
                b.append("Immediate EOF");
 | 
						|
                minor = Minor.EOF;
 | 
						|
              }
 | 
						|
            else
 | 
						|
              {
 | 
						|
                minor = Minor.Giop;
 | 
						|
                b.append(r + " bytes: ");
 | 
						|
                for (int i = 0; i < xMagic.length; i++)
 | 
						|
                  {
 | 
						|
                    b.append(Integer.toHexString(xMagic[i] & 0xFF));
 | 
						|
                    b.append(' ');
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            MARSHAL m = new MARSHAL("Not a GIOP message: " + b);
 | 
						|
            m.minor = minor;
 | 
						|
            throw m;
 | 
						|
          }
 | 
						|
 | 
						|
        version = Version.read_version(istream);
 | 
						|
 | 
						|
        AbstractDataInput din;
 | 
						|
 | 
						|
        flags = (byte) istream.read();
 | 
						|
 | 
						|
        // This checks the bit in the byte we have just received.
 | 
						|
        if (isBigEndian())
 | 
						|
          din = new BigEndianInputStream(istream);
 | 
						|
        else
 | 
						|
          din = new LittleEndianInputStream(istream);
 | 
						|
 | 
						|
        message_type = (byte) din.read();
 | 
						|
 | 
						|
        message_size = din.readInt();
 | 
						|
      }
 | 
						|
    catch (IOException ex)
 | 
						|
      {
 | 
						|
        MARSHAL t = new MARSHAL();
 | 
						|
        t.minor = Minor.Header;
 | 
						|
        t.initCause(ex);
 | 
						|
        throw t;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Get the short string summary of the message.
 | 
						|
   *
 | 
						|
   * @return a short message summary.
 | 
						|
   */
 | 
						|
  public String toString()
 | 
						|
  {
 | 
						|
    return "GIOP " + version + ", " + (isBigEndian() ? "Big" : "Little")
 | 
						|
      + " endian, " + getTypeString(message_type) + ", " + message_size
 | 
						|
      + " bytes. ";
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Write the header to stream.
 | 
						|
   *
 | 
						|
   * @param out a stream to write into.
 | 
						|
   */
 | 
						|
  public void write(java.io.OutputStream out)
 | 
						|
  {
 | 
						|
    try
 | 
						|
      {
 | 
						|
        AbstractDataOutput dout;
 | 
						|
 | 
						|
        if (isBigEndian())
 | 
						|
          dout = new BigEndianOutputStream(out);
 | 
						|
        else
 | 
						|
          dout = new LittleEndianOutputStream(out);
 | 
						|
 | 
						|
        // Write magic sequence.
 | 
						|
        dout.write(MAGIC);
 | 
						|
 | 
						|
        // Write version number.
 | 
						|
        version.write((OutputStream) dout);
 | 
						|
        dout.write(flags);
 | 
						|
        dout.write(message_type);
 | 
						|
        dout.writeInt(message_size);
 | 
						|
      }
 | 
						|
    catch (IOException ex)
 | 
						|
      {
 | 
						|
        MARSHAL t = new MARSHAL(ex.getMessage());
 | 
						|
        t.minor = Minor.Header;
 | 
						|
        t.initCause(ex);
 | 
						|
        throw t;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Read data, followed by the message header. Handle fragmented messages.
 | 
						|
   *
 | 
						|
   * @param source the data source to read from.
 | 
						|
   * @param service the socket on that the time outs are set. Can be null (no
 | 
						|
   * timeouts are set).
 | 
						|
   * @param to_read the timeout while reading the message.
 | 
						|
   * @param to_pause the timeout for pauses between the message parts.
 | 
						|
   */
 | 
						|
  public byte[] readMessage(InputStream source, Socket service, int to_read,
 | 
						|
    int to_pause)
 | 
						|
  {
 | 
						|
    try
 | 
						|
      {
 | 
						|
        byte[] r = new byte[message_size];
 | 
						|
 | 
						|
        int n = 0;
 | 
						|
        if (service != null)
 | 
						|
          service.setSoTimeout(to_read);
 | 
						|
 | 
						|
        while (n < r.length)
 | 
						|
          {
 | 
						|
            n += source.read(r, n, r.length - n);
 | 
						|
          }
 | 
						|
        if (service != null)
 | 
						|
          service.setSoTimeout(to_pause);
 | 
						|
 | 
						|
        // Read the message remainder if the message is fragmented.
 | 
						|
        if (moreFragmentsFollow())
 | 
						|
          {
 | 
						|
            ByteArrayOutputStream buffer = new ByteArrayOutputStream(
 | 
						|
              2 * r.length);
 | 
						|
            buffer.write(r);
 | 
						|
 | 
						|
            if (r.length < 10)
 | 
						|
              // Increase the buffer size if the default value (size of the
 | 
						|
              // previous message) is really too small.
 | 
						|
              r = new byte[1024];
 | 
						|
 | 
						|
            MessageHeader h2 = new MessageHeader();
 | 
						|
 | 
						|
            do
 | 
						|
              {
 | 
						|
                h2.read(source);
 | 
						|
 | 
						|
                int dn;
 | 
						|
 | 
						|
                n = 0;
 | 
						|
                while (n < h2.message_size)
 | 
						|
                  {
 | 
						|
                    dn = source.read(r, 0, h2.message_size - n);
 | 
						|
 | 
						|
                    if (n == 0 && service != null)
 | 
						|
                      service.setSoTimeout(to_read);
 | 
						|
 | 
						|
                    if (n == 0 && version.since_inclusive(1, 2))
 | 
						|
                      {
 | 
						|
                        // Skip the four byte request id.
 | 
						|
                        buffer.write(r, 4, dn - 4);
 | 
						|
                      }
 | 
						|
                    else
 | 
						|
                      buffer.write(r, 0, dn);
 | 
						|
                    n = +dn;
 | 
						|
                  }
 | 
						|
 | 
						|
                if (service != null)
 | 
						|
                  service.setSoTimeout(to_pause);
 | 
						|
              }
 | 
						|
            while (h2.moreFragmentsFollow());
 | 
						|
            return buffer.toByteArray();
 | 
						|
          }
 | 
						|
        else
 | 
						|
          return r;
 | 
						|
      }
 | 
						|
    catch (IOException ioex)
 | 
						|
      {
 | 
						|
        MARSHAL m = new MARSHAL("Unable to read the message continuation.");
 | 
						|
        m.minor = Minor.Header;
 | 
						|
        m.initCause(ioex);
 | 
						|
        throw m;
 | 
						|
      }
 | 
						|
  }
 | 
						|
}
 |