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