1 /* MessageHeader.java -- GIOP message header.
2 Copyright (C) 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu.CORBA.GIOP;
41 import gnu.CORBA.Minor;
42 import gnu.CORBA.Version;
43 import gnu.CORBA.CDR.BigEndianInputStream;
44 import gnu.CORBA.CDR.BigEndianOutputStream;
45 import gnu.CORBA.CDR.LittleEndianInputStream;
46 import gnu.CORBA.CDR.LittleEndianOutputStream;
47 import gnu.CORBA.CDR.AbstractDataInput;
48 import gnu.CORBA.CDR.AbstractDataOutput;
50 import gnu.java.lang.CPStringBuilder;
52 import org.omg.CORBA.MARSHAL;
53 import org.omg.CORBA.portable.IDLEntity;
55 import java.io.ByteArrayOutputStream;
56 import java.io.EOFException;
57 import java.io.IOException;
58 import java.io.InputStream;
59 import java.io.OutputStream;
60 import java.net.Socket;
61 import java.util.Arrays;
64 * The GIOP message header.
66 * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
68 public class MessageHeader
72 * Use serialVersionUID for interoperability.
74 private static final long serialVersionUID = 1;
79 public static final byte REQUEST = 0;
84 public static final byte REPLY = 1;
87 * Cancel request message.
89 public static final byte CANCEL_REQUEST = 2;
92 * Locate request message, used to check the server ability to process
93 * requests for the object reference. This message is also used to get the
94 * address where the object reference should be sent.
96 public static final byte LOCATE_REQUEST = 3;
99 * Locate reply message, sent in response to the {@link #LocateRequest}
102 public static final byte LOCATE_REPLY = 4;
105 * Instruction to close the connection.
107 public static final byte CLOSE_CONNECTION = 5;
112 public static final byte MESSAGE_ERROR = 6;
115 * The fragment messge, following the previous message that has more fragments
116 * flag set. Added in GIOP 1.1
118 public static final byte FRAGMENT = 7;
121 * This must always be "GIOP".
123 public static final byte[] MAGIC = new byte[] { 'G', 'I', 'O', 'P' };
126 * The message type names.
128 protected static String[] types = new String[] { "Request", "Reply",
129 "Cancel", "Locate request", "Locate reply", "Close connection", "Error",
133 * The GIOP version. Initialised to 1.0 .
135 public Version version;
138 * The flags field, introduced since GIOP 1.1.
140 public byte flags = 0;
145 public byte message_type = REQUEST;
148 * The message size, excluding the message header.
150 public int message_size = 0;
153 * Create an empty message header, corresponding version 1.0.
155 public MessageHeader()
157 version = new Version(1, 0);
161 * Create an empty message header, corresponding the given version.
163 * @param major the major message header version.
164 * @param minor the minot message header version.
166 public MessageHeader(int major, int minor)
168 version = new Version(major, minor);
172 * Checks if the message is encoded in the Big Endian, most significant byte
175 public boolean isBigEndian()
177 return (flags & 0x1) == 0;
181 * Checks if the message is partial, and more subsequent fragments follow.
183 public boolean moreFragmentsFollow()
185 return (flags & 0x2) != 0;
189 * Set the encoding to use.
191 * @param use_big_endian if true (default), the Big Endian encoding is used.
192 * If false, the Little Endian encoding is used.
194 public void setBigEndian(boolean use_big_endian)
197 flags = (byte) (flags & ~1);
199 flags = (byte) (flags | 1);
203 * Get the size of the message header itself. So far, it is always 12 bytes.
205 public int getHeaderSize()
211 * Get the message type as string.
213 * @param type the message type as int (the field {@link message_type}).
215 * @return the message type as string.
217 public String getTypeString(int type)
223 catch (ArrayIndexOutOfBoundsException ex)
225 return "unknown type (" + type + ")";
230 * Creates reply header, matching the message header version number.
232 * @return one of {@link gnu.CORBA.GIOP.v1_0.ReplyHeader},
233 * {@link gnu.CORBA.GIOP.v1_2.ReplyHeader}, etc - depending on the version
234 * number in this header.
236 public ReplyHeader create_reply_header()
238 if (version.since_inclusive(1, 2))
239 return new gnu.CORBA.GIOP.v1_2.ReplyHeader();
241 return new gnu.CORBA.GIOP.v1_0.ReplyHeader();
245 * Creates request header, matching the message header version number.
247 * @return one of {@link gnu.CORBA.GIOP.v1_0.RequestHeader},
248 * {@link gnu.CORBA.GIOP.v1_2.RequestHeader}, etc - depending on the version
249 * number in this header.
251 public RequestHeader create_request_header()
253 if (version.since_inclusive(1, 2))
254 return new gnu.CORBA.GIOP.v1_2.RequestHeader();
256 return new gnu.CORBA.GIOP.v1_0.RequestHeader();
260 * Create the cancel header, matching the message header version number.
262 public CancelHeader create_cancel_header()
264 return new gnu.CORBA.GIOP.v1_0.CancelHeader();
268 * Create the error message.
270 public ErrorMessage create_error_message()
272 return new ErrorMessage(version);
276 * Read the header from the stream.
278 * @param istream a stream to read from.
279 * @throws MARSHAL if this is not a GIOP 1.0 header.
281 public void read(java.io.InputStream istream)
282 throws MARSHAL, EOFException
286 byte[] xMagic = new byte[MAGIC.length];
287 int r = istream.read(xMagic);
289 if (! Arrays.equals(xMagic, MAGIC))
291 CPStringBuilder b = new CPStringBuilder();
294 b.append("Immediate EOF");
300 b.append(r + " bytes: ");
301 for (int i = 0; i < xMagic.length; i++)
303 b.append(Integer.toHexString(xMagic[i] & 0xFF));
307 MARSHAL m = new MARSHAL("Not a GIOP message: " + b);
312 version = Version.read_version(istream);
314 AbstractDataInput din;
316 flags = (byte) istream.read();
318 // This checks the bit in the byte we have just received.
320 din = new BigEndianInputStream(istream);
322 din = new LittleEndianInputStream(istream);
324 message_type = (byte) din.read();
326 message_size = din.readInt();
328 catch (IOException ex)
330 MARSHAL t = new MARSHAL();
331 t.minor = Minor.Header;
338 * Get the short string summary of the message.
340 * @return a short message summary.
342 public String toString()
344 return "GIOP " + version + ", " + (isBigEndian() ? "Big" : "Little")
345 + " endian, " + getTypeString(message_type) + ", " + message_size
350 * Write the header to stream.
352 * @param out a stream to write into.
354 public void write(java.io.OutputStream out)
358 AbstractDataOutput dout;
361 dout = new BigEndianOutputStream(out);
363 dout = new LittleEndianOutputStream(out);
365 // Write magic sequence.
368 // Write version number.
369 version.write((OutputStream) dout);
371 dout.write(message_type);
372 dout.writeInt(message_size);
374 catch (IOException ex)
376 MARSHAL t = new MARSHAL(ex.getMessage());
377 t.minor = Minor.Header;
384 * Read data, followed by the message header. Handle fragmented messages.
386 * @param source the data source to read from.
387 * @param service the socket on that the time outs are set. Can be null (no
389 * @param to_read the timeout while reading the message.
390 * @param to_pause the timeout for pauses between the message parts.
392 public byte[] readMessage(InputStream source, Socket service, int to_read,
397 byte[] r = new byte[message_size];
401 service.setSoTimeout(to_read);
405 n += source.read(r, n, r.length - n);
408 service.setSoTimeout(to_pause);
410 // Read the message remainder if the message is fragmented.
411 if (moreFragmentsFollow())
413 ByteArrayOutputStream buffer = new ByteArrayOutputStream(
418 // Increase the buffer size if the default value (size of the
419 // previous message) is really too small.
422 MessageHeader h2 = new MessageHeader();
431 while (n < h2.message_size)
433 dn = source.read(r, 0, h2.message_size - n);
435 if (n == 0 && service != null)
436 service.setSoTimeout(to_read);
438 if (n == 0 && version.since_inclusive(1, 2))
440 // Skip the four byte request id.
441 buffer.write(r, 4, dn - 4);
444 buffer.write(r, 0, dn);
449 service.setSoTimeout(to_pause);
451 while (h2.moreFragmentsFollow());
452 return buffer.toByteArray();
457 catch (IOException ioex)
459 MARSHAL m = new MARSHAL("Unable to read the message continuation.");
460 m.minor = Minor.Header;