Package org.activemq.io.impl

Source Code of org.activemq.io.impl.DefaultWireFormat

/**
*
* Copyright 2004 Protique Ltd
*
* 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.activemq.io.impl;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.activemq.io.WireFormat;
import org.activemq.message.CachedValue;
import org.activemq.message.Packet;
import org.activemq.message.util.WireByteArrayInputStream;
import org.activemq.message.util.WireByteArrayOutputStream;

import EDU.oswego.cs.dl.util.concurrent.SynchronizedShort;

/**
* This is a stateful AbstractDefaultWireFormat which implements value caching.  Not optimial for use by
* many conncurrent threads.  One DefaultWireFormat is typically allocated per client connection. 
* @version $Revision: 1.1.1.1 $
*/
public class DefaultWireFormat extends AbstractDefaultWireFormat implements Serializable {

    private static final int MAX_CACHE_SIZE = Short.MAX_VALUE/2; //needs to be a lot less than Short.MAX_VALUE
    private static final Log log = LogFactory.getLog(DefaultWireFormat.class);
    static final short NULL_VALUE = -1;
    static final short CLEAR_CACHE = -2;
   
    //
    // Fields used during a write.
    //
    protected transient final Object writeMutex = new Object();
    protected transient WireByteArrayOutputStream internalBytesOut;
    protected transient DataOutputStream internalDataOut;
    protected transient WireByteArrayOutputStream cachedBytesOut;
    protected transient DataOutputStream cachedDataOut;
    private Map writeValueCache = new HashMap();
    protected transient SynchronizedShort cachedKeyGenerator;
   
    //
    // Fields used during a read.
    //
    protected transient final Object readMutex = new Object();
    protected transient WireByteArrayInputStream internalBytesIn;
    protected transient DataInputStream internalDataIn;
    private Map readValueCache = new HashMap();

   
    /**
     * Default Constructor
     */
    public DefaultWireFormat() {
        internalBytesOut = new WireByteArrayOutputStream();
        internalDataOut = new DataOutputStream(internalBytesOut);
        internalBytesIn = new WireByteArrayInputStream();
        internalDataIn = new DataInputStream(internalBytesIn);
        this.currentWireFormatVersion = WIRE_FORMAT_VERSION;
        this.cachedKeyGenerator = new SynchronizedShort((short) 0);
        this.cachedBytesOut = new WireByteArrayOutputStream();
        this.cachedDataOut = new DataOutputStream(cachedBytesOut);
    }   

    /**
     * @return new WireFormat
     */
    public WireFormat copy() {
        return new DefaultWireFormat();
    }
   
    private Object readResolve() throws ObjectStreamException {
        return new DefaultWireFormat();
    }
   
    public Packet writePacket(Packet packet, DataOutput dataOut) throws IOException {
        PacketWriter writer = getWriter(packet);
        if (writer != null) {
            synchronized (writeMutex) {
                internalBytesOut.reset();
                writer.writePacket(packet, internalDataOut);
                internalDataOut.flush();
                //reuse the byte buffer in the ByteArrayOutputStream
                byte[] data = internalBytesOut.getData();
                int count = internalBytesOut.size();
                dataOut.writeByte(packet.getPacketType());
                dataOut.writeInt(count);
                //byte[] data = internalBytesOut.toByteArray();
                //int count = data.length;
                //dataOut.writeInt(count);
                packet.setMemoryUsage(count);
                dataOut.write(data, 0, count);
            }
        }
        return null;
    }

    protected synchronized final Packet readPacket(DataInput dataIn, PacketReader reader) throws IOException {
        synchronized (readMutex) {
            Packet packet = reader.createPacket();
            int length = dataIn.readInt();
            packet.setMemoryUsage(length);
            byte[] data = new byte[length];
            dataIn.readFully(data);
            //then splat into the internal datainput
            internalBytesIn.restart(data);
            reader.buildPacket(packet, internalDataIn);
            return packet;
        }
    }
   
    /**
     * A helper method which converts a packet into a byte array Overrides the WireFormat to make use of the internal
     * BytesOutputStream
     *
     * @param packet
     * @return a byte array representing the packet using some wire protocol
     * @throws IOException
     */
    public byte[] toBytes(Packet packet) throws IOException {
        byte[] data = null;
        PacketWriter writer = getWriter(packet);

        if (writer != null) {
           
            synchronized (writeMutex) {
                internalBytesOut.reset();
                internalDataOut.writeByte(packet.getPacketType());
                internalDataOut.writeInt(-1);//the length
                writer.writePacket(packet, internalDataOut);
                internalDataOut.flush();
                data = internalBytesOut.toByteArray();
            }
           
            // lets subtract the header offset from the length
            int length = data.length - 5;
            packet.setMemoryUsage(length);
            //write in the length to the data
            data[1] = (byte) ((length >>> 24) & 0xFF);
            data[2] = (byte) ((length >>> 16) & 0xFF);
            data[3] = (byte) ((length >>> 8) & 0xFF);
            data[4] = (byte) ((length >>> 0) & 0xFF);
        }
       
        return data;
    }

    ///////////////////////////////////////////////////////////////
    //
    // Methods to handle cached values
    //
    ///////////////////////////////////////////////////////////////   
   
    public Object getValueFromReadCache(short key){
        return readValueCache.get(new Short(key));
    }
   
    protected short getWriteCachedKey(Object key) throws IOException{
        if (key != null){
            Short result = null;
            result = (Short)writeValueCache.get(key);
            if (result == null){
                result = new Short(cachedKeyGenerator.increment());
                writeValueCache.put(key,result);
                updateCachedValue(result.shortValue(),key);
            }
            return result.shortValue();
        }
        return DefaultWireFormat.NULL_VALUE;
    }
   
    protected void validateWriteCache() throws IOException {
        if (cachingEnabled) {
            if (writeValueCache.size() >= MAX_CACHE_SIZE) {
                writeValueCache.clear();
                cachedKeyGenerator.set((short) 0);
                updateCachedValue((short) -1, null);// send update to peer to
                                                    // clear the peer cache
            }
        }
    }
   
    protected void handleCachedValue(CachedValue cv) {
        if (cv != null) {
            if (cv.getId() == CLEAR_CACHE) {
                // clear the cache
                readValueCache.clear();
            } else if (cv.getId() != NULL_VALUE) {
                readValueCache.put(new Short(cv.getId()), cv.getValue());
            }
        }
    }   
   
    private synchronized void updateCachedValue(short key, Object value) throws IOException {
        if (cachedValueWriter == null) {
            cachedValueWriter = new CachedValueWriter();
        }
        CachedValue cv = new CachedValue();
        cv.setId(key);
        cv.setValue(value);
        cachedBytesOut.reset();
        cachedValueWriter.writePacket(cv, cachedDataOut);
        cachedDataOut.flush();
        byte[] data = cachedBytesOut.getData();
        int count = cachedBytesOut.size();
        getTransportDataOut().writeByte(cv.getPacketType());
        getTransportDataOut().writeInt(count);
        getTransportDataOut().write(data, 0, count);
    }
}
TOP

Related Classes of org.activemq.io.impl.DefaultWireFormat

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.