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 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
;
62 * The GIOP message header.
64 * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
66 public class MessageHeader
70 * Use serialVersionUID for interoperability.
72 private static final long serialVersionUID
= 1;
77 public static final byte REQUEST
= 0;
82 public static final byte REPLY
= 1;
85 * Cancel request message.
87 public static final byte CANCEL_REQUEST
= 2;
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;
97 * Locate reply message, sent in response to the {@link #LocateRequest}
100 public static final byte LOCATE_REPLY
= 4;
103 * Instruction to close the connection.
105 public static final byte CLOSE_CONNECTION
= 5;
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",
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;
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
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
)
195 flags
= (byte) (flags
& ~
1);
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()
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
)
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();
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();
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
);
287 if (! Arrays
.equals(xMagic
, MAGIC
))
289 StringBuffer b
= new StringBuffer();
292 b
.append("Immediate EOF");
298 b
.append(r
+ " bytes: ");
299 for (int i
= 0; i
< xMagic
.length
; i
++)
301 b
.append(Integer
.toHexString(xMagic
[i
] & 0xFF));
305 MARSHAL m
= new MARSHAL("Not a GIOP message: " + b
);
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.
318 din
= new BigEndianInputStream(istream
);
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
;
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
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
;
359 dout
= new BigEndianOutputStream(out
);
361 dout
= new LittleEndianOutputStream(out
);
363 // Write magic sequence.
366 // Write version number.
367 version
.write((OutputStream
) dout
);
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
;
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
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
,
395 byte[] r
= new byte[message_size
];
399 service
.setSoTimeout(to_read
);
403 n
+= source
.read(r
, n
, r
.length
- n
);
406 service
.setSoTimeout(to_pause
);
408 // Read the message remainder if the message is fragmented.
409 if (moreFragmentsFollow())
411 ByteArrayOutputStream buffer
= new ByteArrayOutputStream(
416 // Increase the buffer size if the default value (size of the
417 // previous message) is really too small.
420 MessageHeader h2
= new MessageHeader();
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);
442 buffer
.write(r
, 0, dn
);
447 service
.setSoTimeout(to_pause
);
449 while (h2
.moreFragmentsFollow());
450 return buffer
.toByteArray();
455 catch (IOException ioex
)
457 MARSHAL m
= new MARSHAL("Unable to read the message continuation.");
458 m
.minor
= Minor
.Header
;