libjava/
[official-gcc.git] / libjava / classpath / gnu / CORBA / GIOP / MessageHeader.java
blobcac2405fc778302c4d4925d1617c2b99a9f3684a
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)
9 any later version.
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
19 02110-1301 USA.
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
24 combination.
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 org.omg.CORBA.MARSHAL;
51 import org.omg.CORBA.portable.IDLEntity;
53 import java.io.ByteArrayOutputStream;
54 import java.io.EOFException;
55 import java.io.IOException;
56 import java.io.InputStream;
57 import java.io.OutputStream;
58 import java.net.Socket;
59 import java.util.Arrays;
61 /**
62 * The GIOP message header.
64 * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
66 public class MessageHeader
67 implements IDLEntity
69 /**
70 * Use serialVersionUID for interoperability.
72 private static final long serialVersionUID = 1;
74 /**
75 * Request message.
77 public static final byte REQUEST = 0;
79 /**
80 * Reply message
82 public static final byte REPLY = 1;
84 /**
85 * Cancel request message.
87 public static final byte CANCEL_REQUEST = 2;
89 /**
90 * Locate request message, used to check the server ability to process
91 * requests for the object reference. This message is also used to get the
92 * address where the object reference should be sent.
94 public static final byte LOCATE_REQUEST = 3;
96 /**
97 * Locate reply message, sent in response to the {@link #LocateRequest}
98 * message.
100 public static final byte LOCATE_REPLY = 4;
103 * Instruction to close the connection.
105 public static final byte CLOSE_CONNECTION = 5;
108 * Error report.
110 public static final byte MESSAGE_ERROR = 6;
113 * The fragment messge, following the previous message that has more fragments
114 * flag set. Added in GIOP 1.1
116 public static final byte FRAGMENT = 7;
119 * This must always be "GIOP".
121 public static final byte[] MAGIC = new byte[] { 'G', 'I', 'O', 'P' };
124 * The message type names.
126 protected static String[] types = new String[] { "Request", "Reply",
127 "Cancel", "Locate request", "Locate reply", "Close connection", "Error",
128 "Fragment" };
131 * The GIOP version. Initialised to 1.0 .
133 public Version version;
136 * The flags field, introduced since GIOP 1.1.
138 public byte flags = 0;
141 * The message type.
143 public byte message_type = REQUEST;
146 * The message size, excluding the message header.
148 public int message_size = 0;
151 * Create an empty message header, corresponding version 1.0.
153 public MessageHeader()
155 version = new Version(1, 0);
159 * Create an empty message header, corresponding the given version.
161 * @param major the major message header version.
162 * @param minor the minot message header version.
164 public MessageHeader(int major, int minor)
166 version = new Version(major, minor);
170 * Checks if the message is encoded in the Big Endian, most significant byte
171 * first.
173 public boolean isBigEndian()
175 return (flags & 0x1) == 0;
179 * Checks if the message is partial, and more subsequent fragments follow.
181 public boolean moreFragmentsFollow()
183 return (flags & 0x2) != 0;
187 * Set the encoding to use.
189 * @param use_big_endian if true (default), the Big Endian encoding is used.
190 * If false, the Little Endian encoding is used.
192 public void setBigEndian(boolean use_big_endian)
194 if (use_big_endian)
195 flags = (byte) (flags & ~1);
196 else
197 flags = (byte) (flags | 1);
201 * Get the size of the message header itself. So far, it is always 12 bytes.
203 public int getHeaderSize()
205 return 12;
209 * Get the message type as string.
211 * @param type the message type as int (the field {@link message_type}).
213 * @return the message type as string.
215 public String getTypeString(int type)
219 return types[type];
221 catch (ArrayIndexOutOfBoundsException ex)
223 return "unknown type (" + type + ")";
228 * Creates reply header, matching the message header version number.
230 * @return one of {@link gnu.CORBA.GIOP.v1_0.ReplyHeader},
231 * {@link gnu.CORBA.GIOP.v1_2.ReplyHeader}, etc - depending on the version
232 * number in this header.
234 public ReplyHeader create_reply_header()
236 if (version.since_inclusive(1, 2))
237 return new gnu.CORBA.GIOP.v1_2.ReplyHeader();
238 else
239 return new gnu.CORBA.GIOP.v1_0.ReplyHeader();
243 * Creates request header, matching the message header version number.
245 * @return one of {@link gnu.CORBA.GIOP.v1_0.RequestHeader},
246 * {@link gnu.CORBA.GIOP.v1_2.RequestHeader}, etc - depending on the version
247 * number in this header.
249 public RequestHeader create_request_header()
251 if (version.since_inclusive(1, 2))
252 return new gnu.CORBA.GIOP.v1_2.RequestHeader();
253 else
254 return new gnu.CORBA.GIOP.v1_0.RequestHeader();
258 * Create the cancel header, matching the message header version number.
260 public CancelHeader create_cancel_header()
262 return new gnu.CORBA.GIOP.v1_0.CancelHeader();
266 * Create the error message.
268 public ErrorMessage create_error_message()
270 return new ErrorMessage(version);
274 * Read the header from the stream.
276 * @param istream a stream to read from.
277 * @throws MARSHAL if this is not a GIOP 1.0 header.
279 public void read(java.io.InputStream istream)
280 throws MARSHAL, EOFException
284 byte[] xMagic = new byte[MAGIC.length];
285 int r = istream.read(xMagic);
286 int minor;
287 if (! Arrays.equals(xMagic, MAGIC))
289 StringBuffer b = new StringBuffer();
290 if (r == - 1)
292 b.append("Immediate EOF");
293 minor = Minor.EOF;
295 else
297 minor = Minor.Giop;
298 b.append(r + " bytes: ");
299 for (int i = 0; i < xMagic.length; i++)
301 b.append(Integer.toHexString(xMagic[i] & 0xFF));
302 b.append(' ');
305 MARSHAL m = new MARSHAL("Not a GIOP message: " + b);
306 m.minor = minor;
307 throw m;
310 version = Version.read_version(istream);
312 AbstractDataInput din;
314 flags = (byte) istream.read();
316 // This checks the bit in the byte we have just received.
317 if (isBigEndian())
318 din = new BigEndianInputStream(istream);
319 else
320 din = new LittleEndianInputStream(istream);
322 message_type = (byte) din.read();
324 message_size = din.readInt();
326 catch (IOException ex)
328 MARSHAL t = new MARSHAL();
329 t.minor = Minor.Header;
330 t.initCause(ex);
331 throw t;
336 * Get the short string summary of the message.
338 * @return a short message summary.
340 public String toString()
342 return "GIOP " + version + ", " + (isBigEndian() ? "Big" : "Little")
343 + " endian, " + getTypeString(message_type) + ", " + message_size
344 + " bytes. ";
348 * Write the header to stream.
350 * @param out a stream to write into.
352 public void write(java.io.OutputStream out)
356 AbstractDataOutput dout;
358 if (isBigEndian())
359 dout = new BigEndianOutputStream(out);
360 else
361 dout = new LittleEndianOutputStream(out);
363 // Write magic sequence.
364 dout.write(MAGIC);
366 // Write version number.
367 version.write((OutputStream) dout);
368 dout.write(flags);
369 dout.write(message_type);
370 dout.writeInt(message_size);
372 catch (IOException ex)
374 MARSHAL t = new MARSHAL(ex.getMessage());
375 t.minor = Minor.Header;
376 t.initCause(ex);
377 throw t;
382 * Read data, followed by the message header. Handle fragmented messages.
384 * @param source the data source to read from.
385 * @param service the socket on that the time outs are set. Can be null (no
386 * timeouts are set).
387 * @param to_read the timeout while reading the message.
388 * @param to_pause the timeout for pauses between the message parts.
390 public byte[] readMessage(InputStream source, Socket service, int to_read,
391 int to_pause)
395 byte[] r = new byte[message_size];
397 int n = 0;
398 if (service != null)
399 service.setSoTimeout(to_read);
401 while (n < r.length)
403 n += source.read(r, n, r.length - n);
405 if (service != null)
406 service.setSoTimeout(to_pause);
408 // Read the message remainder if the message is fragmented.
409 if (moreFragmentsFollow())
411 ByteArrayOutputStream buffer = new ByteArrayOutputStream(
412 2 * r.length);
413 buffer.write(r);
415 if (r.length < 10)
416 // Increase the buffer size if the default value (size of the
417 // previous message) is really too small.
418 r = new byte[1024];
420 MessageHeader h2 = new MessageHeader();
424 h2.read(source);
426 int dn;
428 n = 0;
429 while (n < h2.message_size)
431 dn = source.read(r, 0, h2.message_size - n);
433 if (n == 0 && service != null)
434 service.setSoTimeout(to_read);
436 if (n == 0 && version.since_inclusive(1, 2))
438 // Skip the four byte request id.
439 buffer.write(r, 4, dn - 4);
441 else
442 buffer.write(r, 0, dn);
443 n = +dn;
446 if (service != null)
447 service.setSoTimeout(to_pause);
449 while (h2.moreFragmentsFollow());
450 return buffer.toByteArray();
452 else
453 return r;
455 catch (IOException ioex)
457 MARSHAL m = new MARSHAL("Unable to read the message continuation.");
458 m.minor = Minor.Header;
459 m.initCause(ioex);
460 throw m;