Package org.apache.geronimo.corba.io

Source Code of org.apache.geronimo.corba.io.ValueWriter$IDArray

/**
*
* Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package org.apache.geronimo.corba.io;

import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import javax.rmi.CORBA.ValueHandler;

import org.omg.CORBA.CustomMarshal;
import org.omg.CORBA.portable.BoxedValueHelper;
import org.omg.CORBA.portable.StreamableValue;
import org.omg.CORBA.portable.ValueBase;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.geronimo.corba.channel.MarkHandler;
import org.apache.geronimo.corba.channel.OutputChannelMarker;


/**
* This class is not done.
*/
public class ValueWriter {

 
  static final Log log = LogFactory.getLog(ValueWriter.class);
 
    static final int TAG_VALUE = 0x7fffff00;

    static final int TAG_CODEBASE_PRESENT = 1;

    static final int TAG_SINGLE_ID_PRESENT = 2;

    static final int TAG_MULTI_ID_PRESENT = 6;

    static final int TAG_CHUNKED = 8;

    static String[] EMPTY_SARR = new String[0];

    private boolean isSet(int value, int bits) {
        return (value & bits) == bits;
    }

    private Map instanceTable = new IdentityHashMap();

    /**
     * indirection table for value headers �15.3.4.3
     */
    private Map valueInfoTable = new HashMap();

    private final OutputStreamBase out;

    private OutputChannelMarker chunkMark;

    private boolean currentValueIsChunked;

    private int chunkingLevel;

    private int startPosOfCurrentChunk;

    private int lastEndTagPos;

    private ValueHandler valueHandler;

    private int valueOfLastEndTag;

    public ValueWriter(OutputStreamBase out) {
        this.out = out;
    }

    static class IDArray implements Serializable {

        String[] ids;

        int hashCode;

        IDArray(String[] ids) {
            this.ids = ids;

            hashCode = 0;
            for (int i = 0; i < ids.length; i++)
                hashCode ^= ids[i].hashCode();
        }

        public int hashCode() {
            return hashCode;
        }

        public boolean equals(Object other) {

            if (!(other instanceof IDArray) || other == null)
                return false;

            return java.util.Arrays.equals(ids, ((IDArray) other).ids);
        }
    }

    public void writeValue(java.io.Serializable value, String repositoryID) {
        if (value == null) {
            out.write_long(0);
            return;
        }

        if (write_indirection(instanceTable, value)) {
            return;
        }

        boolean isStreamable = (value instanceof StreamableValue);
        boolean isCustom = (value instanceof CustomMarshal);

        if (!(isStreamable || isCustom)) {
            BoxedValueHelper helper = getHelper(value, null);
            if (helper == null) {
                writeRMIValue(value, repositoryID);
            } else {
                writeValue(value, helper);
            }
            return;
        }

        ValueBase base = (ValueBase) value;
        String[] ids = base._truncatable_ids();
        String valueID = ids[0];
        boolean isTruncatable = ids.length > 1;

        boolean sameType = false; // (valueID.equals (repositoryID));

        boolean isChunked = (isCustom | (isTruncatable & !sameType));

        int tag;

        if (!sameType || (chunkingLevel > 1 && isTruncatable)) {

            if (isTruncatable) {
                tag = TAG_VALUE | TAG_MULTI_ID_PRESENT;

            } else {
                tag = TAG_VALUE | TAG_SINGLE_ID_PRESENT;

                if (ids.length > 1) {
                    ids = new String[1];
                    ids[0] = valueID;
                }
            }
        } else {
            tag = TAG_VALUE;
            ids = EMPTY_SARR;
        }

        // System.out.println ("write_value (1) "+repositoryID);

        int pos = startValue(tag, ids, null, isChunked);
        instanceTable.put(value, new Integer(pos));

        if (isStreamable) {
            ((StreamableValue) value)._write(out);
        } else {
            ((CustomMarshal) value).marshal(out);
        }

        endValue();
    }

