1. /*
  2. * @(#)IDLJavaSerializationOutputStream.java 1.4 04/06/07
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.corba.se.impl.encoding;
  8. import java.io.IOException;
  9. import java.io.ObjectOutputStream;
  10. import java.io.ByteArrayOutputStream;
  11. import java.nio.ByteBuffer;
  12. import com.sun.corba.se.spi.orb.ORB;
  13. import com.sun.corba.se.spi.ior.IOR;
  14. import com.sun.corba.se.spi.ior.IORFactories;
  15. import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
  16. import com.sun.corba.se.spi.logging.CORBALogDomains;
  17. import com.sun.corba.se.spi.presentation.rmi.StubAdapter;
  18. import com.sun.corba.se.impl.util.Utility;
  19. import com.sun.corba.se.impl.orbutil.ORBConstants;
  20. import com.sun.corba.se.impl.orbutil.ORBUtility;
  21. import com.sun.corba.se.impl.corba.TypeCodeImpl;
  22. import com.sun.corba.se.impl.logging.ORBUtilSystemException;
  23. import com.sun.corba.se.impl.protocol.giopmsgheaders.Message;
  24. import org.omg.CORBA.Any;
  25. import org.omg.CORBA.TypeCode;
  26. import org.omg.CORBA.Principal;
  27. import org.omg.CORBA.CompletionStatus;
  28. /**
  29. * Implementation class that uses Java serialization for output streams.
  30. * This assumes a GIOP version 1.2 message format.
  31. *
  32. * This class uses a ByteArrayOutputStream as the underlying buffer. The
  33. * first 16 bytes are direct writes into the underlying buffer. This allows
  34. * [GIOPHeader (12 bytes) + requestID (4 bytes)] to be written as bytes.
  35. * Subsequent write operations on this output stream object uses
  36. * ObjectOutputStream class to write into the buffer. This allows marshaling
  37. * complex types and graphs using the ObjectOutputStream implementation.
  38. *
  39. * Note, this class assumes a GIOP 1.2 style header. Note, we expect that the
  40. * first 16 bytes are written only using the write_octet, write_long or
  41. * write_ulong method calls.
  42. *
  43. * @author Ram Jeyaraman
  44. */
  45. public class IDLJavaSerializationOutputStream extends CDROutputStreamBase {
  46. private ORB orb;
  47. private byte encodingVersion;
  48. private ObjectOutputStream os;
  49. private _ByteArrayOutputStream bos;
  50. private BufferManagerWrite bufferManager;
  51. // [GIOPHeader(12) + requestID(4)] bytes
  52. private final int directWriteLength = Message.GIOPMessageHeaderLength + 4;
  53. protected ORBUtilSystemException wrapper;
  54. class _ByteArrayOutputStream extends ByteArrayOutputStream {
  55. _ByteArrayOutputStream(int initialSize) {
  56. super(initialSize);
  57. }
  58. byte[] getByteArray() {
  59. return this.buf;
  60. }
  61. }
  62. class MarshalObjectOutputStream extends ObjectOutputStream {
  63. ORB orb;
  64. MarshalObjectOutputStream(java.io.OutputStream out, ORB orb)
  65. throws IOException {
  66. super(out);
  67. this.orb = orb;
  68. java.security.AccessController.doPrivileged(
  69. new java.security.PrivilegedAction() {
  70. public Object run() {
  71. // needs SerializablePermission("enableSubstitution")
  72. enableReplaceObject(true);
  73. return null;
  74. }
  75. }
  76. );
  77. }
  78. /**
  79. * Checks for objects that are instances of java.rmi.Remote
  80. * that need to be serialized as proxy (Stub) objects.
  81. */
  82. protected final Object replaceObject(Object obj) throws IOException {
  83. try {
  84. if ((obj instanceof java.rmi.Remote) &&
  85. !(StubAdapter.isStub(obj))) {
  86. return Utility.autoConnect(obj, orb, true);
  87. }
  88. } catch (Exception e) {
  89. IOException ie = new IOException("replaceObject failed");
  90. ie.initCause(e);
  91. throw ie;
  92. }
  93. return obj;
  94. }
  95. }
  96. public IDLJavaSerializationOutputStream(byte encodingVersion) {
  97. super();
  98. this.encodingVersion = encodingVersion;
  99. }
  100. public void init(org.omg.CORBA.ORB orb, boolean littleEndian,
  101. BufferManagerWrite bufferManager,
  102. byte streamFormatVersion,
  103. boolean usePooledByteBuffers) {
  104. this.orb = (ORB) orb;
  105. this.bufferManager = bufferManager;
  106. wrapper = ORBUtilSystemException.get((ORB) orb,
  107. CORBALogDomains.RPC_ENCODING);
  108. bos =
  109. new _ByteArrayOutputStream(ORBConstants.GIOP_DEFAULT_BUFFER_SIZE);
  110. }
  111. // Called from read_octet or read_long or read_ulong method.
  112. private void initObjectOutputStream() {
  113. //System.out.print(" os ");
  114. if (os != null) {
  115. throw wrapper.javaStreamInitFailed();
  116. }
  117. try {
  118. os = new MarshalObjectOutputStream(bos, orb);
  119. } catch (Exception e) {
  120. throw wrapper.javaStreamInitFailed(e);
  121. }
  122. }
  123. // org.omg.CORBA.portable.OutputStream
  124. // Primitive types.
  125. public final void write_boolean(boolean value) {
  126. try {
  127. os.writeBoolean(value);
  128. } catch (Exception e) {
  129. throw wrapper.javaSerializationException(e, "write_boolean");
  130. }
  131. }
  132. public final void write_char(char value) {
  133. try {
  134. os.writeChar(value);
  135. } catch (Exception e) {
  136. throw wrapper.javaSerializationException(e, "write_char");
  137. }
  138. }
  139. public final void write_wchar(char value) {
  140. this.write_char(value);
  141. }
  142. public final void write_octet(byte value) {
  143. // check if size < [ GIOPHeader(12) + requestID(4)] bytes
  144. if (bos.size() < directWriteLength) {
  145. bos.write(value); // direct write.
  146. if (bos.size() == directWriteLength) {
  147. initObjectOutputStream();
  148. }
  149. return;
  150. }
  151. try {
  152. os.writeByte(value);
  153. } catch (Exception e) {
  154. throw wrapper.javaSerializationException(e, "write_octet");
  155. }
  156. }
  157. public final void write_short(short value) {
  158. try {
  159. os.writeShort(value);
  160. } catch (Exception e) {
  161. throw wrapper.javaSerializationException(e, "write_short");
  162. }
  163. }
  164. public final void write_ushort(short value) {
  165. this.write_short(value);
  166. }
  167. public final void write_long(int value) {
  168. // check if size < [ GIOPHeader(12) + requestID(4)] bytes
  169. if (bos.size() < directWriteLength) {
  170. // Use big endian (network byte order). This is fixed.
  171. // Both the writer and reader use the same byte order.
  172. bos.write((byte)((value >>> 24) & 0xFF));
  173. bos.write((byte)((value >>> 16) & 0xFF));
  174. bos.write((byte)((value >>> 8) & 0xFF));
  175. bos.write((byte)((value >>> 0) & 0xFF));
  176. if (bos.size() == directWriteLength) {
  177. initObjectOutputStream();
  178. } else if (bos.size() > directWriteLength) {
  179. // Cannot happen. All direct writes are contained
  180. // within the first 16 bytes.
  181. wrapper.javaSerializationException("write_long");
  182. }
  183. return;
  184. }
  185. try {
  186. os.writeInt(value);
  187. } catch (Exception e) {
  188. throw wrapper.javaSerializationException(e, "write_long");
  189. }
  190. }
  191. public final void write_ulong(int value) {
  192. this.write_long(value);
  193. }
  194. public final void write_longlong(long value) {
  195. try {
  196. os.writeLong(value);
  197. } catch (Exception e) {
  198. throw wrapper.javaSerializationException(e, "write_longlong");
  199. }
  200. }
  201. public final void write_ulonglong(long value) {
  202. this.write_longlong(value);
  203. }
  204. public final void write_float(float value) {
  205. try {
  206. os.writeFloat(value);
  207. } catch (Exception e) {
  208. throw wrapper.javaSerializationException(e, "write_float");
  209. }
  210. }
  211. public final void write_double(double value) {
  212. try {
  213. os.writeDouble(value);
  214. } catch (Exception e) {
  215. throw wrapper.javaSerializationException(e, "write_double");
  216. }
  217. }
  218. // String types.
  219. public final void write_string(String value) {
  220. try {
  221. os.writeUTF(value);
  222. } catch (Exception e) {
  223. throw wrapper.javaSerializationException(e, "write_string");
  224. }
  225. }
  226. public final void write_wstring(String value) {
  227. try {
  228. os.writeObject(value);
  229. } catch (Exception e) {
  230. throw wrapper.javaSerializationException(e, "write_wstring");
  231. }
  232. }
  233. // Array types.
  234. public final void write_boolean_array(boolean[] value,
  235. int offset, int length) {
  236. for (int i = 0; i < length; i++) {
  237. write_boolean(value[offset + i]);
  238. }
  239. }
  240. public final void write_char_array(char[] value, int offset, int length) {
  241. for (int i = 0; i < length; i++) {
  242. write_char(value[offset + i]);
  243. }
  244. }
  245. public final void write_wchar_array(char[] value, int offset, int length) {
  246. write_char_array(value, offset, length);
  247. }
  248. public final void write_octet_array(byte[] value, int offset, int length) {
  249. try {
  250. os.write(value, offset, length);
  251. } catch (Exception e) {
  252. throw wrapper.javaSerializationException(e, "write_octet_array");
  253. }
  254. }
  255. public final void write_short_array(short[] value,
  256. int offset, int length) {
  257. for (int i = 0; i < length; i++) {
  258. write_short(value[offset + i]);
  259. }
  260. }
  261. public final void write_ushort_array(short[] value,
  262. int offset, int length){
  263. write_short_array(value, offset, length);
  264. }
  265. public final void write_long_array(int[] value, int offset, int length) {
  266. for (int i = 0; i < length; i++) {
  267. write_long(value[offset + i]);
  268. }
  269. }
  270. public final void write_ulong_array(int[] value, int offset, int length) {
  271. write_long_array(value, offset, length);
  272. }
  273. public final void write_longlong_array(long[] value,
  274. int offset, int length) {
  275. for (int i = 0; i < length; i++) {
  276. write_longlong(value[offset + i]);
  277. }
  278. }
  279. public final void write_ulonglong_array(long[] value,
  280. int offset,int length) {
  281. write_longlong_array(value, offset, length);
  282. }
  283. public final void write_float_array(float[] value,
  284. int offset, int length) {
  285. for (int i = 0; i < length; i++) {
  286. write_float(value[offset + i]);
  287. }
  288. }
  289. public final void write_double_array(double[] value,
  290. int offset, int length) {
  291. for (int i = 0; i < length; i++) {
  292. write_double(value[offset + i]);
  293. }
  294. }
  295. // Complex types (objects and graphs).
  296. public final void write_Object(org.omg.CORBA.Object value) {
  297. if (value == null) {
  298. IOR nullIOR = IORFactories.makeIOR(orb);
  299. nullIOR.write(parent);
  300. return;
  301. }
  302. // IDL to Java formal 01-06-06 1.21.4.2
  303. if (value instanceof org.omg.CORBA.LocalObject) {
  304. throw wrapper.writeLocalObject(CompletionStatus.COMPLETED_MAYBE);
  305. }
  306. IOR ior = ORBUtility.connectAndGetIOR(orb, value);
  307. ior.write(parent);
  308. return;
  309. }
  310. public final void write_TypeCode(TypeCode tc) {
  311. if (tc == null) {
  312. throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
  313. }
  314. TypeCodeImpl tci;
  315. if (tc instanceof TypeCodeImpl) {
  316. tci = (TypeCodeImpl) tc;
  317. } else {
  318. tci = new TypeCodeImpl(orb, tc);
  319. }
  320. tci.write_value((org.omg.CORBA_2_3.portable.OutputStream) parent);
  321. }
  322. public final void write_any(Any any) {
  323. if (any == null) {
  324. throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
  325. }
  326. write_TypeCode(any.type());
  327. any.write_value(parent);
  328. }
  329. public final void write_Principal(Principal p) {
  330. // We don't need an implementation for this method, since principal
  331. // is absent in GIOP version 1.2 or above.
  332. write_long(p.name().length);
  333. write_octet_array(p.name(), 0, p.name().length);
  334. }
  335. public final void write_fixed(java.math.BigDecimal bigDecimal) {
  336. // This string might contain sign and/or dot
  337. this.write_fixed(bigDecimal.toString(), bigDecimal.signum());
  338. }
  339. // The string may contain a sign and dot
  340. private void write_fixed(String string, int signum) {
  341. int stringLength = string.length();
  342. // Each octet contains (up to) two decimal digits.
  343. byte doubleDigit = 0;
  344. char ch;
  345. byte digit;
  346. // First calculate the string length without optional sign and dot.
  347. int numDigits = 0;
  348. for (int i=0; i<stringLength; i++) {
  349. ch = string.charAt(i);
  350. if (ch == '-' || ch == '+' || ch == '.')
  351. continue;
  352. numDigits++;
  353. }
  354. for (int i=0; i<stringLength; i++) {
  355. ch = string.charAt(i);
  356. if (ch == '-' || ch == '+' || ch == '.')
  357. continue;
  358. digit = (byte)Character.digit(ch, 10);
  359. if (digit == -1) {
  360. throw wrapper.badDigitInFixed(
  361. CompletionStatus.COMPLETED_MAYBE);
  362. }
  363. // If the fixed type has an odd number of decimal digits, then the
  364. // representation begins with the first (most significant) digit.
  365. // Otherwise, this first half-octet is all zero, and the first
  366. // digit is in the second half-octet.
  367. if (numDigits % 2 == 0) {
  368. doubleDigit |= digit;
  369. this.write_octet(doubleDigit);
  370. doubleDigit = 0;
  371. } else {
  372. doubleDigit |= (digit << 4);
  373. }
  374. numDigits--;
  375. }
  376. // The sign configuration in the last half-octet of the representation,
  377. // is 0xD for negative numbers and 0xC for positive and zero values.
  378. if (signum == -1) {
  379. doubleDigit |= 0xd;
  380. } else {
  381. doubleDigit |= 0xc;
  382. }
  383. this.write_octet(doubleDigit);
  384. }
  385. public final org.omg.CORBA.ORB orb() {
  386. return this.orb;
  387. }
  388. // org.omg.CORBA_2_3.portable.OutputStream
  389. public final void write_value(java.io.Serializable value) {
  390. write_value(value, (String) null);
  391. }
  392. public final void write_value(java.io.Serializable value,
  393. java.lang.Class clz) {
  394. write_value(value);
  395. }
  396. public final void write_value(java.io.Serializable value,
  397. String repository_id) {
  398. try {
  399. os.writeObject(value);
  400. } catch (Exception e) {
  401. throw wrapper.javaSerializationException(e, "write_value");
  402. }
  403. }
  404. public final void write_value(java.io.Serializable value,
  405. org.omg.CORBA.portable.BoxedValueHelper factory) {
  406. this.write_value(value, (String) null);
  407. }
  408. public final void write_abstract_interface(java.lang.Object obj) {
  409. boolean isCorbaObject = false; // Assume value type.
  410. org.omg.CORBA.Object theCorbaObject = null;
  411. // Is it a CORBA.Object?
  412. if (obj != null && obj instanceof org.omg.CORBA.Object) {
  413. theCorbaObject = (org.omg.CORBA.Object)obj;
  414. isCorbaObject = true;
  415. }
  416. // Write the boolean flag.
  417. this.write_boolean(isCorbaObject);
  418. // Now write out the object.
  419. if (isCorbaObject) {
  420. write_Object(theCorbaObject);
  421. } else {
  422. try {
  423. write_value((java.io.Serializable)obj);
  424. } catch(ClassCastException cce) {
  425. if (obj instanceof java.io.Serializable) {
  426. throw cce;
  427. } else {
  428. ORBUtility.throwNotSerializableForCorba(
  429. obj.getClass().getName());
  430. }
  431. }
  432. }
  433. }
  434. // com.sun.corba.se.os.encoding.MarshalOutputStream
  435. public final void start_block() {
  436. throw wrapper.giopVersionError();
  437. }
  438. public final void end_block() {
  439. throw wrapper.giopVersionError();
  440. }
  441. public final void putEndian() {
  442. throw wrapper.giopVersionError();
  443. }
  444. public void writeTo(java.io.OutputStream s) throws IOException {
  445. try {
  446. os.flush();
  447. bos.writeTo(s);
  448. } catch (Exception e) {
  449. throw wrapper.javaSerializationException(e, "writeTo");
  450. }
  451. }
  452. public final byte[] toByteArray() {
  453. try {
  454. os.flush();
  455. return bos.toByteArray(); // new copy.
  456. } catch (Exception e) {
  457. throw wrapper.javaSerializationException(e, "toByteArray");
  458. }
  459. }
  460. // org.omg.CORBA.DataOutputStream
  461. public final void write_Abstract (java.lang.Object value) {
  462. write_abstract_interface(value);
  463. }
  464. public final void write_Value(java.io.Serializable value) {
  465. write_value(value);
  466. }
  467. public final void write_any_array(org.omg.CORBA.Any[] value,
  468. int offset, int length) {
  469. for(int i = 0; i < length; i++) {
  470. write_any(value[offset + i]);
  471. }
  472. }
  473. // org.omg.CORBA.portable.ValueBase
  474. public final String[] _truncatable_ids() {
  475. throw wrapper.giopVersionError();
  476. }
  477. // Other.
  478. public final int getSize() {
  479. try {
  480. os.flush();
  481. return bos.size();
  482. } catch (Exception e) {
  483. throw wrapper.javaSerializationException(e, "write_boolean");
  484. }
  485. }
  486. public final int getIndex() {
  487. return getSize();
  488. }
  489. protected int getRealIndex(int index) {
  490. return getSize();
  491. }
  492. public final void setIndex(int value) {
  493. throw wrapper.giopVersionError();
  494. }
  495. public final ByteBuffer getByteBuffer() {
  496. throw wrapper.giopVersionError();
  497. }
  498. public final void setByteBuffer(ByteBuffer byteBuffer) {
  499. throw wrapper.giopVersionError();
  500. }
  501. public final boolean isLittleEndian() {
  502. // Java serialization uses network byte order, that is, big-endian.
  503. return false;
  504. }
  505. public ByteBufferWithInfo getByteBufferWithInfo() {
  506. try {
  507. os.flush();
  508. } catch (Exception e) {
  509. throw wrapper.javaSerializationException(
  510. e, "getByteBufferWithInfo");
  511. }
  512. ByteBuffer byteBuffer = ByteBuffer.wrap(bos.getByteArray());
  513. byteBuffer.limit(bos.size());
  514. return new ByteBufferWithInfo(this.orb, byteBuffer, bos.size());
  515. }
  516. public void setByteBufferWithInfo(ByteBufferWithInfo bbwi) {
  517. throw wrapper.giopVersionError();
  518. }
  519. public final BufferManagerWrite getBufferManager() {
  520. return bufferManager;
  521. }
  522. // This will stay a custom add-on until the java-rtf issue is resolved.
  523. // Then it should be declared in org.omg.CORBA.portable.OutputStream.
  524. //
  525. // Pads the string representation of bigDecimal with zeros to fit the given
  526. // digits and scale before it gets written to the stream.
  527. public final void write_fixed(java.math.BigDecimal bigDecimal,
  528. short digits, short scale) {
  529. String string = bigDecimal.toString();
  530. String integerPart;
  531. String fractionPart;
  532. StringBuffer stringBuffer;
  533. // Get rid of the sign
  534. if (string.charAt(0) == '-' || string.charAt(0) == '+') {
  535. string = string.substring(1);
  536. }
  537. // Determine integer and fraction parts
  538. int dotIndex = string.indexOf('.');
  539. if (dotIndex == -1) {
  540. integerPart = string;
  541. fractionPart = null;
  542. } else if (dotIndex == 0 ) {
  543. integerPart = null;
  544. fractionPart = string;
  545. } else {
  546. integerPart = string.substring(0, dotIndex);
  547. fractionPart = string.substring(dotIndex + 1);
  548. }
  549. // Pad both parts with zeros as necessary
  550. stringBuffer = new StringBuffer(digits);
  551. if (fractionPart != null) {
  552. stringBuffer.append(fractionPart);
  553. }
  554. while (stringBuffer.length() < scale) {
  555. stringBuffer.append('0');
  556. }
  557. if (integerPart != null) {
  558. stringBuffer.insert(0, integerPart);
  559. }
  560. while (stringBuffer.length() < digits) {
  561. stringBuffer.insert(0, '0');
  562. }
  563. // This string contains no sign or dot
  564. this.write_fixed(stringBuffer.toString(), bigDecimal.signum());
  565. }
  566. public final void writeOctetSequenceTo(
  567. org.omg.CORBA.portable.OutputStream s) {
  568. byte[] buf = this.toByteArray(); // new copy.
  569. s.write_long(buf.length);
  570. s.write_octet_array(buf, 0, buf.length);
  571. }
  572. public final GIOPVersion getGIOPVersion() {
  573. return GIOPVersion.V1_2;
  574. }
  575. public final void writeIndirection(int tag, int posIndirectedTo) {
  576. throw wrapper.giopVersionError();
  577. }
  578. void freeInternalCaches() {}
  579. void printBuffer() {
  580. byte[] buf = this.toByteArray();
  581. System.out.println("+++++++ Output Buffer ++++++++");
  582. System.out.println();
  583. System.out.println("Current position: " + buf.length);
  584. //System.out.println("Total length : " + buf.length);
  585. System.out.println();
  586. char[] charBuf = new char[16];
  587. try {
  588. for (int i = 0; i < buf.length; i += 16) {
  589. int j = 0;
  590. // For every 16 bytes, there is one line
  591. // of output. First, the hex output of
  592. // the 16 bytes with each byte separated
  593. // by a space.
  594. while (j < 16 && j + i < buf.length) {
  595. int k = buf[i + j];
  596. if (k < 0)
  597. k = 256 + k;
  598. String hex = Integer.toHexString(k);
  599. if (hex.length() == 1)
  600. hex = "0" + hex;
  601. System.out.print(hex + " ");
  602. j++;
  603. }
  604. // Add any extra spaces to align the
  605. // text column in case we didn't end
  606. // at 16
  607. while (j < 16) {
  608. System.out.print(" ");
  609. j++;
  610. }
  611. // Now output the ASCII equivalents. Non-ASCII
  612. // characters are shown as periods.
  613. int x = 0;
  614. while (x < 16 && x + i < buf.length) {
  615. if (ORBUtility.isPrintable((char)buf[i + x])) {
  616. charBuf[x] = (char) buf[i + x];
  617. } else {
  618. charBuf[x] = '.';
  619. }
  620. x++;
  621. }
  622. System.out.println(new String(charBuf, 0, x));
  623. }
  624. } catch (Throwable t) {
  625. t.printStackTrace();
  626. }
  627. System.out.println("++++++++++++++++++++++++++++++");
  628. }
  629. public void alignOnBoundary(int octetBoundary) {
  630. throw wrapper.giopVersionError();
  631. }
  632. // Needed by request and reply messages for GIOP versions >= 1.2 only.
  633. public void setHeaderPadding(boolean headerPadding) {
  634. // no-op. We don't care about body alignment while using
  635. // Java serialization. What the GIOP spec states does not apply here.
  636. }
  637. // ValueOutputStream -----------------------------
  638. public void start_value(String rep_id) {
  639. throw wrapper.giopVersionError();
  640. }
  641. public void end_value() {
  642. throw wrapper.giopVersionError();
  643. }
  644. // java.io.OutputStream
  645. // Note: These methods are defined in the super class and accessible.
  646. //public abstract void write(byte b[]) throws IOException;
  647. //public abstract void write(byte b[], int off, int len)
  648. // throws IOException;
  649. //public abstract void flush() throws IOException;
  650. //public abstract void close() throws IOException;
  651. }