1 |
/* MessageHeader.java -- GIOP 1.0 message header. |
/* MessageHeader.java -- GIOP message header. |
2 |
Copyright (C) 2005 Free Software Foundation, Inc. |
Copyright (C) 2005 Free Software Foundation, Inc. |
3 |
|
|
4 |
This file is part of GNU Classpath. |
This file is part of GNU Classpath. |
38 |
|
|
39 |
package gnu.CORBA.GIOP; |
package gnu.CORBA.GIOP; |
40 |
|
|
41 |
|
import gnu.CORBA.Minor; |
42 |
|
import gnu.CORBA.Version; |
43 |
|
import gnu.CORBA.CDR.BigEndianInputStream; |
44 |
import gnu.CORBA.CDR.BigEndianOutputStream; |
import gnu.CORBA.CDR.BigEndianOutputStream; |
45 |
import gnu.CORBA.CDR.LittleEndianInputStream; |
import gnu.CORBA.CDR.LittleEndianInputStream; |
46 |
import gnu.CORBA.CDR.LittleEndianOutputStream; |
import gnu.CORBA.CDR.LittleEndianOutputStream; |
47 |
import gnu.CORBA.CDR.abstractDataOutputStream; |
import gnu.CORBA.CDR.AbstractDataInput; |
48 |
import gnu.CORBA.Version; |
import gnu.CORBA.CDR.AbstractDataOutput; |
49 |
|
|
50 |
import org.omg.CORBA.MARSHAL; |
import org.omg.CORBA.MARSHAL; |
51 |
import org.omg.CORBA.portable.IDLEntity; |
import org.omg.CORBA.portable.IDLEntity; |
52 |
|
|
53 |
import java.io.DataInputStream; |
import java.io.ByteArrayOutputStream; |
54 |
import java.io.IOException; |
import java.io.IOException; |
55 |
|
import java.io.InputStream; |
56 |
import java.io.OutputStream; |
import java.io.OutputStream; |
57 |
|
import java.net.Socket; |
58 |
import java.util.Arrays; |
import java.util.Arrays; |
|
import gnu.CORBA.CDR.BigEndianInputStream; |
|
|
import gnu.CORBA.CDR.abstractDataInputStream; |
|
|
import java.io.InputStream; |
|
59 |
|
|
60 |
/** |
/** |
61 |
* The GIOP message header. |
* The GIOP message header. |
62 |
* |
* |
63 |
* @author Audrius Meskauskas (AudriusA@Bioinformatics.org) |
* @author Audrius Meskauskas (AudriusA@Bioinformatics.org) |
64 |
*/ |
*/ |
65 |
public class MessageHeader |
public class MessageHeader |
66 |
implements IDLEntity |
implements IDLEntity |
67 |
{ |
{ |
68 |
/** |
/** |
69 |
|
* Use serialVersionUID for interoperability. |
70 |
|
*/ |
71 |
|
private static final long serialVersionUID = 1; |
72 |
|
|
73 |
|
/** |
74 |
* Request message. |
* Request message. |
75 |
*/ |
*/ |
76 |
public static final byte REQUEST = 0; |
public static final byte REQUEST = 0; |
86 |
public static final byte CANCEL_REQUEST = 2; |
public static final byte CANCEL_REQUEST = 2; |
87 |
|
|
88 |
/** |
/** |
89 |
* Locate request message, used to check the server ability to |
* Locate request message, used to check the server ability to process |
90 |
* process requests for the object reference. |
* requests for the object reference. This message is also used to get the |
|
* This message is also used to get the |
|
91 |
* address where the object reference should be sent. |
* address where the object reference should be sent. |
92 |
*/ |
*/ |
93 |
public static final byte LOCATE_REQUEST = 3; |
public static final byte LOCATE_REQUEST = 3; |
94 |
|
|
95 |
/** |
/** |
96 |
* Locate reply message, sent in response to the |
* Locate reply message, sent in response to the {@link #LocateRequest} |
97 |
* {@link #LocateRequest} message. |
* message. |
98 |
*/ |
*/ |
99 |
public static final byte LOCATE_REPLY = 4; |
public static final byte LOCATE_REPLY = 4; |
100 |
|
|
109 |
public static final byte MESSAGE_ERROR = 6; |
public static final byte MESSAGE_ERROR = 6; |
110 |
|
|
111 |
/** |
/** |
112 |
* The fragment messge, following the previous message that |
* The fragment messge, following the previous message that has more fragments |
113 |
* has more fragments flag set. Added in GIOP 1.1 |
* flag set. Added in GIOP 1.1 |
114 |
*/ |
*/ |
115 |
public static final byte FRAGMENT = 7; |
public static final byte FRAGMENT = 7; |
116 |
|
|
122 |
/** |
/** |
123 |
* The message type names. |
* The message type names. |
124 |
*/ |
*/ |
125 |
protected static String[] types = |
protected static String[] types = new String[] { "Request", "Reply", |
126 |
new String[] |
"Cancel", "Locate request", "Locate reply", "Close connection", "Error", |
127 |
{ |
"Fragment" }; |
|
"Request", "Reply", "Cancel", "Locate request", "Locate reply", |
|
|
"Close connection", "Error", "Fragment" |
|
|
}; |
|
128 |
|
|
129 |
/** |
/** |
130 |
* The GIOP version. Initialised to 1.0 . |
* The GIOP version. Initialised to 1.0 . |
156 |
|
|
157 |
/** |
/** |
158 |
* Create an empty message header, corresponding the given version. |
* Create an empty message header, corresponding the given version. |
159 |
* |
* |
160 |
* @param major the major message header version. |
* @param major the major message header version. |
161 |
* @param minor the minot message header version. |
* @param minor the minot message header version. |
162 |
*/ |
*/ |
166 |
} |
} |
167 |
|
|
168 |
/** |
/** |
169 |
* Checks if the message is encoded in the Big Endian, most significant |
* Checks if the message is encoded in the Big Endian, most significant byte |
170 |
* byte first. |
* first. |
171 |
*/ |
*/ |
172 |
public boolean isBigEndian() |
public boolean isBigEndian() |
173 |
{ |
{ |
175 |
} |
} |
176 |
|
|
177 |
/** |
/** |
178 |
|
* Checks if the message is partial, and more subsequent fragments follow. |
179 |
|
*/ |
180 |
|
public boolean moreFragmentsFollow() |
181 |
|
{ |
182 |
|
return (flags & 0x2) != 0; |
183 |
|
} |
184 |
|
|
185 |
|
/** |
186 |
* Set the encoding to use. |
* Set the encoding to use. |
187 |
* |
* |
188 |
* @param use_big_endian if true (default), the Big Endian |
* @param use_big_endian if true (default), the Big Endian encoding is used. |
189 |
* encoding is used. If false, the Little Endian encoding is used. |
* If false, the Little Endian encoding is used. |
190 |
*/ |
*/ |
191 |
public void setBigEndian(boolean use_big_endian) |
public void setBigEndian(boolean use_big_endian) |
192 |
{ |
{ |
206 |
|
|
207 |
/** |
/** |
208 |
* Get the message type as string. |
* Get the message type as string. |
209 |
* |
* |
210 |
* @param type the message type as int (the field {@link message_type}). |
* @param type the message type as int (the field {@link message_type}). |
211 |
* |
* |
212 |
* @return the message type as string. |
* @return the message type as string. |
213 |
*/ |
*/ |
214 |
public String getTypeString(int type) |
public String getTypeString(int type) |
215 |
{ |
{ |
216 |
try |
try |
217 |
{ |
{ |
218 |
return types [ type ]; |
return types[type]; |
219 |
} |
} |
220 |
catch (ArrayIndexOutOfBoundsException ex) |
catch (ArrayIndexOutOfBoundsException ex) |
221 |
{ |
{ |
225 |
|
|
226 |
/** |
/** |
227 |
* Creates reply header, matching the message header version number. |
* Creates reply header, matching the message header version number. |
228 |
* |
* |
229 |
* @return one of {@link gnu.CORBA.GIOP.v1_0.ReplyHeader}, |
* @return one of {@link gnu.CORBA.GIOP.v1_0.ReplyHeader}, |
230 |
* {@link gnu.CORBA.GIOP.v1_2.ReplyHeader}, etc - depending on |
* {@link gnu.CORBA.GIOP.v1_2.ReplyHeader}, etc - depending on the version |
231 |
* the version number in this header. |
* number in this header. |
232 |
*/ |
*/ |
233 |
public ReplyHeader create_reply_header() |
public ReplyHeader create_reply_header() |
234 |
{ |
{ |
240 |
|
|
241 |
/** |
/** |
242 |
* Creates request header, matching the message header version number. |
* Creates request header, matching the message header version number. |
243 |
* |
* |
244 |
* @return one of {@link gnu.CORBA.GIOP.v1_0.RequestHeader}, |
* @return one of {@link gnu.CORBA.GIOP.v1_0.RequestHeader}, |
245 |
* {@link gnu.CORBA.GIOP.v1_2.RequestHeader}, etc - depending on |
* {@link gnu.CORBA.GIOP.v1_2.RequestHeader}, etc - depending on the version |
246 |
* the version number in this header. |
* number in this header. |
247 |
*/ |
*/ |
248 |
public RequestHeader create_request_header() |
public RequestHeader create_request_header() |
249 |
{ |
{ |
271 |
|
|
272 |
/** |
/** |
273 |
* Read the header from the stream. |
* Read the header from the stream. |
274 |
* |
* |
275 |
* @param istream a stream to read from. |
* @param istream a stream to read from. |
276 |
* |
* |
277 |
* @throws MARSHAL if this is not a GIOP 1.0 header. |
* @throws MARSHAL if this is not a GIOP 1.0 header. |
278 |
*/ |
*/ |
279 |
public void read(java.io.InputStream istream) |
public void read(java.io.InputStream istream) |
280 |
throws MARSHAL |
throws MARSHAL |
281 |
{ |
{ |
282 |
try |
try |
283 |
{ |
{ |
284 |
byte[] xMagic = new byte[ MAGIC.length ]; |
byte[] xMagic = new byte[MAGIC.length]; |
285 |
istream.read(xMagic); |
istream.read(xMagic); |
286 |
if (!Arrays.equals(xMagic, MAGIC)) |
if (!Arrays.equals(xMagic, MAGIC)) |
287 |
throw new MARSHAL("Not a GIOP message"); |
{ |
288 |
|
MARSHAL m = new MARSHAL("Not a GIOP message"); |
289 |
|
m.minor = Minor.Giop; |
290 |
|
throw m; |
291 |
|
} |
292 |
|
|
293 |
version = Version.read_version(istream); |
version = Version.read_version(istream); |
294 |
|
|
295 |
abstractDataInputStream din; |
AbstractDataInput din; |
296 |
|
|
297 |
flags = (byte) istream.read(); |
flags = (byte) istream.read(); |
298 |
|
|
309 |
catch (IOException ex) |
catch (IOException ex) |
310 |
{ |
{ |
311 |
MARSHAL t = new MARSHAL(); |
MARSHAL t = new MARSHAL(); |
312 |
|
t.minor = Minor.Header; |
313 |
t.initCause(ex); |
t.initCause(ex); |
314 |
throw t; |
throw t; |
315 |
} |
} |
317 |
|
|
318 |
/** |
/** |
319 |
* Get the short string summary of the message. |
* Get the short string summary of the message. |
320 |
* |
* |
321 |
* @return a short message summary. |
* @return a short message summary. |
322 |
*/ |
*/ |
323 |
public String toString() |
public String toString() |
324 |
{ |
{ |
325 |
return "GIOP " + version + ", " + (isBigEndian() ? "Big" : "Little") + |
return "GIOP " + version + ", " + (isBigEndian() ? "Big" : "Little") |
326 |
" endian, " + getTypeString(message_type) + ", " + message_size + |
+ " endian, " + getTypeString(message_type) + ", " + message_size |
327 |
" bytes. "; |
+ " bytes. "; |
328 |
} |
} |
329 |
|
|
330 |
/** |
/** |
331 |
* Write the header to stream. |
* Write the header to stream. |
332 |
* |
* |
333 |
* @param out a stream to write into. |
* @param out a stream to write into. |
334 |
*/ |
*/ |
335 |
public void write(java.io.OutputStream out) |
public void write(java.io.OutputStream out) |
336 |
{ |
{ |
337 |
try |
try |
338 |
{ |
{ |
339 |
abstractDataOutputStream dout; |
AbstractDataOutput dout; |
340 |
|
|
341 |
if (isBigEndian()) |
if (isBigEndian()) |
342 |
dout = new BigEndianOutputStream(out); |
dout = new BigEndianOutputStream(out); |
348 |
|
|
349 |
// Write version number. |
// Write version number. |
350 |
version.write((OutputStream) dout); |
version.write((OutputStream) dout); |
|
|
|
351 |
dout.write(flags); |
dout.write(flags); |
|
|
|
352 |
dout.write(message_type); |
dout.write(message_type); |
|
|
|
353 |
dout.writeInt(message_size); |
dout.writeInt(message_size); |
354 |
} |
} |
355 |
catch (IOException ex) |
catch (IOException ex) |
356 |
{ |
{ |
357 |
MARSHAL t = new MARSHAL(); |
MARSHAL t = new MARSHAL(); |
358 |
|
t.minor = Minor.Header; |
359 |
t.initCause(ex); |
t.initCause(ex); |
360 |
throw t; |
throw t; |
361 |
} |
} |
362 |
} |
} |
363 |
|
|
364 |
|
/** |
365 |
|
* Read data, followed by the message header. Handle fragmented messages. |
366 |
|
* |
367 |
|
* @param source the data source to read from. |
368 |
|
* @param service the socket on that the time outs are set. Can be null (no |
369 |
|
* timeouts are set). |
370 |
|
* @param to_read the timeout while reading the message. |
371 |
|
* @param to_pause the timeout for pauses between the message parts. |
372 |
|
*/ |
373 |
|
public byte[] readMessage(InputStream source, Socket service, int to_read, |
374 |
|
int to_pause) |
375 |
|
{ |
376 |
|
try |
377 |
|
{ |
378 |
|
byte[] r = new byte[message_size]; |
379 |
|
|
380 |
|
int n = 0; |
381 |
|
if (service != null) |
382 |
|
service.setSoTimeout(to_read); |
383 |
|
|
384 |
|
reading: while (n < r.length) |
385 |
|
{ |
386 |
|
n += source.read(r, n, r.length - n); |
387 |
|
} |
388 |
|
if (service != null) |
389 |
|
service.setSoTimeout(to_pause); |
390 |
|
|
391 |
|
// Read the message remainder if the message is fragmented. |
392 |
|
if (moreFragmentsFollow()) |
393 |
|
{ |
394 |
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream( |
395 |
|
2 * r.length); |
396 |
|
buffer.write(r); |
397 |
|
|
398 |
|
if (r.length < 10) |
399 |
|
// Increase the buffer size if the default value (size of the |
400 |
|
// previous message) is really too small. |
401 |
|
r = new byte[1024]; |
402 |
|
|
403 |
|
MessageHeader h2 = new MessageHeader(); |
404 |
|
|
405 |
|
do |
406 |
|
{ |
407 |
|
h2.read(source); |
408 |
|
|
409 |
|
int dn; |
410 |
|
|
411 |
|
n = 0; |
412 |
|
reading: while (n < h2.message_size) |
413 |
|
{ |
414 |
|
dn = source.read(r, 0, h2.message_size - n); |
415 |
|
|
416 |
|
if (n == 0 && service != null) |
417 |
|
service.setSoTimeout(to_read); |
418 |
|
|
419 |
|
if (n == 0 && version.since_inclusive(1, 2)) |
420 |
|
{ |
421 |
|
// Skip the four byte request id. |
422 |
|
buffer.write(r, 4, dn - 4); |
423 |
|
} |
424 |
|
else |
425 |
|
buffer.write(r, 0, dn); |
426 |
|
n = +dn; |
427 |
|
} |
428 |
|
|
429 |
|
if (service != null) |
430 |
|
service.setSoTimeout(to_pause); |
431 |
|
} |
432 |
|
while (h2.moreFragmentsFollow()); |
433 |
|
return buffer.toByteArray(); |
434 |
|
} |
435 |
|
else |
436 |
|
return r; |
437 |
|
} |
438 |
|
catch (IOException ioex) |
439 |
|
{ |
440 |
|
MARSHAL m = new MARSHAL("Unable to read the message continuation."); |
441 |
|
m.minor = Minor.Header; |
442 |
|
m.initCause(ioex); |
443 |
|
throw m; |
444 |
|
} |
445 |
|
} |
446 |
} |
} |