    private void writeRMIValue(java.io.Serializable value, String id) {

        if (value instanceof java.lang.String) {
            org.omg.CORBA.WStringValueHelper.write(out, (String) value);
            return;
        }

        if (valueHandler == null) {
            valueHandler = out.getValueHandler();
        }

        //
        // Needs writeReplace?
        //
        java.io.Serializable repValue = valueHandler.writeReplace(value);

        //
        // Repeat base checks if value was replaced
        //
        if (value != repValue) {
            if (repValue == null) {
                out.write_long(0);
                return;
            }

            if (write_indirection(instanceTable, repValue)) {
                return;
            }

            value = repValue;
        }

        //
        // Get the class object for the value
        //
        Class clz = value.getClass();

        //
        // 0x7fffff00 + SINGLE_ID
        //
        int tag = TAG_VALUE | TAG_SINGLE_ID_PRESENT;

        String codebase = javax.rmi.CORBA.Util.getCodebase(clz);
        if (codebase != null && codebase.length() != 0)
            tag |= TAG_CODEBASE_PRESENT;

        //
        // Determine the repository ID
        //
        String[] ids = new String[1];
        ids[0] = valueHandler.getRMIRepositoryID(clz);

        //
        // Determine if chunked encoding is needed
        //
        // TODO: this was always true in Trifork codebase, find out why!

        boolean isChunked = true || valueHandler.isCustomMarshaled(clz);

        // System.out.println ("write_value (2) "+ids[0]);

        int pos = startValue(tag, ids, codebase, isChunked);
        instanceTable.put(value, new Integer(pos));
        valueHandler.writeValue(out, value);
        endValue();
    }

    public void writeValue(Serializable value, BoxedValueHelper helper) {

        if (value == null) {
            out.write_long(0);
            return;
        }

        if (write_indirection(instanceTable, value)) {
            return;
        }

        if (helper == null) {
            helper = getHelper(value, null);
        }

        if (helper == null)
            throw new org.omg.CORBA.MARSHAL("Can't locate helper");

        String[] ids = new String[1];
        ids[0] = helper.get_id();
        int tag = TAG_VALUE | TAG_SINGLE_ID_PRESENT;

        // System.out.println ("write_value (3) "+ids[0]);

        int pos = startValue(tag, ids, null, false);
        instanceTable.put(value, new Integer(pos));
        helper.write_value(out, value);
        endValue();

    }

    private int startValue(int tag, String[] ids, String codebase,
                           boolean forceChunk)
    {

        currentValueIsChunked |= forceChunk;

        if (currentValueIsChunked) {
            tag |= TAG_CHUNKED;
            chunkingLevel += 1;

            //
            // Since chunks cannot be nested, we need to finish off
            // the previous chunk before we can start...
            //
            if ((chunkingLevel > 1) && (chunkMark != null))
                endChunk();

            // TODO: understand why we need to write a chunk end here.
            // the next thing written to the output stream is a value
            // tag, and that should be fine as an chunk-end-marker
        }

        out.write_long(tag);
        int startPos = out.__stream_position() - 4;

        if (isSet(tag, TAG_CODEBASE_PRESENT)) {
            write_value_metadata_string(codebase);
        }

        if (isSet(tag, TAG_MULTI_ID_PRESENT)) {

            IDArray idlist = new IDArray(ids);
            if (!write_indirection(valueInfoTable, idlist)) {
                out.align(4);
                valueInfoTable
                        .put(idlist, new Integer(out.__stream_position()));
                out.write_long(ids.length);

                for (int i = 0; i < ids.length; i++) {
                    write_value_metadata_string(ids[i]);
                }
            }

        } else if (isSet(tag, TAG_SINGLE_ID_PRESENT)) {

            write_value_metadata_string(ids[0]);
        }

        if (currentValueIsChunked) {

            //
            // start the next chunk as soon as anything is written
            // to the stream
            //
            lastEndTagPos = 0;

            startChunk();
        }

        return startPos;
    }

