001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.iiop;
030:
031: import com.caucho.vfs.WriteStream;
032:
033: import java.io.IOException;
034:
035: public class StreamMessageWriter extends MessageWriter {
036: private WriteStream _out;
037:
038: private byte[] _buffer;
039: private int _bufferLength;
040:
041: private int _offset;
042: private int _length;
043:
044: private int _version;
045: private int _reqId;
046:
047: public StreamMessageWriter() {
048: }
049:
050: public StreamMessageWriter(WriteStream out) {
051: init(out);
052: }
053:
054: /**
055: * initialize the writer.
056: */
057: public void init(WriteStream out) {
058: _out = out;
059: _buffer = _out.getBuffer();
060: _bufferLength = _buffer.length;
061:
062: _buffer[0] = 'G';
063: _buffer[1] = 'I';
064: _buffer[2] = 'O';
065: _buffer[3] = 'P';
066: }
067:
068: /**
069: * initialize the writer.
070: */
071: public void initRaw(WriteStream out) {
072: _out = out;
073: _buffer = _out.getBuffer();
074: _bufferLength = _buffer.length;
075: }
076:
077: /**
078: * Starts a 1.0 message.
079: */
080: @Override
081: public void start10Message(int type) {
082: _version = 0;
083:
084: _offset = 12;
085: _length = 12;
086:
087: _buffer[4] = 1;
088: _buffer[5] = 0;
089: _buffer[6] = 0;
090: _buffer[7] = (byte) type;
091: }
092:
093: /**
094: * Starts a 1.1 message.
095: */
096: @Override
097: public void start11Message(int type) {
098: _version = 1;
099:
100: _offset = 12;
101: _length = 12;
102:
103: _buffer[4] = 1;
104: _buffer[5] = 1;
105: _buffer[6] = 0;
106: _buffer[7] = (byte) type;
107: }
108:
109: /**
110: * Starts a 1.2 message.
111: */
112: @Override
113: public void start12Message(int type) {
114: _version = 2;
115:
116: _offset = 12;
117: _length = 12;
118:
119: _buffer[4] = 1;
120: _buffer[5] = 2;
121: _buffer[6] = 0;
122: _buffer[7] = (byte) type;
123: }
124:
125: /**
126: * Returns the offset.
127: */
128: public int getOffset() {
129: // flush if nearly full to deal with the IIOP 1.2 message header
130: if (_bufferLength <= _length + 4)
131: flushBuffer();
132:
133: return _offset;
134: }
135:
136: /**
137: * Writes a byte.
138: */
139: public void write(int v) {
140: if (_bufferLength <= _length)
141: flushBuffer();
142:
143: _offset++;
144: _buffer[_length++] = (byte) v;
145: }
146:
147: /**
148: * Writes data
149: */
150: public void write(byte[] buffer, int offset, int length) {
151: while (length > 0) {
152: int sublen = _bufferLength - _length;
153:
154: if (length < sublen)
155: sublen = length;
156:
157: System.arraycopy(buffer, offset, _buffer, _length, sublen);
158:
159: _offset += sublen;
160: _length += sublen;
161: length -= sublen;
162:
163: if (length > 0)
164: flushBuffer();
165: }
166: }
167:
168: /**
169: * Writes a short
170: */
171: public final void writeShort(int v) {
172: if (_bufferLength <= _length + 1)
173: flushBuffer();
174:
175: _offset += 2;
176:
177: _buffer[_length++] = (byte) (v >> 8);
178: _buffer[_length++] = (byte) (v);
179: }
180:
181: /**
182: * Writes an integer.
183: */
184: public void writeInt(int v) {
185: if (_bufferLength <= _length + 3)
186: flushBuffer();
187:
188: _offset += 4;
189:
190: _buffer[_length++] = (byte) (v >> 24);
191: _buffer[_length++] = (byte) (v >> 16);
192: _buffer[_length++] = (byte) (v >> 8);
193: _buffer[_length++] = (byte) (v);
194: }
195:
196: /**
197: * Aligns to a specified value.
198: */
199: public void align(int v) {
200: int delta = v - _offset % v;
201:
202: if (delta == v)
203: return;
204:
205: _offset += delta;
206:
207: for (; delta > 0; delta--)
208: _buffer[_length++] = 0;
209: }
210:
211: /**
212: * Flushes the buffer.
213: */
214: public void flushBuffer() {
215: try {
216: int size = _length - 12;
217:
218: _buffer[6] = 2; // fragmented
219:
220: _buffer[8] = (byte) (size >> 24);
221: _buffer[9] = (byte) (size >> 16);
222: _buffer[10] = (byte) (size >> 8);
223: _buffer[11] = (byte) (size >> 0);
224:
225: /*
226: // For IIOP 1.2, the fragment is padded to align(8).
227: if (_version == 2) {
228: _length += (8 - _offset) & 0x7;
229: }
230: */
231:
232: _out.setBufferOffset(_length);
233: _out.flushBuffer();
234:
235: _buffer[7] = IiopReader.MSG_FRAGMENT;
236:
237: // For IIOP 1.2, the fragment header has a request id
238: if (_version >= 2) {
239: _buffer[12] = (byte) (_reqId >> 24);
240: _buffer[13] = (byte) (_reqId >> 16);
241: _buffer[14] = (byte) (_reqId >> 8);
242: _buffer[15] = (byte) (_reqId);
243: _length = 16;
244: } else
245: _length = 12;
246: } catch (IOException e) {
247: throw new RuntimeException(e);
248: }
249: }
250:
251: /**
252: * Completes the response.
253: */
254: public void close() throws IOException {
255: int size = _length - 12;
256:
257: _buffer[6] = 0; // last message
258:
259: _buffer[8] = (byte) (size >> 24);
260: _buffer[9] = (byte) (size >> 16);
261: _buffer[10] = (byte) (size >> 8);
262: _buffer[11] = (byte) (size >> 0);
263:
264: /*
265: if (_version == 2) {
266: int delta = (8 - _offset) & 0x7;
267:
268: for (int i = 0; i < delta; i++)
269: _buffer[_length + i] = (byte) 0xaa;
270:
271: _length += delta;
272: }
273: */
274:
275: // debugData();
276: _out.setBufferOffset(_length);
277: _out.flushBuffer();
278:
279: _length = 0;
280: }
281:
282: public void debugData() {
283: for (int tail = 0; tail < _length; tail += 16) {
284: for (int j = 0; j < 16; j++) {
285: System.out.print(" ");
286:
287: if (tail + j < _length)
288: printHex(_buffer[tail + j]);
289: else
290: System.out.print(" ");
291: }
292:
293: System.out.print(" ");
294: for (int j = 0; j < 16; j++) {
295: if (tail + j < _length)
296: printCh(_buffer[tail + j]);
297: else
298: System.out.print(" ");
299: }
300:
301: System.out.println();
302: }
303:
304: System.out.println();
305: }
306:
307: private void printHex(int d) {
308: int ch1 = (d >> 4) & 0xf;
309: int ch2 = d & 0xf;
310:
311: if (ch1 >= 10)
312: System.out.print((char) ('a' + ch1 - 10));
313: else
314: System.out.print((char) ('0' + ch1));
315:
316: if (ch2 >= 10)
317: System.out.print((char) ('a' + ch2 - 10));
318: else
319: System.out.print((char) ('0' + ch2));
320: }
321:
322: private void printCh(int d) {
323: if (d >= 0x20 && d <= 0x7f)
324: System.out.print("" + ((char) d));
325: else
326: System.out.print(".");
327: }
328:
329: private String toCh(int d) {
330: if (d >= 0x20 && d <= 0x7f)
331: return "" + (char) d;
332: else
333: return "" + d;
334: }
335:
336: private static String toHex(int v) {
337: String s = "";
338:
339: for (int i = 28; i >= 0; i -= 4) {
340: int h = (v >> i) & 0xf;
341:
342: if (h >= 10)
343: s += ((char) ('a' + h - 10));
344: else
345: s += (h);
346: }
347:
348: return s;
349: }
350: }
|