Frames | No Frames |
1: /* MessageHeader.java -- GIOP message header. 2: Copyright (C) 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 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. 10: 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. 15: 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. 20: 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. 25: 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. */ 37: 38: 39: 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; 45: import gnu.CORBA.CDR.LittleEndianInputStream; 46: import gnu.CORBA.CDR.LittleEndianOutputStream; 47: import gnu.CORBA.CDR.AbstractDataInput; 48: import gnu.CORBA.CDR.AbstractDataOutput; 49: 50: import org.omg.CORBA.MARSHAL; 51: import org.omg.CORBA.portable.IDLEntity; 52: 53: import java.io.ByteArrayOutputStream; 54: import java.io.IOException; 55: import java.io.InputStream; 56: import java.io.OutputStream; 57: import java.net.Socket; 58: import java.util.Arrays; 59: 60: /** 61: * The GIOP message header. 62: * 63: * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) 64: */ 65: public class MessageHeader 66: implements IDLEntity 67: { 68: /** 69: * Use serialVersionUID for interoperability. 70: */ 71: private static final long serialVersionUID = 1; 72: 73: /** 74: * Request message. 75: */ 76: public static final byte REQUEST = 0; 77: 78: /** 79: * Reply message 80: */ 81: public static final byte REPLY = 1; 82: 83: /** 84: * Cancel request message. 85: */ 86: public static final byte CANCEL_REQUEST = 2; 87: 88: /** 89: * Locate request message, used to check the server ability to process 90: * requests for the object reference. This message is also used to get the 91: * address where the object reference should be sent. 92: */ 93: public static final byte LOCATE_REQUEST = 3; 94: 95: /** 96: * Locate reply message, sent in response to the {@link #LocateRequest} 97: * message. 98: */ 99: public static final byte LOCATE_REPLY = 4; 100: 101: /** 102: * Instruction to close the connection. 103: */ 104: public static final byte CLOSE_CONNECTION = 5; 105: 106: /** 107: * Error report. 108: */ 109: public static final byte MESSAGE_ERROR = 6; 110: 111: /** 112: * The fragment messge, following the previous message that has more fragments 113: * flag set. Added in GIOP 1.1 114: */ 115: public static final byte FRAGMENT = 7; 116: 117: /** 118: * This must always be "GIOP". 119: */ 120: public static final byte[] MAGIC = new byte[] { 'G', 'I', 'O', 'P' }; 121: 122: /** 123: * The message type names. 124: */ 125: protected static String[] types = new String[] { "Request", "Reply", 126: "Cancel", "Locate request", "Locate reply", "Close connection", "Error", 127: "Fragment" }; 128: 129: /** 130: * The GIOP version. Initialised to 1.0 . 131: */ 132: public Version version; 133: 134: /** 135: * The flags field, introduced since GIOP 1.1. 136: */ 137: public byte flags = 0; 138: 139: /** 140: * The message type. 141: */ 142: public byte message_type = REQUEST; 143: 144: /** 145: * The message size, excluding the message header. 146: */ 147: public int message_size = 0; 148: 149: /** 150: * Create an empty message header, corresponding version 1.0. 151: */ 152: public MessageHeader() 153: { 154: version = new Version(1, 0); 155: } 156: 157: /** 158: * Create an empty message header, corresponding the given version. 159: * 160: * @param major the major message header version. 161: * @param minor the minot message header version. 162: */ 163: public MessageHeader(int major, int minor) 164: { 165: version = new Version(major, minor); 166: } 167: 168: /** 169: * Checks if the message is encoded in the Big Endian, most significant byte 170: * first. 171: */ 172: public boolean isBigEndian() 173: { 174: return (flags & 0x1) == 0; 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. 187: * 188: * @param use_big_endian if true (default), the Big Endian encoding is used. 189: * If false, the Little Endian encoding is used. 190: */ 191: public void setBigEndian(boolean use_big_endian) 192: { 193: if (use_big_endian) 194: flags = (byte) (flags & ~1); 195: else 196: flags = (byte) (flags | 1); 197: } 198: 199: /** 200: * Get the size of the message header itself. So far, it is always 12 bytes. 201: */ 202: public int getHeaderSize() 203: { 204: return 12; 205: } 206: 207: /** 208: * Get the message type as string. 209: * 210: * @param type the message type as int (the field {@link message_type}). 211: * 212: * @return the message type as string. 213: */ 214: public String getTypeString(int type) 215: { 216: try 217: { 218: return types[type]; 219: } 220: catch (ArrayIndexOutOfBoundsException ex) 221: { 222: return "unknown type (" + type + ")"; 223: } 224: } 225: 226: /** 227: * Creates reply header, matching the message header version number. 228: * 229: * @return one of {@link gnu.CORBA.GIOP.v1_0.ReplyHeader}, 230: * {@link gnu.CORBA.GIOP.v1_2.ReplyHeader}, etc - depending on the version 231: * number in this header. 232: */ 233: public ReplyHeader create_reply_header() 234: { 235: if (version.since_inclusive(1, 2)) 236: return new gnu.CORBA.GIOP.v1_2.ReplyHeader(); 237: else 238: return new gnu.CORBA.GIOP.v1_0.ReplyHeader(); 239: } 240: 241: /** 242: * Creates request header, matching the message header version number. 243: * 244: * @return one of {@link gnu.CORBA.GIOP.v1_0.RequestHeader}, 245: * {@link gnu.CORBA.GIOP.v1_2.RequestHeader}, etc - depending on the version 246: * number in this header. 247: */ 248: public RequestHeader create_request_header() 249: { 250: if (version.since_inclusive(1, 2)) 251: return new gnu.CORBA.GIOP.v1_2.RequestHeader(); 252: else 253: return new gnu.CORBA.GIOP.v1_0.RequestHeader(); 254: } 255: 256: /** 257: * Create the cancel header, matching the message header version number. 258: */ 259: public CancelHeader create_cancel_header() 260: { 261: return new gnu.CORBA.GIOP.v1_0.CancelHeader(); 262: } 263: 264: /** 265: * Create the error message. 266: */ 267: public ErrorMessage create_error_message() 268: { 269: return new ErrorMessage(version); 270: } 271: 272: /** 273: * Read the header from the stream. 274: * 275: * @param istream a stream to read from. 276: * 277: * @throws MARSHAL if this is not a GIOP 1.0 header. 278: */ 279: public void read(java.io.InputStream istream) 280: throws MARSHAL 281: { 282: try 283: { 284: byte[] xMagic = new byte[MAGIC.length]; 285: istream.read(xMagic); 286: if (!Arrays.equals(xMagic, MAGIC)) 287: { 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); 294: 295: AbstractDataInput din; 296: 297: flags = (byte) istream.read(); 298: 299: // This checks the bit in the byte we have just received. 300: if (isBigEndian()) 301: din = new BigEndianInputStream(istream); 302: else 303: din = new LittleEndianInputStream(istream); 304: 305: message_type = (byte) din.read(); 306: 307: message_size = din.readInt(); 308: } 309: catch (IOException ex) 310: { 311: MARSHAL t = new MARSHAL(); 312: t.minor = Minor.Header; 313: t.initCause(ex); 314: throw t; 315: } 316: } 317: 318: /** 319: * Get the short string summary of the message. 320: * 321: * @return a short message summary. 322: */ 323: public String toString() 324: { 325: return "GIOP " + version + ", " + (isBigEndian() ? "Big" : "Little") 326: + " endian, " + getTypeString(message_type) + ", " + message_size 327: + " bytes. "; 328: } 329: 330: /** 331: * Write the header to stream. 332: * 333: * @param out a stream to write into. 334: */ 335: public void write(java.io.OutputStream out) 336: { 337: try 338: { 339: AbstractDataOutput dout; 340: 341: if (isBigEndian()) 342: dout = new BigEndianOutputStream(out); 343: else 344: dout = new LittleEndianOutputStream(out); 345: 346: // Write magic sequence. 347: dout.write(MAGIC); 348: 349: // Write version number. 350: version.write((OutputStream) dout); 351: dout.write(flags); 352: dout.write(message_type); 353: dout.writeInt(message_size); 354: } 355: catch (IOException ex) 356: { 357: MARSHAL t = new MARSHAL(); 358: t.minor = Minor.Header; 359: t.initCause(ex); 360: 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: }