cdroutputstream_1_2.java

来自「JAVA 所有包」· Java 代码 · 共 342 行

JAVA
342
字号
/* * @(#)CDROutputStream_1_2.java	1.13 05/11/17 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */package com.sun.corba.se.impl.encoding;import org.omg.CORBA.BAD_PARAM;import org.omg.CORBA.INTERNAL;import org.omg.CORBA.CompletionStatus;import com.sun.corba.se.spi.ior.iiop.GIOPVersion;import com.sun.corba.se.impl.encoding.CodeSetConversion;import com.sun.corba.se.impl.orbutil.ORBConstants;public class CDROutputStream_1_2 extends CDROutputStream_1_1{    // There's a situation with chunking with fragmentation    // in which the alignment for a primitive value is needed    // to fill fragment N, but the primitive won't fit so    // must go into fragment N + 1.  The behavior is the same    // as that for specialChunks.    //    // Unfortunately, given the current code, we can't reuse    // specialChunk.  If you wrap each of the following    // write calls with handleSpecialChunkBegin/End, you    // will lose your state because the primitive calls will    // change the variables, etc.    //    // All of the CDR code should be rewritten moving chunking    // to a different level, perhaps in the buffer managers.    // We want to move to a compositional model rather than    // using inheritance.    //    // Note that in the grow case, chunks are _NOT_ closed    // at grow points, now.    //    // **** NOTE ****    // Since we will not support valuetypes with GIOP 1.1, that    // also means we do not support chunking there.    //    protected boolean primitiveAcrossFragmentedChunk = false;    // Used in chunking.  Here's how this works:    //    // When chunking and writing an array of primitives, a string, or a     // wstring, _AND_ it won't fit in the buffer do the following.  (As    // you can see, this is a very "special" chunk.)    //    //     1.  Write the length of the chunk including the array length    //     2.  Set specialChunk to true    // 3 applies to ALL chunking:    //     3.  In grow, if we need to fragment and specialChunk is false    //               a) call end_block    //               b) fragment    // Now back to the array only case:    //     [write the data]    //     4.  if specialChunk is true     //               a) Close the chunk    //               b) Set specialChunk to false    protected boolean specialChunk = false;    // Indicates whether the header should be padded. In GIOP 1.2 and above, the    // body must be aligned on a 8-octet boundary, and so the header needs to be    // padded appropriately. However, if there is no body to a request or reply    // message, there is no need to pad the header, in the unfragmented case.    private boolean headerPadding;        protected void handleSpecialChunkBegin(int requiredSize)    {        // If we're chunking and the item won't fit in the buffer        if (inBlock && requiredSize + bbwi.position() > bbwi.buflen) {            // Duplicating some code from end_block.  Compute            // and write the total chunk length.            int oldSize = bbwi.position();            bbwi.position(blockSizeIndex - 4);            //write_long(oldSize - blockSizeIndex);            writeLongWithoutAlign((oldSize - blockSizeIndex) + requiredSize);            bbwi.position(oldSize);                // Set the special flag so we don't end the chunk when            // we fragment            specialChunk = true;        }    }    protected void handleSpecialChunkEnd()    {        // If we're in a chunk and the item spanned fragments        if (inBlock && specialChunk) {            // This is unnecessary, but I just want to show that            // we're done with the current chunk.  (the end_block            // call is inappropriate here)            inBlock = false;            blockSizeIndex = -1;            blockSizePosition = -1;                        // Start a new chunk since we fragmented during the item.            // Thus, no one can go back to add more to the chunk length            start_block();            // Now turn off the flag so we go back to the normal            // behavior of closing a chunk when we fragment and            // reopening afterwards.            specialChunk = false;        }    }        // Called after writing primitives    private void checkPrimitiveAcrossFragmentedChunk()    {        if (primitiveAcrossFragmentedChunk) {            primitiveAcrossFragmentedChunk = false;            inBlock = false;            // It would be nice to have a StreamPosition            // abstraction if we could avoid allocation            // overhead.            blockSizeIndex = -1;            blockSizePosition = -1;            // Start a new chunk            start_block();        }            }    public void write_octet(byte x) {        super.write_octet(x);        checkPrimitiveAcrossFragmentedChunk();    }    public void write_short(short x) {        super.write_short(x);        checkPrimitiveAcrossFragmentedChunk();    }    public void write_long(int x) {        super.write_long(x);        checkPrimitiveAcrossFragmentedChunk();    }    public void write_longlong(long x) {        super.write_longlong(x);        checkPrimitiveAcrossFragmentedChunk();    }    // Called by RequestMessage_1_2 or ReplyMessage_1_2 classes only.    void setHeaderPadding(boolean headerPadding) {        this.headerPadding = headerPadding;    }    protected void alignAndReserve(int align, int n) {        // headerPadding bit is set by the write operation of RequestMessage_1_2        // or ReplyMessage_1_2 classes. When set, the very first body write        // operation (from the stub code) would trigger an alignAndReserve         // method call, that would in turn add the appropriate header padding,        // such that the body is aligned on a 8-octet boundary. The padding        // is required for GIOP versions 1.2 and above, only if body is present.        if (headerPadding == true) {            headerPadding = false;            alignOnBoundary(ORBConstants.GIOP_12_MSG_BODY_ALIGNMENT);        }                // In GIOP 1.2, we always end fragments at our        // fragment size, which is an "evenly divisible        // 8 byte boundary" (aka divisible by 16).  A fragment can         // end with appropriate alignment padding, but no padding        // is needed with respect to the next GIOP fragment        // header since it ends on an 8 byte boundary.        bbwi.position(bbwi.position() + computeAlignment(align));        if (bbwi.position() + n  > bbwi.buflen)            grow(align, n);    }    protected void grow(int align, int n) {                // Save the current size for possible post-fragmentation calculation        int oldSize = bbwi.position();        // See notes where specialChunk is defined, as well as the        // above notes for primitiveAcrossFragmentedChunk.        //        // If we're writing a primitive and chunking, we need to update        // the chunk length to include the length of the primitive (unless        // this complexity is handled by specialChunk).        //        // Note that this is wasted processing in the grow case, but that        // we don't actually close the chunk in that case.        boolean handleChunk = (inBlock && !specialChunk);        if (handleChunk) {            int oldIndex = bbwi.position();            bbwi.position(blockSizeIndex - 4);            writeLongWithoutAlign((oldIndex - blockSizeIndex) + n);            bbwi.position(oldIndex);        }        bbwi.needed = n;        bufferManagerWrite.overflow(bbwi);        // At this point, if we fragmented, we should have a ByteBufferWithInfo        // with the fragment header already marshalled.  The buflen and position        // should be updated accordingly, and the fragmented flag should be set.        // Note that fragmented is only true in the streaming and collect cases.        if (bbwi.fragmented) {            // Clear the flag            bbwi.fragmented = false;            // Update fragmentOffset so indirections work properly.            // At this point, oldSize is the entire length of the            // previous buffer.  bbwi.position() is the length of the            // fragment header of this buffer.            fragmentOffset += (oldSize - bbwi.position());            // We just fragmented, and need to signal that we should            // start a new chunk after writing the primitive.            if (handleChunk)                primitiveAcrossFragmentedChunk = true;                    }    }    public GIOPVersion getGIOPVersion() {        return GIOPVersion.V1_2;    }    public void write_wchar(char x)    {        // In GIOP 1.2, a wchar is encoded as an unsigned octet length        // followed by the octets of the converted wchar.  This is good,        // but it causes problems with our chunking code.  We don't        // want that octet to get put in a different chunk at the end        // of the previous fragment.          //        // Ensure that this won't happen by overriding write_wchar_array        // and doing our own handleSpecialChunkBegin/End here.        CodeSetConversion.CTBConverter converter = getWCharConverter();        converter.convert(x);        handleSpecialChunkBegin(1 + converter.getNumBytes());        write_octet((byte)converter.getNumBytes());        byte[] result = converter.getBytes();        // Write the bytes without messing with chunking        // See CDROutputStream_1_0        internalWriteOctetArray(result, 0, converter.getNumBytes());        handleSpecialChunkEnd();    }    public void write_wchar_array(char[] value, int offset, int length)    {        if (value == null) {	    throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);        }           CodeSetConversion.CTBConverter converter = getWCharConverter();        // Unfortunately, because of chunking, we have to convert the        // entire char[] to a byte[] array first so we can know how        // many bytes we're writing ahead of time.  You can't split        // an array of primitives into multiple chunks.        int totalNumBytes = 0;        // Remember that every wchar starts with an octet telling        // its length.  The buffer size is an upper bound estimate.        int maxLength = (int)Math.ceil(converter.getMaxBytesPerChar() * length);        byte[] buffer = new byte[maxLength + length];        for (int i = 0; i < length; i++) {            // Convert one wchar            converter.convert(value[offset + i]);            // Make sure to add the octet length            buffer[totalNumBytes++] = (byte)converter.getNumBytes();            // Copy it into our buffer            System.arraycopy(converter.getBytes(), 0,                             buffer, totalNumBytes,                             converter.getNumBytes());            totalNumBytes += converter.getNumBytes();        }        // Now that we know the total length, we can deal with chunking.        // Note that we don't have to worry about alignment since they're        // just octets.        handleSpecialChunkBegin(totalNumBytes);        // Must use totalNumBytes rather than buffer.length since the        // buffer.length is only the upper bound estimate.        internalWriteOctetArray(buffer, 0, totalNumBytes);        handleSpecialChunkEnd();    }        public void write_wstring(String value) {        if (value == null) {	    throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);        }        // In GIOP 1.2, wstrings are not terminated by a null.  The        // length is the number of octets in the converted format.        // A zero length string is represented with the 4 byte length        // value of 0.        if (value.length() == 0) {            write_long(0);            return;        }        CodeSetConversion.CTBConverter converter = getWCharConverter();        converter.convert(value);        handleSpecialChunkBegin(computeAlignment(4) + 4 + converter.getNumBytes());        write_long(converter.getNumBytes());        // Write the octet array without tampering with chunking        internalWriteOctetArray(converter.getBytes(), 0, converter.getNumBytes());        handleSpecialChunkEnd();    }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?