1. /*
  2. * @(#)CDROutputStream_1_0.java 1.112 04/06/21
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. /*
  8. * Licensed Materials - Property of IBM
  9. * RMI-IIOP v1.0
  10. * Copyright IBM Corp. 1998 1999 All Rights Reserved
  11. *
  12. * US Government Users Restricted Rights - Use, duplication or
  13. * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  14. */
  15. package com.sun.corba.se.impl.encoding;
  16. import java.io.ByteArrayOutputStream;
  17. import java.io.IOException;
  18. import java.io.Serializable;
  19. import java.io.ByteArrayOutputStream;
  20. import java.io.ObjectOutputStream;
  21. import java.io.IOException;
  22. import java.lang.reflect.Method;
  23. import java.lang.reflect.InvocationTargetException;
  24. import java.math.BigDecimal;
  25. import java.nio.ByteBuffer;
  26. import java.rmi.Remote;
  27. import java.security.AccessController;
  28. import java.security.PrivilegedExceptionAction;
  29. import java.security.PrivilegedActionException;
  30. import java.util.Hashtable;
  31. import java.util.Stack;
  32. import javax.rmi.CORBA.Util;
  33. import javax.rmi.CORBA.ValueHandler;
  34. import javax.rmi.CORBA.ValueHandlerMultiFormat;
  35. import org.omg.CORBA.CustomMarshal;
  36. import org.omg.CORBA.DataOutputStream;
  37. import org.omg.CORBA.TypeCodePackage.BadKind;
  38. import org.omg.CORBA.SystemException;
  39. import org.omg.CORBA.CompletionStatus;
  40. import org.omg.CORBA.Object;
  41. import org.omg.CORBA.Principal;
  42. import org.omg.CORBA.TypeCode;
  43. import org.omg.CORBA.Any;
  44. import org.omg.CORBA.VM_CUSTOM;
  45. import org.omg.CORBA.VM_TRUNCATABLE;
  46. import org.omg.CORBA.VM_NONE;
  47. import org.omg.CORBA.portable.IDLEntity;
  48. import org.omg.CORBA.portable.CustomValue;
  49. import org.omg.CORBA.portable.StreamableValue;
  50. import org.omg.CORBA.portable.BoxedValueHelper;
  51. import org.omg.CORBA.portable.OutputStream;
  52. import org.omg.CORBA.portable.ValueBase;
  53. import com.sun.org.omg.CORBA.portable.ValueHelper;
  54. import com.sun.corba.se.pept.protocol.MessageMediator;
  55. import com.sun.corba.se.pept.transport.ByteBufferPool;
  56. import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
  57. import com.sun.corba.se.spi.ior.IOR;
  58. import com.sun.corba.se.spi.ior.IORFactories;
  59. import com.sun.corba.se.spi.orb.ORB;
  60. import com.sun.corba.se.spi.orb.ORBVersionFactory;
  61. import com.sun.corba.se.spi.orb.ORBVersion;
  62. import com.sun.corba.se.spi.protocol.CorbaMessageMediator;
  63. import com.sun.corba.se.spi.logging.CORBALogDomains;
  64. import com.sun.corba.se.impl.encoding.ByteBufferWithInfo;
  65. import com.sun.corba.se.impl.encoding.MarshalOutputStream;
  66. import com.sun.corba.se.impl.encoding.CodeSetConversion;
  67. import com.sun.corba.se.impl.corba.TypeCodeImpl;
  68. import com.sun.corba.se.impl.orbutil.CacheTable;
  69. import com.sun.corba.se.impl.orbutil.ORBUtility;
  70. import com.sun.corba.se.impl.orbutil.RepositoryIdStrings;
  71. import com.sun.corba.se.impl.orbutil.RepositoryIdUtility;
  72. import com.sun.corba.se.impl.orbutil.RepositoryIdFactory;
  73. import com.sun.corba.se.impl.util.Utility;
  74. import com.sun.corba.se.impl.logging.ORBUtilSystemException;
  75. public class CDROutputStream_1_0 extends CDROutputStreamBase
  76. {
  77. private static final int INDIRECTION_TAG = 0xffffffff;
  78. protected boolean littleEndian;
  79. protected BufferManagerWrite bufferManagerWrite;
  80. ByteBufferWithInfo bbwi;
  81. protected ORB orb;
  82. protected ORBUtilSystemException wrapper ;
  83. protected boolean debug = false;
  84. protected int blockSizeIndex = -1;
  85. protected int blockSizePosition = 0;
  86. protected byte streamFormatVersion;
  87. private static final int DEFAULT_BUFFER_SIZE = 1024;
  88. private static final String kWriteMethod = "write";
  89. // Codebase cache
  90. private CacheTable codebaseCache = null;
  91. // Value cache
  92. private CacheTable valueCache = null;
  93. // Repository ID cache
  94. private CacheTable repositoryIdCache = null;
  95. // Write end flag
  96. private int end_flag = 0;
  97. // Beginning with the resolution to interop issue 3526,
  98. // only enclosing chunked valuetypes are taken into account
  99. // when computing the nesting level. However, we still need
  100. // the old computation around for interoperability with our
  101. // older ORBs.
  102. private int chunkedValueNestingLevel = 0;
  103. private boolean mustChunk = false;
  104. // In block marker
  105. protected boolean inBlock = false;
  106. // Last end tag position
  107. private int end_flag_position = 0;
  108. private int end_flag_index = 0;
  109. // ValueHandler
  110. private ValueHandler valueHandler = null;
  111. // Repository ID handlers
  112. private RepositoryIdUtility repIdUtil;
  113. private RepositoryIdStrings repIdStrs;
  114. // Code set converters (created when first needed)
  115. private CodeSetConversion.CTBConverter charConverter;
  116. private CodeSetConversion.CTBConverter wcharConverter;
  117. // REVISIT - This should be re-factored so that including whether
  118. // to use pool byte buffers or not doesn't need to be known.
  119. public void init(org.omg.CORBA.ORB orb,
  120. boolean littleEndian,
  121. BufferManagerWrite bufferManager,
  122. byte streamFormatVersion,
  123. boolean usePooledByteBuffers)
  124. {
  125. // ORB must not be null. See CDROutputStream constructor.
  126. this.orb = (ORB)orb;
  127. this.wrapper = ORBUtilSystemException.get( this.orb,
  128. CORBALogDomains.RPC_ENCODING ) ;
  129. debug = this.orb.transportDebugFlag;
  130. this.littleEndian = littleEndian;
  131. this.bufferManagerWrite = bufferManager;
  132. this.bbwi = new ByteBufferWithInfo(orb, bufferManager, usePooledByteBuffers);
  133. this.streamFormatVersion = streamFormatVersion;
  134. createRepositoryIdHandlers();
  135. }
  136. public void init(org.omg.CORBA.ORB orb,
  137. boolean littleEndian,
  138. BufferManagerWrite bufferManager,
  139. byte streamFormatVersion)
  140. {
  141. init(orb, littleEndian, bufferManager, streamFormatVersion, true);
  142. }
  143. private final void createRepositoryIdHandlers()
  144. {
  145. if (orb != null) {
  146. // Get the appropriate versions based on the ORB version. The
  147. // ORB versioning info is only in the core ORB.
  148. repIdUtil
  149. = RepositoryIdFactory.getRepIdUtility(orb);
  150. repIdStrs
  151. = RepositoryIdFactory.getRepIdStringsFactory(orb);
  152. } else {
  153. // Get the latest versions
  154. repIdUtil = RepositoryIdFactory.getRepIdUtility();
  155. repIdStrs = RepositoryIdFactory.getRepIdStringsFactory();
  156. }
  157. }
  158. public BufferManagerWrite getBufferManager()
  159. {
  160. return bufferManagerWrite;
  161. }
  162. public byte[] toByteArray() {
  163. byte[] it;
  164. it = new byte[bbwi.position()];
  165. // Micro-benchmarks show ByteBuffer.get(int) out perform the bulk
  166. // ByteBuffer.get(byte[], offset, length).
  167. for (int i = 0; i < bbwi.position(); i++)
  168. it[i] = bbwi.byteBuffer.get(i);
  169. return it;
  170. }
  171. public GIOPVersion getGIOPVersion() {
  172. return GIOPVersion.V1_0;
  173. }
  174. // Called by Request and Reply message. Valid for GIOP versions >= 1.2 only.
  175. // Illegal for GIOP versions < 1.2.
  176. void setHeaderPadding(boolean headerPadding) {
  177. throw wrapper.giopVersionError();
  178. }
  179. protected void handleSpecialChunkBegin(int requiredSize)
  180. {
  181. // No-op for GIOP 1.0
  182. }
  183. protected void handleSpecialChunkEnd()
  184. {
  185. // No-op for GIOP 1.0
  186. }
  187. protected final int computeAlignment(int align) {
  188. if (align > 1) {
  189. int incr = bbwi.position() & (align - 1);
  190. if (incr != 0)
  191. return align - incr;
  192. }
  193. return 0;
  194. }
  195. protected void alignAndReserve(int align, int n) {
  196. bbwi.position(bbwi.position() + computeAlignment(align));
  197. if (bbwi.position() + n > bbwi.buflen)
  198. grow(align, n);
  199. }
  200. //
  201. // Default implementation of grow. Subclassers may override this.
  202. // Always grow the single buffer. This needs to delegate
  203. // fragmentation policy for IIOP 1.1.
  204. //
  205. protected void grow(int align, int n)
  206. {
  207. bbwi.needed = n;
  208. bufferManagerWrite.overflow(bbwi);
  209. }
  210. public final void putEndian() throws SystemException {
  211. write_boolean(littleEndian);
  212. }
  213. public final boolean littleEndian() {
  214. return littleEndian;
  215. }
  216. void freeInternalCaches() {
  217. if (codebaseCache != null)
  218. codebaseCache.done();
  219. if (valueCache != null)
  220. valueCache.done();
  221. if (repositoryIdCache != null)
  222. repositoryIdCache.done();
  223. }
  224. // No such type in java
  225. public final void write_longdouble(double x)
  226. {
  227. throw wrapper.longDoubleNotImplemented(
  228. CompletionStatus.COMPLETED_MAYBE ) ;
  229. }
  230. public void write_octet(byte x)
  231. {
  232. // The 'if' stmt is commented out since we need the alignAndReserve to
  233. // be called, particularly when the first body byte is written,
  234. // to induce header padding to align the body on a 8-octet boundary,
  235. // for GIOP versions 1.2 and above. Refer to internalWriteOctetArray()
  236. // method that also has a similar change.
  237. //if (bbwi.position() + 1 > bbwi.buflen)
  238. alignAndReserve(1, 1);
  239. // REVISIT - Should just use ByteBuffer.put(byte) and let it
  240. // increment the ByteBuffer position. This is true
  241. // for all write operations in this file.
  242. bbwi.byteBuffer.put(bbwi.position(), x);
  243. bbwi.position(bbwi.position() + 1);
  244. }
  245. public final void write_boolean(boolean x)
  246. {
  247. write_octet(x? (byte)1:(byte)0);
  248. }
  249. public void write_char(char x)
  250. {
  251. CodeSetConversion.CTBConverter converter = getCharConverter();
  252. converter.convert(x);
  253. // CORBA formal 99-10-07 15.3.1.6: "In the case of multi-byte encodings
  254. // of characters, a single instance of the char type may only
  255. // hold one octet of any multi-byte character encoding."
  256. if (converter.getNumBytes() > 1)
  257. throw wrapper.invalidSingleCharCtb(CompletionStatus.COMPLETED_MAYBE);
  258. write_octet(converter.getBytes()[0]);
  259. }
  260. // These wchar methods are only used when talking to
  261. // legacy ORBs, now.
  262. private final void writeLittleEndianWchar(char x) {
  263. bbwi.byteBuffer.put(bbwi.position(), (byte)(x & 0xFF));
  264. bbwi.byteBuffer.put(bbwi.position() + 1, (byte)((x >>> 8) & 0xFF));
  265. bbwi.position(bbwi.position() + 2);
  266. }
  267. private final void writeBigEndianWchar(char x) {
  268. bbwi.byteBuffer.put(bbwi.position(), (byte)((x >>> 8) & 0xFF));
  269. bbwi.byteBuffer.put(bbwi.position() + 1, (byte)(x & 0xFF));
  270. bbwi.position(bbwi.position() + 2);
  271. }
  272. private final void writeLittleEndianShort(short x) {
  273. bbwi.byteBuffer.put(bbwi.position(), (byte)(x & 0xFF));
  274. bbwi.byteBuffer.put(bbwi.position() + 1, (byte)((x >>> 8) & 0xFF));
  275. bbwi.position(bbwi.position() + 2);
  276. }
  277. private final void writeBigEndianShort(short x) {
  278. bbwi.byteBuffer.put(bbwi.position(), (byte)((x >>> 8) & 0xFF));
  279. bbwi.byteBuffer.put(bbwi.position() + 1, (byte)(x & 0xFF));
  280. bbwi.position(bbwi.position() + 2);
  281. }
  282. private final void writeLittleEndianLong(int x) {
  283. bbwi.byteBuffer.put(bbwi.position(), (byte)(x & 0xFF));
  284. bbwi.byteBuffer.put(bbwi.position() + 1, (byte)((x >>> 8) & 0xFF));
  285. bbwi.byteBuffer.put(bbwi.position() + 2, (byte)((x >>> 16) & 0xFF));
  286. bbwi.byteBuffer.put(bbwi.position() + 3, (byte)((x >>> 24) & 0xFF));
  287. bbwi.position(bbwi.position() + 4);
  288. }
  289. private final void writeBigEndianLong(int x) {
  290. bbwi.byteBuffer.put(bbwi.position(), (byte)((x >>> 24) & 0xFF));
  291. bbwi.byteBuffer.put(bbwi.position() + 1, (byte)((x >>> 16) & 0xFF));
  292. bbwi.byteBuffer.put(bbwi.position() + 2, (byte)((x >>> 8) & 0xFF));
  293. bbwi.byteBuffer.put(bbwi.position() + 3, (byte)(x & 0xFF));
  294. bbwi.position(bbwi.position() + 4);
  295. }
  296. private final void writeLittleEndianLongLong(long x) {
  297. bbwi.byteBuffer.put(bbwi.position(), (byte)(x & 0xFF));
  298. bbwi.byteBuffer.put(bbwi.position() + 1, (byte)((x >>> 8) & 0xFF));
  299. bbwi.byteBuffer.put(bbwi.position() + 2, (byte)((x >>> 16) & 0xFF));
  300. bbwi.byteBuffer.put(bbwi.position() + 3, (byte)((x >>> 24) & 0xFF));
  301. bbwi.byteBuffer.put(bbwi.position() + 4, (byte)((x >>> 32) & 0xFF));
  302. bbwi.byteBuffer.put(bbwi.position() + 5, (byte)((x >>> 40) & 0xFF));
  303. bbwi.byteBuffer.put(bbwi.position() + 6, (byte)((x >>> 48) & 0xFF));
  304. bbwi.byteBuffer.put(bbwi.position() + 7, (byte)((x >>> 56) & 0xFF));
  305. bbwi.position(bbwi.position() + 8);
  306. }
  307. private final void writeBigEndianLongLong(long x) {
  308. bbwi.byteBuffer.put(bbwi.position(), (byte)((x >>> 56) & 0xFF));
  309. bbwi.byteBuffer.put(bbwi.position() + 1, (byte)((x >>> 48) & 0xFF));
  310. bbwi.byteBuffer.put(bbwi.position() + 2, (byte)((x >>> 40) & 0xFF));
  311. bbwi.byteBuffer.put(bbwi.position() + 3, (byte)((x >>> 32) & 0xFF));
  312. bbwi.byteBuffer.put(bbwi.position() + 4, (byte)((x >>> 24) & 0xFF));
  313. bbwi.byteBuffer.put(bbwi.position() + 5, (byte)((x >>> 16) & 0xFF));
  314. bbwi.byteBuffer.put(bbwi.position() + 6, (byte)((x >>> 8) & 0xFF));
  315. bbwi.byteBuffer.put(bbwi.position() + 7, (byte)(x & 0xFF));
  316. bbwi.position(bbwi.position() + 8);
  317. }
  318. public void write_wchar(char x)
  319. {
  320. // Don't allow transmission of wchar/wstring data with
  321. // foreign ORBs since it's against the spec.
  322. if (ORBUtility.isForeignORB(orb)) {
  323. throw wrapper.wcharDataInGiop10(CompletionStatus.COMPLETED_MAYBE);
  324. }
  325. // If it's one of our legacy ORBs, do what they did:
  326. alignAndReserve(2, 2);
  327. if (littleEndian) {
  328. writeLittleEndianWchar(x);
  329. } else {
  330. writeBigEndianWchar(x);
  331. }
  332. }
  333. public void write_short(short x)
  334. {
  335. alignAndReserve(2, 2);
  336. if (littleEndian) {
  337. writeLittleEndianShort(x);
  338. } else {
  339. writeBigEndianShort(x);
  340. }
  341. }
  342. public final void write_ushort(short x)
  343. {
  344. write_short(x);
  345. }
  346. public void write_long(int x)
  347. {
  348. alignAndReserve(4, 4);
  349. if (littleEndian) {
  350. writeLittleEndianLong(x);
  351. } else {
  352. writeBigEndianLong(x);
  353. }
  354. }
  355. public final void write_ulong(int x)
  356. {
  357. write_long(x);
  358. }
  359. public void write_longlong(long x)
  360. {
  361. alignAndReserve(8, 8);
  362. if (littleEndian) {
  363. writeLittleEndianLongLong(x);
  364. } else {
  365. writeBigEndianLongLong(x);
  366. }
  367. }
  368. public final void write_ulonglong(long x)
  369. {
  370. write_longlong(x);
  371. }
  372. public final void write_float(float x)
  373. {
  374. write_long(Float.floatToIntBits(x));
  375. }
  376. public final void write_double(double x)
  377. {
  378. write_longlong(Double.doubleToLongBits(x));
  379. }
  380. public void write_string(String value)
  381. {
  382. writeString(value);
  383. }
  384. protected int writeString(String value)
  385. {
  386. if (value == null) {
  387. throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
  388. }
  389. CodeSetConversion.CTBConverter converter = getCharConverter();
  390. converter.convert(value);
  391. // A string is encoded as an unsigned CORBA long for the
  392. // number of bytes to follow (including a terminating null).
  393. // There is only one octet per character in the string.
  394. int len = converter.getNumBytes() + 1;
  395. handleSpecialChunkBegin(computeAlignment(4) + 4 + len);
  396. write_long(len);
  397. int indirection = get_offset() - 4;
  398. internalWriteOctetArray(converter.getBytes(), 0, converter.getNumBytes());
  399. // Write the null ending
  400. write_octet((byte)0);
  401. handleSpecialChunkEnd();
  402. return indirection;
  403. }
  404. public void write_wstring(String value)
  405. {
  406. if (value == null)
  407. throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
  408. // Don't allow transmission of wchar/wstring data with
  409. // foreign ORBs since it's against the spec.
  410. if (ORBUtility.isForeignORB(orb)) {
  411. throw wrapper.wcharDataInGiop10(CompletionStatus.COMPLETED_MAYBE);
  412. }
  413. // When talking to our legacy ORBs, do what they did:
  414. int len = value.length() + 1;
  415. // This will only have an effect if we're already chunking
  416. handleSpecialChunkBegin(4 + (len * 2) + computeAlignment(4));
  417. write_long(len);
  418. for (int i = 0; i < len - 1; i++)
  419. write_wchar(value.charAt(i));
  420. // Write the null ending
  421. write_short((short)0);
  422. // This will only have an effect if we're already chunking
  423. handleSpecialChunkEnd();
  424. }
  425. // Performs no checks and doesn't tamper with chunking
  426. void internalWriteOctetArray(byte[] value, int offset, int length)
  427. {
  428. int n = offset;
  429. // This flag forces the alignAndReserve method to be called the
  430. // first time an octet is written. This is necessary to ensure
  431. // that the body is aligned on an 8-octet boundary. Note the 'if'
  432. // condition inside the 'while' loop below. Also, refer to the
  433. // write_octet() method that has a similar change.
  434. boolean align = true;
  435. while (n < length+offset) {
  436. int avail;
  437. int bytes;
  438. int wanted;
  439. if ((bbwi.position() + 1 > bbwi.buflen) || align) {
  440. align = false;
  441. alignAndReserve(1, 1);
  442. }
  443. avail = bbwi.buflen - bbwi.position();
  444. wanted = (length + offset) - n;
  445. bytes = (wanted < avail) ? wanted : avail;
  446. for (int i = 0; i < bytes; i++)
  447. bbwi.byteBuffer.put(bbwi.position() + i, value[n+i]);
  448. bbwi.position(bbwi.position() + bytes);
  449. n += bytes;
  450. }
  451. }
  452. public final void write_octet_array(byte b[], int offset, int length)
  453. {
  454. if ( b == null )
  455. throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
  456. // This will only have an effect if we're already chunking
  457. handleSpecialChunkBegin(length);
  458. internalWriteOctetArray(b, offset, length);
  459. // This will only have an effect if we're already chunking
  460. handleSpecialChunkEnd();
  461. }
  462. public void write_Principal(Principal p)
  463. {
  464. write_long(p.name().length);
  465. write_octet_array(p.name(), 0, p.name().length);
  466. }
  467. public void write_any(Any any)
  468. {
  469. if ( any == null )
  470. throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
  471. write_TypeCode(any.type());
  472. any.write_value(parent);
  473. }
  474. public void write_TypeCode(TypeCode tc)
  475. {
  476. if ( tc == null ) {
  477. throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
  478. }
  479. TypeCodeImpl tci;
  480. if (tc instanceof TypeCodeImpl) {
  481. tci = (TypeCodeImpl)tc;
  482. }
  483. else {
  484. tci = new TypeCodeImpl(orb, tc);
  485. }
  486. tci.write_value((org.omg.CORBA_2_3.portable.OutputStream)parent);
  487. }
  488. public void write_Object(org.omg.CORBA.Object ref)
  489. {
  490. if (ref == null) {
  491. IOR nullIOR = IORFactories.makeIOR( orb ) ;
  492. nullIOR.write(parent);
  493. return;
  494. }
  495. // IDL to Java formal 01-06-06 1.21.4.2
  496. if (ref instanceof org.omg.CORBA.LocalObject)
  497. throw wrapper.writeLocalObject(CompletionStatus.COMPLETED_MAYBE);
  498. IOR ior = ORBUtility.connectAndGetIOR( orb, ref ) ;
  499. ior.write(parent);
  500. return;
  501. }
  502. // ------------ RMI related methods --------------------------
  503. public void write_abstract_interface(java.lang.Object obj) {
  504. boolean corbaObject = false; // Assume value type.
  505. org.omg.CORBA.Object theObject = null;
  506. // Is it a CORBA.Object?
  507. if (obj != null && obj instanceof org.omg.CORBA.Object) {
  508. // Yes.
  509. theObject = (org.omg.CORBA.Object)obj;
  510. corbaObject = true;
  511. }
  512. // Write our flag...
  513. write_boolean(corbaObject);
  514. // Now write out the object...
  515. if (corbaObject) {
  516. write_Object(theObject);
  517. } else {
  518. try {
  519. write_value((java.io.Serializable)obj);
  520. } catch(ClassCastException cce) {
  521. if (obj instanceof java.io.Serializable)
  522. throw cce;
  523. else
  524. ORBUtility.throwNotSerializableForCorba(obj.getClass().getName());
  525. }
  526. }
  527. }
  528. public void write_value(Serializable object, Class clz) {
  529. write_value(object);
  530. }
  531. private void writeWStringValue(String string) {
  532. int indirection = writeValueTag(mustChunk, false, null);
  533. // Write WStringValue's repository ID
  534. write_repositoryId(repIdStrs.getWStringValueRepId());
  535. // Add indirection for object to indirection table
  536. updateIndirectionTable(indirection, string, string);
  537. // Write Value chunk
  538. if (mustChunk) {
  539. start_block();
  540. end_flag--;
  541. chunkedValueNestingLevel--;
  542. } else
  543. end_flag--;
  544. write_wstring(string);
  545. if (mustChunk)
  546. end_block();
  547. // Write end tag
  548. writeEndTag(mustChunk);
  549. }
  550. private void writeArray(Serializable array, Class clazz) {
  551. if (valueHandler == null)
  552. valueHandler = ORBUtility.createValueHandler(orb); //d11638
  553. // Write value_tag
  554. int indirection = writeValueTag(mustChunk, false, Util.getCodebase(clazz));
  555. // Write repository ID
  556. write_repositoryId(repIdStrs.createSequenceRepID(clazz));
  557. // Add indirection for object to indirection table
  558. updateIndirectionTable(indirection, array, array);
  559. // Write Value chunk
  560. if (mustChunk) {
  561. start_block();
  562. end_flag--;
  563. chunkedValueNestingLevel--;
  564. } else
  565. end_flag--;
  566. if (valueHandler instanceof ValueHandlerMultiFormat) {
  567. ValueHandlerMultiFormat vh = (ValueHandlerMultiFormat)valueHandler;
  568. vh.writeValue(parent, array, streamFormatVersion);
  569. } else
  570. valueHandler.writeValue(parent, array);
  571. if (mustChunk)
  572. end_block();
  573. // Write end tag
  574. writeEndTag(mustChunk);
  575. }
  576. private void writeValueBase(org.omg.CORBA.portable.ValueBase object,
  577. Class clazz) {
  578. // _REVISIT_ could check to see whether chunking really needed
  579. mustChunk = true;
  580. // Write value_tag
  581. int indirection = writeValueTag(true, false, Util.getCodebase(clazz));
  582. // Get rep id
  583. String repId = ((ValueBase)object)._truncatable_ids()[0];
  584. // Write rep id
  585. write_repositoryId(repId);
  586. // Add indirection for object to indirection table
  587. updateIndirectionTable(indirection, object, object);
  588. // Write Value chunk
  589. start_block();
  590. end_flag--;
  591. chunkedValueNestingLevel--;
  592. writeIDLValue(object, repId);
  593. end_block();
  594. // Write end tag
  595. writeEndTag(true);
  596. }
  597. private void writeRMIIIOPValueType(Serializable object, Class clazz) {
  598. if (valueHandler == null)
  599. valueHandler = ORBUtility.createValueHandler(orb); //d11638
  600. Serializable key = object;
  601. // Allow the ValueHandler to call writeReplace on
  602. // the Serializable (if the method is present)
  603. object = valueHandler.writeReplace(key);
  604. if (object == null) {
  605. // Write null tag and return
  606. write_long(0);
  607. return;
  608. }
  609. if (object != key) {
  610. if (valueCache != null && valueCache.containsKey(object)) {
  611. writeIndirection(INDIRECTION_TAG, valueCache.getVal(object));
  612. return;
  613. }
  614. clazz = object.getClass();
  615. }
  616. if (mustChunk || valueHandler.isCustomMarshaled(clazz)) {
  617. mustChunk = true;
  618. }
  619. // Write value_tag
  620. int indirection = writeValueTag(mustChunk, false, Util.getCodebase(clazz));
  621. // Write rep. id
  622. write_repositoryId(repIdStrs.createForJavaType(clazz));
  623. // Add indirection for object to indirection table
  624. updateIndirectionTable(indirection, object, key);
  625. if (mustChunk) {
  626. // Write Value chunk
  627. end_flag--;
  628. chunkedValueNestingLevel--;
  629. start_block();
  630. } else
  631. end_flag--;
  632. if (valueHandler instanceof ValueHandlerMultiFormat) {
  633. ValueHandlerMultiFormat vh = (ValueHandlerMultiFormat)valueHandler;
  634. vh.writeValue(parent, object, streamFormatVersion);
  635. } else
  636. valueHandler.writeValue(parent, object);
  637. if (mustChunk)
  638. end_block();
  639. // Write end tag
  640. writeEndTag(mustChunk);
  641. }
  642. public void write_value(Serializable object, String repository_id) {
  643. // Handle null references
  644. if (object == null) {
  645. // Write null tag and return
  646. write_long(0);
  647. return;
  648. }
  649. // Handle shared references
  650. if (valueCache != null && valueCache.containsKey(object)) {
  651. writeIndirection(INDIRECTION_TAG, valueCache.getVal(object));
  652. return;
  653. }
  654. Class clazz = object.getClass();
  655. boolean oldMustChunk = mustChunk;
  656. if (mustChunk)
  657. mustChunk = true;
  658. if (inBlock)
  659. end_block();
  660. if (clazz.isArray()) {
  661. // Handle arrays
  662. writeArray(object, clazz);
  663. } else if (object instanceof org.omg.CORBA.portable.ValueBase) {
  664. // Handle IDL Value types
  665. writeValueBase((org.omg.CORBA.portable.ValueBase)object, clazz);
  666. } else if (shouldWriteAsIDLEntity(object)) {
  667. writeIDLEntity((IDLEntity)object);
  668. } else if (object instanceof java.lang.String) {
  669. writeWStringValue((String)object);
  670. } else if (object instanceof java.lang.Class) {
  671. writeClass(repository_id, (Class)object);
  672. } else {
  673. // RMI-IIOP value type
  674. writeRMIIIOPValueType(object, clazz);
  675. }
  676. mustChunk = oldMustChunk;
  677. // Check to see if we need to start another block for a
  678. // possible outer value
  679. if (mustChunk)
  680. start_block();
  681. }
  682. public void write_value(Serializable object)
  683. {
  684. write_value(object, (String)null);
  685. }
  686. public void write_value(Serializable object, org.omg.CORBA.portable.BoxedValueHelper factory)
  687. {
  688. // Handle null references
  689. if (object == null) {
  690. // Write null tag and return
  691. write_long(0);
  692. return;
  693. }
  694. // Handle shared references
  695. if ((valueCache != null) && valueCache.containsKey(object)) {
  696. writeIndirection(INDIRECTION_TAG, valueCache.getVal(object));
  697. return;
  698. }
  699. boolean oldMustChunk = mustChunk;
  700. boolean isCustom = false;
  701. if (factory instanceof ValueHelper) {
  702. short modifier;
  703. try {
  704. modifier = ((ValueHelper)factory).get_type().type_modifier();
  705. } catch(BadKind ex) { // tk_value_box
  706. modifier = VM_NONE.value;
  707. }
  708. if (object instanceof CustomMarshal &&
  709. modifier == VM_CUSTOM.value) {
  710. isCustom = true;
  711. mustChunk = true;
  712. }
  713. if (modifier == VM_TRUNCATABLE.value)
  714. mustChunk = true;
  715. }
  716. if (mustChunk) {
  717. if (inBlock)
  718. end_block();
  719. // Write value_tag
  720. int indirection = writeValueTag(true, false, Util.getCodebase(object.getClass()));
  721. write_repositoryId(factory.get_id());
  722. // Add indirection for object to indirection table
  723. updateIndirectionTable(indirection, object, object);
  724. // Write Value chunk
  725. start_block();
  726. end_flag--;
  727. chunkedValueNestingLevel--;
  728. if (isCustom)
  729. ((CustomMarshal)object).marshal(parent);
  730. else
  731. factory.write_value(parent, object);
  732. end_block();
  733. // Write end tag
  734. writeEndTag(true);
  735. }
  736. else {
  737. // Write value_tag
  738. int indirection = writeValueTag(false, false, Util.getCodebase(object.getClass()));
  739. write_repositoryId(factory.get_id());
  740. // Add indirection for object to indirection table
  741. updateIndirectionTable(indirection, object, object);
  742. // Write Value chunk
  743. end_flag--;
  744. // no need to test for custom on the non-chunked path
  745. factory.write_value(parent, object);
  746. // Write end tag
  747. writeEndTag(false);
  748. }
  749. mustChunk = oldMustChunk;
  750. // Check to see if we need to start another block for a
  751. // possible outer value
  752. if (mustChunk)
  753. start_block();
  754. }
  755. public int get_offset() {
  756. return bbwi.position();
  757. }
  758. public void start_block() {
  759. if (debug) {
  760. dprint("CDROutputStream_1_0 start_block, position" + bbwi.position());
  761. }
  762. //Move inBlock=true to after write_long since write_long might
  763. //trigger grow which will lead to erroneous behavior with a
  764. //missing blockSizeIndex.
  765. //inBlock = true;
  766. // Save space in the buffer for block size
  767. write_long(0);
  768. //Has to happen after write_long since write_long could
  769. //trigger grow which is overridden by supper classes to
  770. //depend on inBlock.
  771. inBlock = true;
  772. blockSizePosition = get_offset();
  773. // Remember where to put the size of the endblock less 4
  774. blockSizeIndex = bbwi.position();
  775. if (debug) {
  776. dprint("CDROutputStream_1_0 start_block, blockSizeIndex "
  777. + blockSizeIndex);
  778. }
  779. }
  780. // Utility method which will hopefully decrease chunking complexity
  781. // by allowing us to end_block and update chunk lengths without
  782. // calling alignAndReserve. Otherwise, it's possible to get into
  783. // recursive scenarios which lose the chunking state.
  784. protected void writeLongWithoutAlign(int x) {
  785. if (littleEndian) {
  786. writeLittleEndianLong(x);
  787. } else {
  788. writeBigEndianLong(x);
  789. }
  790. }
  791. public void end_block() {
  792. if (debug) {
  793. dprint("CDROutputStream_1_0.java end_block");
  794. }
  795. if (!inBlock)
  796. return;
  797. if (debug) {
  798. dprint("CDROutputStream_1_0.java end_block, in a block");
  799. }
  800. inBlock = false;
  801. // Test to see if the block was of zero length
  802. // If so, remove the block instead of ending it
  803. // (This can happen if the last field written
  804. // in a value was another value)
  805. if (get_offset() == blockSizePosition) {
  806. // Need to assert that blockSizeIndex == bbwi.position()? REVISIT
  807. bbwi.position(bbwi.position() - 4);
  808. blockSizeIndex = -1;
  809. blockSizePosition = -1;
  810. return;
  811. }
  812. int oldSize = bbwi.position();
  813. bbwi.position(blockSizeIndex - 4);
  814. writeLongWithoutAlign(oldSize - blockSizeIndex);
  815. bbwi.position(oldSize);
  816. blockSizeIndex = -1;
  817. blockSizePosition = -1;
  818. // System.out.println(" post end_block: " + get_offset() + " " + bbwi.position());
  819. }
  820. public org.omg.CORBA.ORB orb()
  821. {
  822. return orb;
  823. }
  824. // ------------ End RMI related methods --------------------------
  825. public final void write_boolean_array(boolean[]value, int offset, int length) {
  826. if ( value == null )
  827. throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
  828. // This will only have an effect if we're already chunking
  829. handleSpecialChunkBegin(length);
  830. for (int i = 0; i < length; i++)
  831. write_boolean(value[offset + i]);
  832. // This will only have an effect if we're already chunking
  833. handleSpecialChunkEnd();
  834. }
  835. public final void write_char_array(char[]value, int offset, int length) {
  836. if ( value == null )
  837. throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
  838. // This will only have an effect if we're already chunking
  839. handleSpecialChunkBegin(length);
  840. for (int i = 0; i < length; i++)
  841. write_char(value[offset + i]);
  842. // This will only have an effect if we're already chunking
  843. handleSpecialChunkEnd();
  844. }
  845. public void write_wchar_array(char[]value, int offset, int length) {
  846. if ( value == null )
  847. throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
  848. // This will only have an effect if we're already chunking
  849. handleSpecialChunkBegin(computeAlignment(2) + (length * 2));
  850. for (int i = 0; i < length; i++)
  851. write_wchar(value[offset + i]);
  852. // This will only have an effect if we're already chunking
  853. handleSpecialChunkEnd();
  854. }
  855. public final void write_short_array(short[]value, int offset, int length) {
  856. if ( value == null )
  857. throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
  858. // This will only have an effect if we're already chunking
  859. handleSpecialChunkBegin(computeAlignment(2) + (length * 2));
  860. for (int i = 0; i < length; i++)
  861. write_short(value[offset + i]);
  862. // This will only have an effect if we're already chunking
  863. handleSpecialChunkEnd();
  864. }
  865. public final void write_ushort_array(short[]value, int offset, int length) {
  866. write_short_array(value, offset, length);
  867. }
  868. public final void write_long_array(int[]value, int offset, int length) {
  869. if ( value == null )
  870. throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
  871. // This will only have an effect if we're already chunking
  872. handleSpecialChunkBegin(computeAlignment(4) + (length * 4));
  873. for (int i = 0; i < length; i++)
  874. write_long(value[offset + i]);
  875. // This will only have an effect if we're already chunking
  876. handleSpecialChunkEnd();
  877. }
  878. public final void write_ulong_array(int[]value, int offset, int length) {
  879. write_long_array(value, offset, length);
  880. }
  881. public final void write_longlong_array(long[]value, int offset, int length) {
  882. if ( value == null )
  883. throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
  884. // This will only have an effect if we're already chunking
  885. handleSpecialChunkBegin(computeAlignment(8) + (length * 8));
  886. for (int i = 0; i < length; i++)
  887. write_longlong(value[offset + i]);
  888. // This will only have an effect if we're already chunking
  889. handleSpecialChunkEnd();
  890. }
  891. public final void write_ulonglong_array(long[]value, int offset, int length) {
  892. write_longlong_array(value, offset, length);
  893. }
  894. public final void write_float_array(float[]value, int offset, int length) {
  895. if ( value == null )
  896. throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
  897. // This will only have an effect if we're already chunking
  898. handleSpecialChunkBegin(computeAlignment(4) + (length * 4));
  899. for (int i = 0; i < length; i++)
  900. write_float(value[offset + i]);
  901. // This will only have an effect if we're already chunking
  902. handleSpecialChunkEnd();
  903. }
  904. public final void write_double_array(double[]value, int offset, int length) {
  905. if ( value == null )
  906. throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
  907. // This will only have an effect if we're already chunking
  908. handleSpecialChunkBegin(computeAlignment(8) + (length * 8));
  909. for (int i = 0; i < length; i++)
  910. write_double(value[offset + i]);
  911. // This will only have an effect if we're already chunking
  912. handleSpecialChunkEnd();
  913. }
  914. public void write_string_array(String[] value, int offset, int length) {
  915. if ( value == null )
  916. throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
  917. for(int i = 0; i < length; i++)
  918. write_string(value[offset + i]);
  919. }
  920. public void write_wstring_array(String[] value, int offset, int length) {
  921. if ( value == null )
  922. throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
  923. for(int i = 0; i < length; i++)
  924. write_wstring(value[offset + i]);
  925. }
  926. public final void write_any_array(org.omg.CORBA.Any value[], int offset, int length)
  927. {
  928. for(int i = 0; i < length; i++)
  929. write_any(value[offset + i]);
  930. }
  931. //--------------------------------------------------------------------//
  932. // CDROutputStream state management.
  933. //
  934. public void writeTo(java.io.OutputStream s)
  935. throws java.io.IOException
  936. {
  937. byte[] tmpBuf = null;
  938. if (bbwi.byteBuffer.hasArray())
  939. {
  940. tmpBuf = bbwi.byteBuffer.array();
  941. }
  942. else
  943. {
  944. int size = bbwi.position();
  945. tmpBuf = new byte[size];
  946. // Micro-benchmarks are showing a loop of ByteBuffer.get(int) is
  947. // faster than ByteBuffer.get(byte[], offset, length)
  948. for (int i = 0; i < size; i++)
  949. tmpBuf[i] = bbwi.byteBuffer.get(i);
  950. }
  951. s.write(tmpBuf, 0, bbwi.position());
  952. }
  953. public void writeOctetSequenceTo(org.omg.CORBA.portable.OutputStream s) {
  954. byte[] buf = null;
  955. if (bbwi.byteBuffer.hasArray())
  956. {
  957. buf = bbwi.byteBuffer.array();
  958. }
  959. else
  960. {
  961. int size = bbwi.position();
  962. buf = new byte[size];
  963. // Micro-benchmarks are showing a loop of ByteBuffer.get(int) is
  964. // faster than ByteBuffer.get(byte[], offset, length)
  965. for (int i = 0; i < size; i++)
  966. buf[i] = bbwi.byteBuffer.get(i);
  967. }
  968. s.write_long(bbwi.position());
  969. s.write_octet_array(buf, 0, bbwi.position());
  970. }
  971. public final int getSize() {
  972. return bbwi.position();
  973. }
  974. public int getIndex() {
  975. return bbwi.position();
  976. }
  977. public boolean isLittleEndian() {
  978. return littleEndian;
  979. }
  980. public void setIndex(int value) {
  981. bbwi.position(value);
  982. }
  983. public ByteBufferWithInfo getByteBufferWithInfo() {
  984. return bbwi;
  985. }
  986. public void setByteBufferWithInfo(ByteBufferWithInfo bbwi) {
  987. this.bbwi = bbwi;
  988. }
  989. public ByteBuffer getByteBuffer() {
  990. ByteBuffer result = null;;
  991. if (bbwi != null) {
  992. result = bbwi.byteBuffer;
  993. }
  994. return result;
  995. }
  996. public void setByteBuffer(ByteBuffer byteBuffer) {
  997. bbwi.byteBuffer = byteBuffer;
  998. }
  999. private final void updateIndirectionTable(int indirection, java.lang.Object object,
  1000. java.lang.Object key) {
  1001. // int indirection = get_offset();
  1002. if (valueCache == null)
  1003. valueCache = new CacheTable(orb,true);
  1004. valueCache.put(object, indirection);
  1005. if (key != object)
  1006. valueCache.put(key, indirection);
  1007. }
  1008. private final void write_repositoryId(String id) {
  1009. // Use an indirection if available
  1010. if (repositoryIdCache != null && repositoryIdCache.containsKey(id)) {
  1011. writeIndirection(INDIRECTION_TAG, repositoryIdCache.getVal(id));
  1012. return;
  1013. }
  1014. // Write it as a string. Note that we have already done the
  1015. // special case conversion of non-Latin-1 characters to escaped
  1016. // Latin-1 sequences in RepositoryId.
  1017. // It's not a good idea to cache them now that we can have
  1018. // multiple code sets.
  1019. int indirection = writeString(id);
  1020. // Add indirection for id to indirection table
  1021. if (repositoryIdCache == null)
  1022. repositoryIdCache = new CacheTable(orb,true);
  1023. repositoryIdCache.put(id, indirection);
  1024. }
  1025. private void write_codebase(String str, int pos) {
  1026. if (codebaseCache != null && codebaseCache.containsKey(str)) {
  1027. writeIndirection(INDIRECTION_TAG, codebaseCache.getVal(str));
  1028. }
  1029. else {
  1030. write_string(str);
  1031. if (codebaseCache == null)
  1032. codebaseCache = new CacheTable(orb,true);
  1033. codebaseCache.put(str, pos);
  1034. }
  1035. }
  1036. private final int writeValueTag(boolean chunkIt, boolean repNotWritten,
  1037. String codebase) {
  1038. int indirection = 0;
  1039. if (chunkIt && repNotWritten){
  1040. if (codebase == null) {
  1041. write_long(repIdUtil.getStandardRMIChunkedNoRepStrId());
  1042. indirection = get_offset() - 4;
  1043. } else {
  1044. write_long(repIdUtil.getCodeBaseRMIChunkedNoRepStrId());
  1045. indirection = get_offset() - 4;
  1046. write_codebase(codebase, get_offset());
  1047. }
  1048. } else if (chunkIt && !repNotWritten){
  1049. if (codebase == null) {
  1050. write_long(repIdUtil.getStandardRMIChunkedId());
  1051. indirection = get_offset() - 4;
  1052. } else {
  1053. write_long(repIdUtil.getCodeBaseRMIChunkedId());
  1054. indirection = get_offset() - 4;
  1055. write_codebase(codebase, get_offset());
  1056. }
  1057. } else {
  1058. if (codebase == null) {
  1059. write_long(repIdUtil.getStandardRMIUnchunkedId());
  1060. indirection = get_offset() - 4;
  1061. } else {
  1062. write_long(repIdUtil.getCodeBaseRMIUnchunkedId());
  1063. indirection = get_offset() - 4;
  1064. write_codebase(codebase, get_offset());
  1065. }
  1066. }
  1067. return indirection;
  1068. }
  1069. private void writeIDLValue(Serializable object, String repID)
  1070. {
  1071. if (object instanceof StreamableValue) {
  1072. ((StreamableValue)object)._write(parent);
  1073. } else if (object instanceof CustomValue) {
  1074. ((CustomValue)object).marshal(parent);
  1075. } else {
  1076. BoxedValueHelper helper = Utility.getHelper(object.getClass(), null, repID);
  1077. boolean isCustom = false;
  1078. if (helper instanceof ValueHelper && object instanceof CustomMarshal) {
  1079. try {
  1080. if (((ValueHelper)helper).get_type().type_modifier() == VM_CUSTOM.value)
  1081. isCustom = true;
  1082. } catch(BadKind ex) {
  1083. throw wrapper.badTypecodeForCustomValue( CompletionStatus.COMPLETED_MAYBE,
  1084. ex ) ;
  1085. }
  1086. }
  1087. if (isCustom)
  1088. ((CustomMarshal)object).marshal(parent);
  1089. else
  1090. helper.write_value(parent, object);
  1091. }
  1092. }
  1093. // Handles end tag compaction...
  1094. private void writeEndTag(boolean chunked){
  1095. if (chunked) {
  1096. if (get_offset() == end_flag_position) {
  1097. if (bbwi.position() == end_flag_index) {
  1098. // We are exactly at the same position and index as the
  1099. // end of the last end tag. Thus, we can back up over it
  1100. // and compact the tags.
  1101. bbwi.position(bbwi.position() - 4);
  1102. } else {
  1103. // Special case in which we're at the beginning of a new
  1104. // fragment, but the position is the same. We can't back up,
  1105. // so we just write the new end tag without compaction. This
  1106. // occurs when a value ends and calls start_block to open a
  1107. // continuation chunk, but it's called at the very end of
  1108. // a fragment.
  1109. }
  1110. }
  1111. writeNestingLevel();
  1112. // Remember the last index and position. These are only used when chunking.
  1113. end_flag_index = bbwi.position();
  1114. end_flag_position = get_offset();
  1115. chunkedValueNestingLevel++;
  1116. }
  1117. // Increment the nesting level
  1118. end_flag++;
  1119. }
  1120. /**
  1121. * Handles ORB versioning of the end tag. Should only
  1122. * be called if chunking.
  1123. *
  1124. * If talking to our older ORBs (Standard Extension,
  1125. * Kestrel, and Ladybird), write the end flag that takes
  1126. * into account all enclosing valuetypes.
  1127. *
  1128. * If talking a newer or foreign ORB, or if the orb
  1129. * instance is null, write the end flag that only takes
  1130. * into account the enclosing chunked valuetypes.
  1131. */
  1132. private void writeNestingLevel() {
  1133. if (orb == null ||
  1134. ORBVersionFactory.getFOREIGN().equals(orb.getORBVersion()) ||
  1135. ORBVersionFactory.getNEWER().compareTo(orb.getORBVersion()) <= 0) {
  1136. write_long(chunkedValueNestingLevel);
  1137. } else {
  1138. write_long(end_flag);
  1139. }
  1140. }
  1141. private void writeClass(String repository_id, Class clz) {
  1142. if (repository_id == null)
  1143. repository_id = repIdStrs.getClassDescValueRepId();
  1144. // Write value_tag
  1145. int indirection = writeValueTag(mustChunk, false, null);
  1146. updateIndirectionTable(indirection, clz, clz);
  1147. write_repositoryId(repository_id);
  1148. if (mustChunk) {
  1149. // Write Value chunk
  1150. start_block();
  1151. end_flag--;
  1152. chunkedValueNestingLevel--;
  1153. } else
  1154. end_flag--;
  1155. writeClassBody(clz);
  1156. if (mustChunk)
  1157. end_block();
  1158. // Write end tag
  1159. writeEndTag(mustChunk);
  1160. }
  1161. // Pre-Merlin/J2EE 1.3 ORBs wrote the repository ID
  1162. // and codebase strings in the wrong order. This handles
  1163. // backwards compatibility.
  1164. private void writeClassBody(Class clz) {
  1165. if (orb == null ||
  1166. ORBVersionFactory.getFOREIGN().equals(orb.getORBVersion()) ||
  1167. ORBVersionFactory.getNEWER().compareTo(orb.getORBVersion()) <= 0) {
  1168. write_value(Util.getCodebase(clz));
  1169. write_value(repIdStrs.createForAnyType(clz));
  1170. } else {
  1171. write_value(repIdStrs.createForAnyType(clz));
  1172. write_value(Util.getCodebase(clz));
  1173. }
  1174. }
  1175. // Casts and returns an Object as a Serializable
  1176. // This is required for JDK 1.1 only to avoid VerifyErrors when
  1177. // passing arrays as Serializable
  1178. // private java.io.Serializable make_serializable(java.lang.Object object)
  1179. // {
  1180. // return (java.io.Serializable)object;
  1181. // }
  1182. private boolean shouldWriteAsIDLEntity(Serializable object)
  1183. {
  1184. return ((object instanceof IDLEntity) && (!(object instanceof ValueBase)) &&
  1185. (!(object instanceof org.omg.CORBA.Object)));
  1186. }
  1187. private void writeIDLEntity(IDLEntity object) {
  1188. // _REVISIT_ could check to see whether chunking really needed
  1189. mustChunk = true;
  1190. String repository_id = repIdStrs.createForJavaType(object);
  1191. Class clazz = object.getClass();
  1192. String codebase = Util.getCodebase(clazz);
  1193. // Write value_tag
  1194. int indirection = writeValueTag(true, false, codebase);
  1195. updateIndirectionTable(indirection, object, object);
  1196. // Write rep. id
  1197. write_repositoryId(repository_id);
  1198. // Write Value chunk
  1199. end_flag--;
  1200. chunkedValueNestingLevel--;
  1201. start_block();
  1202. // Write the IDLEntity using reflection
  1203. try {
  1204. ClassLoader clazzLoader = (clazz == null ? null : clazz.getClassLoader());
  1205. final Class helperClass = Utility.loadClassForClass(clazz.getName()+"Helper", codebase,
  1206. clazzLoader, clazz, clazzLoader);
  1207. final Class argTypes[] = {org.omg.CORBA.portable.OutputStream.class, clazz};
  1208. // getDeclaredMethod requires RuntimePermission accessDeclaredMembers
  1209. // if a different class loader is used (even though the javadoc says otherwise)
  1210. Method writeMethod = null;
  1211. try {
  1212. writeMethod = (Method)AccessController.doPrivileged(
  1213. new PrivilegedExceptionAction() {
  1214. public java.lang.Object run() throws NoSuchMethodException {
  1215. return helperClass.getDeclaredMethod(kWriteMethod, argTypes);
  1216. }
  1217. }
  1218. );
  1219. } catch (PrivilegedActionException pae) {
  1220. // this gets caught below
  1221. throw (NoSuchMethodException)pae.getException();
  1222. }
  1223. java.lang.Object args[] = {parent, object};
  1224. writeMethod.invoke(null, args);
  1225. } catch (ClassNotFoundException cnfe) {
  1226. throw wrapper.errorInvokingHelperWrite( CompletionStatus.COMPLETED_MAYBE, cnfe ) ;
  1227. } catch(NoSuchMethodException nsme) {
  1228. throw wrapper.errorInvokingHelperWrite( CompletionStatus.COMPLETED_MAYBE, nsme ) ;
  1229. } catch(IllegalAccessException iae) {
  1230. throw wrapper.errorInvokingHelperWrite( CompletionStatus.COMPLETED_MAYBE, iae ) ;
  1231. } catch(InvocationTargetException ite) {
  1232. throw wrapper.errorInvokingHelperWrite( CompletionStatus.COMPLETED_MAYBE, ite ) ;
  1233. }
  1234. end_block();
  1235. // Write end tag
  1236. writeEndTag(true);
  1237. }
  1238. /* DataOutputStream methods */
  1239. public void write_Abstract (java.lang.Object value) {
  1240. write_abstract_interface(value);
  1241. }
  1242. public void write_Value (java.io.Serializable value) {
  1243. write_value(value);
  1244. }
  1245. // This will stay a custom add-on until the java-rtf issue is resolved.
  1246. // Then it should be declared in org.omg.CORBA.portable.OutputStream.
  1247. //
  1248. // Pads the string representation of bigDecimal with zeros to fit the given
  1249. // digits and scale before it gets written to the stream.
  1250. public void write_fixed(java.math.BigDecimal bigDecimal, short digits, short scale) {
  1251. String string = bigDecimal.toString();
  1252. String integerPart;
  1253. String fractionPart;
  1254. StringBuffer stringBuffer;
  1255. // Get rid of the sign
  1256. if (string.charAt(0) == '-' || string.charAt(0) == '+') {
  1257. string = string.substring(1);
  1258. }
  1259. // Determine integer and fraction parts
  1260. int dotIndex = string.indexOf('.');
  1261. if (dotIndex == -1) {
  1262. integerPart = string;
  1263. fractionPart = null;
  1264. } else if (dotIndex == 0 ) {
  1265. integerPart = null;
  1266. fractionPart = string;
  1267. } else {
  1268. integerPart = string.substring(0, dotIndex);
  1269. fractionPart = string.substring(dotIndex + 1);
  1270. }
  1271. // Pad both parts with zeros as necessary
  1272. stringBuffer = new StringBuffer(digits);
  1273. if (fractionPart != null) {
  1274. stringBuffer.append(fractionPart);
  1275. }
  1276. while (stringBuffer.length() < scale) {
  1277. stringBuffer.append('0');
  1278. }
  1279. if (integerPart != null) {
  1280. stringBuffer.insert(0, integerPart);
  1281. }
  1282. while (stringBuffer.length() < digits) {
  1283. stringBuffer.insert(0, '0');
  1284. }
  1285. // This string contains no sign or dot
  1286. this.write_fixed(stringBuffer.toString(), bigDecimal.signum());
  1287. }
  1288. // This method should be remove by the java-rtf issue.
  1289. // Right now the scale and digits information of the type code is lost.
  1290. public void write_fixed(java.math.BigDecimal bigDecimal) {
  1291. // This string might contain sign and/or dot
  1292. this.write_fixed(bigDecimal.toString(), bigDecimal.signum());
  1293. }
  1294. // The string may contain a sign and dot
  1295. public void write_fixed(String string, int signum) {
  1296. int stringLength = string.length();
  1297. // Each octet contains (up to) two decimal digits
  1298. byte doubleDigit = 0;
  1299. char ch;
  1300. byte digit;
  1301. // First calculate the length of the string without optional sign and dot
  1302. int numDigits = 0;
  1303. for (int i=0; i<stringLength; i++) {
  1304. ch = string.charAt(i);
  1305. if (ch == '-' || ch == '+' || ch == '.')
  1306. continue;
  1307. numDigits++;
  1308. }
  1309. for (int i=0; i<stringLength; i++) {
  1310. ch = string.charAt(i);
  1311. if (ch == '-' || ch == '+' || ch == '.')
  1312. continue;
  1313. digit = (byte)Character.digit(ch, 10);
  1314. if (digit == -1) {
  1315. throw wrapper.badDigitInFixed( CompletionStatus.COMPLETED_MAYBE ) ;
  1316. }
  1317. // If the fixed type has an odd number of decimal digits,
  1318. // then the representation begins with the first (most significant) digit.
  1319. // Otherwise, this first half-octet is all zero, and the first digit
  1320. // is in the second half-octet.
  1321. if (numDigits % 2 == 0) {
  1322. doubleDigit |= digit;
  1323. this.write_octet(doubleDigit);
  1324. doubleDigit = 0;
  1325. } else {
  1326. doubleDigit |= (digit << 4);
  1327. }
  1328. numDigits--;
  1329. }
  1330. // The sign configuration, in the last half-octet of the representation,
  1331. // is 0xD for negative numbers and 0xC for positive and zero values
  1332. if (signum == -1) {
  1333. doubleDigit |= 0xd;
  1334. } else {
  1335. doubleDigit |= 0xc;
  1336. }
  1337. this.write_octet(doubleDigit);
  1338. }
  1339. private final static String _id = "IDL:omg.org/CORBA/DataOutputStream:1.0";
  1340. private final static String[] _ids = { _id };
  1341. public String[] _truncatable_ids() {
  1342. if (_ids == null)
  1343. return null;
  1344. return (String[])_ids.clone();
  1345. }
  1346. /* for debugging */
  1347. public void printBuffer() {
  1348. CDROutputStream_1_0.printBuffer(this.bbwi);
  1349. }
  1350. public static void printBuffer(ByteBufferWithInfo bbwi) {
  1351. System.out.println("+++++++ Output Buffer ++++++++");
  1352. System.out.println();
  1353. System.out.println("Current position: " + bbwi.position());
  1354. System.out.println("Total length : " + bbwi.buflen);
  1355. System.out.println();
  1356. char[] charBuf = new char[16];
  1357. try {
  1358. for (int i = 0; i < bbwi.position(); i += 16) {
  1359. int j = 0;
  1360. // For every 16 bytes, there is one line
  1361. // of output. First, the hex output of
  1362. // the 16 bytes with each byte separated
  1363. // by a space.
  1364. while (j < 16 && j + i < bbwi.position()) {
  1365. int k = bbwi.byteBuffer.get(i + j);
  1366. if (k < 0)
  1367. k = 256 + k;
  1368. String hex = Integer.toHexString(k);
  1369. if (hex.length() == 1)
  1370. hex = "0" + hex;
  1371. System.out.print(hex + " ");
  1372. j++;
  1373. }
  1374. // Add any extra spaces to align the
  1375. // text column in case we didn't end
  1376. // at 16
  1377. while (j < 16) {
  1378. System.out.print(" ");
  1379. j++;
  1380. }
  1381. // Now output the ASCII equivalents. Non-ASCII
  1382. // characters are shown as periods.
  1383. int x = 0;
  1384. while (x < 16 && x + i < bbwi.position()) {
  1385. if (ORBUtility.isPrintable((char)bbwi.byteBuffer.get(i + x)))
  1386. charBuf[x] = (char)bbwi.byteBuffer.get(i + x);
  1387. else
  1388. charBuf[x] = '.';
  1389. x++;
  1390. }
  1391. System.out.println(new String(charBuf, 0, x));
  1392. }
  1393. } catch (Throwable t) {
  1394. t.printStackTrace();
  1395. }
  1396. System.out.println("++++++++++++++++++++++++++++++");
  1397. }
  1398. public void writeIndirection(int tag, int posIndirectedTo)
  1399. {
  1400. // Must ensure that there are no chunks between the tag
  1401. // and the actual indirection value. This isn't talked about
  1402. // in the spec, but seems to cause headaches in our code.
  1403. // At the very least, this method isolates the indirection code
  1404. // that was duplicated so often.
  1405. handleSpecialChunkBegin(computeAlignment(4) + 8);
  1406. // write indirection tag
  1407. write_long(tag);
  1408. // write indirection
  1409. // Use parent.getRealIndex() so that it can be overridden by TypeCodeOutputStreams
  1410. /*
  1411. System.out.println("CDROutputStream_1_0 writing indirection pos " + posIndirectedTo +
  1412. " - real index " + parent.getRealIndex(get_offset()) + " = " +
  1413. (posIndirectedTo - parent.getRealIndex(get_offset())));
  1414. */
  1415. write_long(posIndirectedTo - parent.getRealIndex(get_offset()));
  1416. handleSpecialChunkEnd();
  1417. }
  1418. protected CodeSetConversion.CTBConverter getCharConverter() {
  1419. if (charConverter == null)
  1420. charConverter = parent.createCharCTBConverter();
  1421. return charConverter;
  1422. }
  1423. protected CodeSetConversion.CTBConverter getWCharConverter() {
  1424. if (wcharConverter == null)
  1425. wcharConverter = parent.createWCharCTBConverter();
  1426. return wcharConverter;
  1427. }
  1428. protected void dprint(String msg) {
  1429. if (debug)
  1430. ORBUtility.dprint(this, msg);
  1431. }
  1432. void alignOnBoundary(int octetBoundary) {
  1433. alignAndReserve(octetBoundary, 0);
  1434. }
  1435. public void start_value(String rep_id) {
  1436. if (debug) {
  1437. dprint("start_value w/ rep id "
  1438. + rep_id
  1439. + " called at pos "
  1440. + get_offset()
  1441. + " position "
  1442. + bbwi.position());
  1443. }
  1444. if (inBlock)
  1445. end_block();
  1446. // Write value_tag
  1447. writeValueTag(true, false, null);
  1448. // Write rep. id
  1449. write_repositoryId(rep_id);
  1450. // Write Value chunk
  1451. end_flag--;
  1452. chunkedValueNestingLevel--;
  1453. // Make sure to chunk the custom data
  1454. start_block();
  1455. }
  1456. public void end_value() {
  1457. if (debug) {
  1458. dprint("end_value called at pos "
  1459. + get_offset()
  1460. + " position "
  1461. + bbwi.position());
  1462. }
  1463. end_block();
  1464. writeEndTag(true);
  1465. // Check to see if we need to start another block for a
  1466. // possible outer value. Since we're in the stream
  1467. // format 2 custom type contained by another custom
  1468. // type, mustChunk should always be true.
  1469. //
  1470. // Here's why we need to open a continuation chunk:
  1471. //
  1472. // We need to enclose the default data of the
  1473. // next subclass down in chunks. There won't be
  1474. // an end tag separating the superclass optional
  1475. // data and the subclass's default data.
  1476. if (debug) {
  1477. dprint("mustChunk is " + mustChunk);
  1478. }
  1479. if (mustChunk) {
  1480. start_block();
  1481. }
  1482. }
  1483. public void close() throws IOException
  1484. {
  1485. // tell BufferManagerWrite to release any ByteBuffers
  1486. getBufferManager().close();
  1487. // It's possible bbwi.byteBuffer is shared between
  1488. // this OutputStream and an InputStream. Thus, we check
  1489. // if the Input/Output streams are using the same ByteBuffer.
  1490. // If they sharing the same ByteBuffer we need to ensure only
  1491. // one of those ByteBuffers are released to the ByteBufferPool.
  1492. if (getByteBufferWithInfo() != null && getByteBuffer() != null)
  1493. {
  1494. int bbHash = System.identityHashCode(bbwi.byteBuffer);
  1495. MessageMediator messageMediator = parent.getMessageMediator();
  1496. if (messageMediator != null)
  1497. {
  1498. CDRInputObject inputObj =
  1499. (CDRInputObject)messageMediator.getInputObject();
  1500. if (inputObj != null)
  1501. {
  1502. ByteBuffer inputBb = inputObj.getByteBuffer();
  1503. int iBbHash = 0;
  1504. if (inputBb != null)
  1505. {
  1506. iBbHash = System.identityHashCode(inputBb);
  1507. if (bbHash == iBbHash) // shared?
  1508. {
  1509. // Set InputStream's ByteBuffer and bbwi to null
  1510. // so its ByteBuffer cannot be released to the pool
  1511. inputObj.setByteBuffer(null);
  1512. inputObj.setByteBufferWithInfo(null);
  1513. }
  1514. }
  1515. }
  1516. }
  1517. // release this stream's ByteBuffer to the pool
  1518. ByteBufferPool byteBufferPool = orb.getByteBufferPool();
  1519. if (debug)
  1520. {
  1521. // print address of ByteBuffer being released
  1522. int bbAddress = System.identityHashCode(bbwi.byteBuffer);
  1523. StringBuffer sb = new StringBuffer(80);
  1524. sb.append(".close - releasing ByteBuffer id (");
  1525. sb.append(bbAddress).append(") to ByteBufferPool.");
  1526. String msg = sb.toString();
  1527. dprint(msg);
  1528. }
  1529. byteBufferPool.releaseByteBuffer(getByteBuffer());
  1530. bbwi.byteBuffer = null;
  1531. bbwi = null;
  1532. }
  1533. }
  1534. }