001: /*
002: * Copyright (c) 1998-2000 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.util.Alarm;
032: import com.caucho.util.IdentityIntMap;
033: import com.caucho.iiop.any.*;
034: import com.caucho.iiop.orb.IiopProxyHandler;
035:
036: import org.omg.CORBA.Any;
037: import org.omg.CORBA.ORB;
038: import org.omg.CORBA.SystemException;
039: import org.omg.CORBA.TCKind;
040: import org.omg.CORBA.TypeCode;
041: import org.omg.CORBA.portable.IDLEntity;
042: import org.omg.SendingContext.RunTime;
043:
044: import javax.rmi.CORBA.ClassDesc;
045: import javax.rmi.CORBA.Util;
046: import javax.rmi.CORBA.ValueHandler;
047: import java.io.IOException;
048: import java.io.Serializable;
049: import java.lang.reflect.*;
050: import java.util.*;
051:
052: abstract public class IiopWriter extends
053: org.omg.CORBA_2_3.portable.OutputStream {
054: static protected final int VALUE_TAG = 0x7fffff00;
055: static protected final int VALUE_HAS_CODESET = 0x1;
056: static protected final int VALUE_NO_TYPE = 0x0;
057: static protected final int VALUE_ONE_REP_ID = 0x2;
058: static protected final int VALUE_MANY_REP_IDS = 0x6;
059:
060: protected MessageWriter _out;
061: protected int _type;
062:
063: protected SystemException _nullSystemException;
064:
065: protected IiopReader _reader;
066:
067: protected String _host;
068: protected int _port;
069:
070: private org.omg.CORBA.ORB _orb;
071:
072: private IiopWriter _parent;
073: private WriterContext _context;
074:
075: public IiopWriter() {
076: }
077:
078: public IiopWriter(IiopWriter parent, MessageWriter out) {
079: _parent = parent;
080: _out = out;
081: _context = parent.getContext();
082: }
083:
084: /**
085: * Initialize the writer with a new underlying stream.
086: *
087: * @param ws the underlying write stream.
088: */
089: public void init(MessageWriter out) {
090: _out = out;
091:
092: _context = new WriterContext();
093: }
094:
095: public void init() {
096: _context = new WriterContext();
097: }
098:
099: /**
100: * Initialize the writer with a new underlying stream and a reader.
101: *
102: * @param ws the underlying write stream.
103: * @param reader the reader
104: */
105: public void init(MessageWriter out, IiopReader reader) {
106: init(out);
107:
108: _reader = reader;
109: }
110:
111: protected WriterContext getContext() {
112: return _context;
113: }
114:
115: /**
116: * Set the default host.
117: */
118: public void setHost(String host) {
119: _host = host;
120: }
121:
122: /**
123: * Get the default host.
124: */
125: public String getHost() {
126: return _host;
127: }
128:
129: /**
130: * Set the default port.
131: */
132: public void setPort(int port) {
133: _port = port;
134: }
135:
136: /**
137: * Get the default port.
138: */
139: public int getPort() {
140: return _port;
141: }
142:
143: /**
144: * Writes the header for a request
145: *
146: * @param operation the method to call
147: */
148: public void startRequest(IOR ior, String operation)
149: throws IOException {
150: byte[] bytes = ior.getOid();
151:
152: startRequest(bytes, 0, bytes.length, operation);
153: }
154:
155: /**
156: * Writes the header for a request
157: *
158: * @param operation the method to call
159: */
160: public void startRequest(byte[] oid, int off, int len,
161: String operation) throws IOException {
162: startRequest(oid, off, len, operation, (int) Alarm
163: .getCurrentTime(), null);
164: }
165:
166: /**
167: * Writes the header for a request
168: *
169: * @param operation the method to call
170: */
171: abstract public void startRequest(byte[] oid, int off, int len,
172: String operation, int requestId,
173: ArrayList<ServiceContext> serviceList) throws IOException;
174:
175: public void writeRequestServiceControlList() throws IOException {
176: write_long(1);
177: writeCodeSetService();
178: }
179:
180: public void writeCodeSetService() throws IOException {
181: write_long(IiopReader.SERVICE_CODE_SET);
182: write_long(12); // length
183: write_long(0);
184: write_long(0x10001); // iso-8859-1
185: write_long(0x10100); // utf-16
186: }
187:
188: /**
189: * Writes the header for a request
190: */
191: abstract public void startReplyOk(int requestId) throws IOException;
192:
193: /**
194: * Writes the header for a system reply exception
195: */
196: abstract public void startReplySystemException(int requestId,
197: String exceptionId, int minorStatus, int completionStatus,
198: Throwable cause) throws IOException;
199:
200: /**
201: * Writes the header for a user exception
202: */
203: public void startReplyUserException(int requestId,
204: String exceptionId) throws IOException {
205: startReplyUserException(requestId);
206:
207: writeString(exceptionId);
208: }
209:
210: /**
211: * Writes the header for a user exception with no exception id
212: */
213: abstract public void startReplyUserException(int requestId)
214: throws IOException;
215:
216: public void alignMethodArgs() {
217: }
218:
219: /**
220: * Writes an IOR to the output.
221: */
222: public void writeIOR(IOR ior) {
223: byte[] bytes = ior.getByteArray();
224:
225: _out.align(4);
226: _out.write(bytes, 0, bytes.length);
227: }
228:
229: /**
230: * Writes a null IOR to the packet.
231: */
232: public void writeNullIOR() {
233: write_long(1);
234: write_long(0);
235: write_long(0);
236: }
237:
238: /**
239: * Writes a null to the packet.
240: */
241: public void writeNull() {
242: write_long(0);
243: }
244:
245: /* CORBA */
246: public org.omg.CORBA.ORB orb() {
247: return _orb;
248: }
249:
250: public void setOrb(org.omg.CORBA.ORB orb) {
251: _orb = orb;
252: }
253:
254: public org.omg.CORBA.portable.InputStream create_input_stream() {
255: throw new UnsupportedOperationException("no input stream");
256: }
257:
258: /**
259: * Writes a sequence of booleans to the output stream.
260: */
261: public void write_boolean_array(boolean[] value, int offset,
262: int length) {
263: for (int i = 0; i < length; i++)
264: _out.write(value[i + offset] ? 1 : 0);
265: }
266:
267: /**
268: * Writes a sequence of 8-bit characters to the output stream.
269: */
270: public void write_char_array(char[] value, int offset, int length) {
271: for (int i = 0; i < length; i++)
272: _out.write((int) value[i + offset]);
273: }
274:
275: /**
276: * Writes a sequence of 16-bit characters to the output stream.
277: */
278: public void write_wchar_array(char[] value, int offset, int length) {
279: for (int i = 0; i < length; i++)
280: write_wchar(value[i + offset]);
281: }
282:
283: /**
284: * Writes a sequence of bytes to the output stream.
285: */
286: public void write_octet_array(byte[] value, int offset, int length) {
287: for (int i = 0; i < length; i++)
288: _out.write((int) value[i + offset]);
289: }
290:
291: /**
292: * Writes a sequence of shorts to the output stream.
293: */
294: public void write_short_array(short[] value, int offset, int length) {
295: for (int i = 0; i < length; i++)
296: _out.writeShort((int) value[i + offset]);
297: }
298:
299: /**
300: * Writes a sequence of unsigned shorts to the output stream.
301: */
302: public void write_ushort_array(short[] value, int offset, int length) {
303: _out.align(2);
304: for (int i = 0; i < length; i++)
305: _out.writeShort((int) value[i + offset]);
306: }
307:
308: /**
309: * Writes a sequence of CORBA long (Java int) to the output stream.
310: */
311: public void write_long_array(int[] value, int offset, int length) {
312: _out.align(4);
313: for (int i = 0; i < length; i++)
314: _out.writeInt(value[i + offset]);
315: }
316:
317: /**
318: * Writes a sequence of CORBA unsigned long (Java int) to the output stream.
319: */
320: public void write_ulong_array(int[] value, int offset, int length) {
321: _out.align(4);
322: for (int i = 0; i < length; i++)
323: _out.writeInt(value[i + offset]);
324: }
325:
326: /**
327: * Writes a sequence of CORBA long long (Java long) to the output stream.
328: */
329: public void write_longlong_array(long[] value, int offset,
330: int length) {
331: _out.align(8);
332: for (int i = 0; i < length; i++)
333: _out.writeLong(value[i + offset]);
334: }
335:
336: /**
337: * Writes a sequence of CORBA long long (Java long) to the output stream.
338: */
339: public void write_ulonglong_array(long[] value, int offset,
340: int length) {
341: _out.align(8);
342: for (int i = 0; i < length; i++)
343: _out.writeLong(value[i + offset]);
344: }
345:
346: /**
347: * Writes a sequence of floats to the output stream.
348: */
349: public void write_float_array(float[] value, int offset, int length) {
350: _out.align(4);
351: for (int i = 0; i < length; i++) {
352: float v = value[i + offset];
353: int bits = Float.floatToIntBits(v);
354:
355: _out.writeInt(bits);
356: }
357: }
358:
359: /**
360: * Writes a sequence of doubles to the output stream.
361: */
362: public void write_double_array(double[] value, int offset,
363: int length) {
364: _out.align(8);
365: for (int i = 0; i < length; i++) {
366: double v = value[i + offset];
367: long bits = Double.doubleToLongBits(v);
368:
369: _out.writeLong(bits);
370: }
371: }
372:
373: /**
374: * Writes a sequence of 8-bit characters to the output stream.
375: */
376: public void write_string(String a) {
377: if (a == null) {
378: write_long(0);
379: return;
380: }
381:
382: _out.align(4);
383:
384: int oldOffset = _context.getString(a);
385:
386: if (oldOffset >= 0) {
387: write_long(-1);
388: int offset = getOffset();
389: write_long(oldOffset - offset);
390: } else {
391: int length = a.length();
392:
393: write_long(length + 1);
394: int offset = getOffset();
395: _context.putString(a, offset);
396:
397: for (int i = 0; i < length; i++)
398: _out.write((int) a.charAt(i));
399: _out.write(0);
400: }
401: }
402:
403: /**
404: * Writes a sequence of 8-bit characters to the output stream.
405: */
406: public void write_wstring(String a) {
407: if (a == null) {
408: write_long(0);
409: return;
410: }
411:
412: int length = a.length();
413: write_long(length + 1);
414: for (int i = 0; i < length; i++)
415: _out.writeShort((int) a.charAt(i));
416: _out.writeShort(0);
417: }
418:
419: /**
420: * Writes a CORBA object to the output stream.
421: */
422: public void write_Object(org.omg.CORBA.Object obj) {
423: if (obj == null) {
424: write_long(1);
425: write(0);
426: write_long(0);
427: } else {
428: writeIOR(((DummyObjectImpl) obj).getIOR());
429: }
430: }
431:
432: /**
433: * Writes a CORBA typecode to the output stream.
434: */
435: public void write_TypeCode(TypeCode tc) {
436: if (tc == null) {
437: write_long(TCKind._tk_null);
438: return;
439: }
440:
441: try {
442: switch (tc.kind().value()) {
443: case TCKind._tk_null:
444: case TCKind._tk_void:
445: case TCKind._tk_short:
446: case TCKind._tk_ushort:
447: case TCKind._tk_long:
448: case TCKind._tk_ulong:
449: case TCKind._tk_longlong:
450: case TCKind._tk_ulonglong:
451: case TCKind._tk_float:
452: case TCKind._tk_double:
453: case TCKind._tk_longdouble:
454: case TCKind._tk_boolean:
455: case TCKind._tk_char:
456: case TCKind._tk_wchar:
457: case TCKind._tk_octet:
458: case TCKind._tk_any:
459: case TCKind._tk_TypeCode:
460: write_long(tc.kind().value());
461: break;
462:
463: case TCKind._tk_string:
464: write_long(tc.kind().value());
465: write_long(tc.length());
466: break;
467:
468: case TCKind._tk_sequence:
469: SequenceTypeCode.writeTypeCode(this , tc);
470: break;
471:
472: case TCKind._tk_value:
473: ValueTypeCode.writeTypeCode(this , tc);
474: break;
475:
476: case TCKind._tk_value_box:
477: ValueBoxTypeCode.writeTypeCode(this , tc);
478: break;
479:
480: case TCKind._tk_abstract_interface:
481: AbstractInterfaceTypeCode.writeTypeCode(this , tc);
482: break;
483:
484: default:
485: System.out.println("UNKNOWN TC: " + tc + " "
486: + tc.kind() + " " + tc.kind().value());
487: throw new UnsupportedOperationException(String
488: .valueOf(tc));
489: }
490: } catch (Exception e) {
491: throw new RuntimeException(e);
492: }
493: }
494:
495: /**
496: * Writes a CORBA abstract interface to the output stream.
497: */
498: public void write_abstract_interface(java.lang.Object obj) {
499: // XXX: check for remote object
500: write_boolean(false);
501:
502: if (obj instanceof Serializable || obj == null)
503: write_value((Serializable) obj);
504: else
505: write_value(((IiopProxyHandler) obj).getStub());
506: }
507:
508: public void write_any(Any any) {
509: write_TypeCode(any.type());
510: any.write_value(this );
511: }
512:
513: public void write_Principal(org.omg.CORBA.Principal principal) {
514: throw new UnsupportedOperationException();
515: }
516:
517: public void write_value(Serializable obj, Class javaType) {
518: write_value(obj);
519: }
520:
521: public void write_value(Serializable obj) {
522: ValueHandler valueHandler = _context.getValueHandler();
523:
524: if (obj == null) {
525: write_long(0);
526: return;
527: } else if (obj instanceof String) {
528: write_long(VALUE_TAG | VALUE_ONE_REP_ID);
529: write_string("IDL:omg.org/CORBA/WStringValue:1.0");
530: write_wstring((String) obj);
531: } else if (obj instanceof Class) {
532: write_long(VALUE_TAG | VALUE_ONE_REP_ID);
533: write_string(valueHandler
534: .getRMIRepositoryID(ClassDesc.class));
535: write_value(valueHandler.getRMIRepositoryID((Class) obj));
536: write_value(valueHandler.getRMIRepositoryID((Class) obj));
537: } else if (obj instanceof IDLEntity) {
538: try {
539: Class helperClass = Class.forName(obj.getClass()
540: .getName()
541: + "Helper", false, obj.getClass()
542: .getClassLoader());
543:
544: Method writeHelper = helperClass
545: .getMethod(
546: "write",
547: new Class[] {
548: org.omg.CORBA.portable.OutputStream.class,
549: obj.getClass() });
550:
551: writeHelper.invoke(null, this , obj);
552: } catch (Exception e) {
553: throw new RuntimeException(e);
554: }
555: } else {
556: int oldValue = _context.getRef(obj);
557:
558: if (oldValue < 0) {
559: _out.align(4);
560:
561: _context.putRef(obj, getOffset());
562:
563: write_long(VALUE_TAG | VALUE_ONE_REP_ID);
564: String repId = valueHandler.getRMIRepositoryID(obj
565: .getClass());
566: write_string(repId);
567: valueHandler.writeValue(this , obj);
568: } else {
569: _out.align(4);
570:
571: write_long(0xffffffff);
572: int delta = oldValue - getOffset();
573:
574: write_long(delta);
575: }
576: }
577: }
578:
579: /**
580: * Writes a 32-bit integer.
581: */
582: public void write(int b) {
583: write_long(b);
584: }
585:
586: /**
587: * Writes a boolean
588: */
589: public void write_boolean(boolean v) {
590: _out.write(v ? 1 : 0);
591: }
592:
593: /**
594: * Writes a 8-bit byte.
595: */
596: public void write_octet(byte v) {
597: _out.write(v);
598: }
599:
600: /**
601: * Writes a 16-bit short.
602: */
603: public void write_short(short v) {
604: _out.align(2);
605: _out.writeShort(v);
606: }
607:
608: /**
609: * Writes a 16-bit short.
610: */
611: public void write_ushort(short v) {
612: _out.align(2);
613: _out.writeShort(v);
614: }
615:
616: /**
617: * Writes a 8-bit char.
618: */
619: public void write_char(char v) {
620: _out.write(v);
621: }
622:
623: /**
624: * Writes a 16-bit char.
625: */
626: public void write_wchar(char v) {
627: _out.align(2);
628: _out.writeShort(v);
629: }
630:
631: /**
632: * Writes a 32-bit int
633: */
634: public void write_long(int v) {
635: _out.align(4);
636: _out.writeInt(v);
637: }
638:
639: /**
640: * Writes a 32-bit int
641: */
642: public void write_ulong(int v) {
643: _out.align(4);
644: _out.writeInt(v);
645: }
646:
647: /**
648: * Writes a 64-bit int
649: */
650: public void write_longlong(long v) {
651: _out.align(8);
652: _out.writeLong(v);
653: }
654:
655: /**
656: * Writes a 64-bit long
657: */
658: public void write_ulonglong(long v) {
659: _out.align(8);
660: _out.writeLong(v);
661: }
662:
663: /**
664: * Writes a 32-bit float.
665: */
666: public void write_float(float v) {
667: int bits = Float.floatToIntBits(v);
668:
669: _out.align(4);
670: _out.writeInt(bits);
671: }
672:
673: /**
674: * Writes a 64-bit double.
675: */
676: public void write_double(double v) {
677: long bits = Double.doubleToLongBits(v);
678:
679: _out.align(8);
680: _out.writeLong(bits);
681: }
682:
683: /**
684: * Writes a string to the packet.
685: *
686: * @param v string value
687: */
688: public void writeString(String v) {
689: if (v == null) {
690: write_long(0);
691: return;
692: }
693:
694: int len = v.length();
695: write_long(len + 1);
696: for (int i = 0; i < len; i++)
697: _out.write(v.charAt(i));
698: _out.write(0);
699: }
700:
701: /**
702: * Writes a byte array
703: *
704: * @param b byte buffer
705: */
706: public void writeBytes(byte[] b, int off, int len) {
707: write_long(len);
708: _out.write(b, off, len);
709: }
710:
711: /**
712: * Writes a byte array
713: *
714: * @param b byte buffer
715: */
716: public void write(byte[] b, int off, int len) {
717: _out.write(b, off, len);
718: }
719:
720: public IiopReader _call() throws IOException {
721: _out.close();
722:
723: _reader.readRequest();
724:
725: return _reader;
726: }
727:
728: public final int getOffset() {
729: if (_parent != null)
730: return _parent.getOffset() + 4 + _out.getOffset();
731: else
732: return _out.getOffset();
733: }
734: }
|