    void endValue() {

        if (!currentValueIsChunked)
            return;

        //
        // We need to make sure no chunks are started in the middle of
        // writing the end tag, and if we need to have a chunk here.
        //

        if (false && lastEndTagPos > 0 && out.__stream_position() == lastEndTagPos + 4) {

            // if we just terminated the previous value (which must
            // then have been nested inside the current value), then
            // we simply step back one and write the new end tag.

            valueOfLastEndTag++;

            //
            // TODO: figure a way to rewrite the last end-tag
            // TODO: revisit buf.pos = lastEndTagPos;

            if (log.isDebugEnabled()) {
                log.debug("rewriting endTag" + valueOfLastEndTag
                          + ", chunkingLevel=" + chunkingLevel);
            }

            out.write_long(valueOfLastEndTag);

        } else {

            // end the current chunk
            endChunk();

            //
            // Write the end tag and remember where it is
            //
            valueOfLastEndTag = -chunkingLevel;

            out.write_long(valueOfLastEndTag);
            if (chunkingLevel > 1)
                lastEndTagPos = out.__stream_position() - 4;
        }

        //
        // At the end of a chunked value, we must have ended the chunk
        // inside the value, i.e., right after a value we must never
        // be inside a chunk.
        //
        if (startPosOfCurrentChunk != 0)
            out.__fatal("startPosOfCurrentChunk is " + startPosOfCurrentChunk
                        + "; there should be no chunk here!");

        if (chunkingLevel == 1) {
            currentValueIsChunked = false;
            lastEndTagPos = 0;
            valueOfLastEndTag = 0;
        }

        chunkingLevel -= 1;
    }

    private void write_value_metadata_string(String string) {
        if (!write_indirection(valueInfoTable, string)) {
            out.align(4);
            valueInfoTable.put(string, new Integer(out.__stream_position()));
            out.write_string(string);
        }
    }

    MarkHandler chunkHandler = new MarkHandler() {
        public void bufferFull(OutputChannelMarker state) throws IOException {

            // end the chunk by writing the size at the start of the chunk.
            // endChunk will call state.release()
            endChunk();

            // start a new chunk here //
            // TODO: outer mark handler needs to be run first...
            startChunk();
        }
    };

       
    private void startChunk() {
        if (currentValueIsChunked == false)
            out.__fatal("not chunked");

        out.align(4);
        // TODO: revisit chunkMark = out.mark(chunkHandler);
        startPosOfCurrentChunk = out.__stream_position();
        chunkMark = out.mark(chunkHandler);
        out.write_long(0);
    }

    private void endChunk() {
        if (currentValueIsChunked == false)
            out.__fatal("not chunked");

        // compute chunk size
        int size = out.__stream_position() - startPosOfCurrentChunk;

        // TODO: align chunk size? That which follows a chunk must
        // be a 4-byte integer (chunk end marker) so we will do the
        // alignment...
        // TODO: revisit size += out.computeAlignment(size, 4);

        try {
            chunkMark.putInt(0, size);
        }
        catch (IOException e) {
            throw out.translate_exception(e);
        }

        chunkMark.release();
        chunkMark = null;
    }

    private boolean write_indirection(Map table, Serializable value) {
        Integer pos = (Integer) table.get(value);
        if (pos == null) {
            return false;
        }

        out.write_long(-1);
        int off = pos.intValue() - out.__stream_position();
        out.write_long(off);

        return true;
    }

    private BoxedValueHelper getHelper(Serializable value,
                                       String id)
    {
        /*
        Class helper = null;

        // TODO: Cache this info somewhere (contextclassloader)?

        try {
            String name = value.getClass().getName() + "Helper";
            Class c = Util.classForName(name);
            if (BoxedValueHelper.class.isAssignableFrom(c))
                helper = c;
        }
        catch (ClassNotFoundException ex) {
            // ignore //
        }

        if (helper == null && id != null) {
            try {
                String name = Util.idToClassName(id) + "Helper";
                helper = Util.classForName(name);
            }
            catch (ClassNotFoundException ex) {
                // ignore //
            }
        }

        if (helper != null) {
            try {
                return (BoxedValueHelper) helper.newInstance();
            }
            catch (ClassCastException ex) {
                // ignore //
            }
            catch (InstantiationException ex) {
                // ignore //
            }
            catch (IllegalAccessException ex) {
                // ignore //
            }
        }
        */
        return null;
    }

}
TOP

Related Classes of org.apache.geronimo.corba.io.ValueWriter$IDArray

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.