/**
*
* 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.codehaus.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.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.activemq.io.AbstractWireFormat;
import org.codehaus.activemq.io.WireFormat;
import org.codehaus.activemq.message.AbstractPacket;
import org.codehaus.activemq.message.Packet;
import org.codehaus.activemq.message.util.WireByteArrayInputStream;
import org.codehaus.activemq.message.util.WireByteArrayOutputStream;
/**
* Default implementation used for Java-Java protocols. When talking to non-Java nodes we may use a different wire
* format.
*
* @version $Revision: 1.3 $
*/
public class DefaultWireFormat extends AbstractWireFormat implements Serializable {
/**
* Current wire format version for this implementation
*/
public static final int WIRE_FORMAT_VERSION = 2;
private static final Log log = LogFactory.getLog(DefaultWireFormat.class);
private transient PacketReader messageReader;
private transient PacketReader textMessageReader;
private transient PacketReader objectMessageReader;
private transient PacketReader bytesMessageReader;
private transient PacketReader streamMessageReader;
private transient PacketReader mapMessageReader;
private transient PacketReader messageAckReader;
private transient PacketReader receiptReader;
private transient PacketReader consumerInfoReader;
private transient PacketReader producerInfoReader;
private transient PacketReader transactionInfoReader;
private transient PacketReader xaTransactionInfoReader;
private transient PacketReader brokerInfoReader;
private transient PacketReader connectionInfoReader;
private transient PacketReader sessionInfoReader;
private transient PacketReader durableUnsubscribeReader;
private transient PacketReader reponseReceiptReader;
private transient PacketReader intReponseReceiptReader;
private transient PacketReader capacityInfoReader;
private transient PacketReader capacityInfoRequestReader;
private transient PacketReader wireFormatInfoReader;
private transient PacketReader keepAliveReader;
private transient PacketWriter messageWriter;
private transient PacketWriter textMessageWriter;
private transient PacketWriter objectMessageWriter;
private transient PacketWriter bytesMessageWriter;
private transient PacketWriter streamMessageWriter;
private transient PacketWriter mapMessageWriter;
private transient PacketWriter messageAckWriter;
private transient PacketWriter receiptWriter;
private transient PacketWriter consumerInfoWriter;
private transient PacketWriter producerInfoWriter;
private transient PacketWriter transactionInfoWriter;
private transient PacketWriter xaTransactionInfoWriter;
private transient PacketWriter brokerInfoWriter;
private transient PacketWriter connectionInfoWriter;
private transient PacketWriter sessionInfoWriter;
private transient PacketWriter durableUnsubscribeWriter;
private transient PacketWriter reponseReceiptWriter;
private transient PacketWriter intReponseReceiptWriter;
private transient PacketWriter capacityInfoWriter;
private transient PacketWriter capacityInfoRequestWriter;
private transient PacketWriter wireFormatInfoWriter;
private transient PacketWriter keepAliveWriter;
private transient WireByteArrayOutputStream internalBytesOut;
private transient DataOutputStream internalDataOut;
private transient WireByteArrayInputStream internalBytesIn;
private transient DataInputStream internalDataIn;
private transient int currentWireFormatVersion;
private List readers = new ArrayList();
private List writers = new ArrayList();
/**
* Default Constructor
*/
public DefaultWireFormat() {
internalBytesOut = new WireByteArrayOutputStream();
internalDataOut = new DataOutputStream(internalBytesOut);
internalBytesIn = new WireByteArrayInputStream();
internalDataIn = new DataInputStream(internalBytesIn);
this.currentWireFormatVersion = WIRE_FORMAT_VERSION;
initializeReaders();
initializeWriters();
}
/**
* @return new WireFormat
*/
public WireFormat copy() {
return new DefaultWireFormat();
}
/**
* @param in
* @return
* @throws IOException
*/
public Packet readPacket(DataInput in) throws IOException {
int type = in.readByte();
return readPacket(type, in);
}
/**
* @param firstByte
* @param dataIn
* @return
* @throws IOException
*
*/
public Packet readPacket(int firstByte, DataInput dataIn) throws IOException {
switch (firstByte) {
case Packet.ACTIVEMQ_MESSAGE :
return readPacket(dataIn, messageReader);
case Packet.ACTIVEMQ_TEXT_MESSAGE :
return readPacket(dataIn, textMessageReader);
case Packet.ACTIVEMQ_OBJECT_MESSAGE :
return readPacket(dataIn, objectMessageReader);
case Packet.ACTIVEMQ_BYTES_MESSAGE :
return readPacket(dataIn, bytesMessageReader);
case Packet.ACTIVEMQ_STREAM_MESSAGE :
return readPacket(dataIn, streamMessageReader);
case Packet.ACTIVEMQ_MAP_MESSAGE :
return readPacket(dataIn, mapMessageReader);
case Packet.ACTIVEMQ_MSG_ACK :
return readPacket(dataIn, messageAckReader);
case Packet.RECEIPT_INFO :
return readPacket(dataIn, receiptReader);
case Packet.CONSUMER_INFO :
return readPacket(dataIn, consumerInfoReader);
case Packet.PRODUCER_INFO :
return readPacket(dataIn, producerInfoReader);
case Packet.TRANSACTION_INFO :
return readPacket(dataIn, transactionInfoReader);
case Packet.XA_TRANSACTION_INFO :
return readPacket(dataIn, xaTransactionInfoReader);
case Packet.ACTIVEMQ_BROKER_INFO :
return readPacket(dataIn, brokerInfoReader);
case Packet.ACTIVEMQ_CONNECTION_INFO :
return readPacket(dataIn, connectionInfoReader);
case Packet.SESSION_INFO :
return readPacket(dataIn, sessionInfoReader);
case Packet.DURABLE_UNSUBSCRIBE :
return readPacket(dataIn, durableUnsubscribeReader);
case Packet.RESPONSE_RECEIPT_INFO :
return readPacket(dataIn, reponseReceiptReader);
case Packet.INT_RESPONSE_RECEIPT_INFO :
return readPacket(dataIn, intReponseReceiptReader);
case Packet.CAPACITY_INFO :
return readPacket(dataIn, capacityInfoReader);
case Packet.CAPACITY_INFO_REQUEST :
return readPacket(dataIn, capacityInfoRequestReader);
case Packet.WIRE_FORMAT_INFO :
return readPacket(dataIn, wireFormatInfoReader);
case Packet.KEEP_ALIVE :
return readPacket(dataIn, keepAliveReader);
default :
log.error("Could not find PacketReader for packet type: "
+ AbstractPacket.getPacketTypeAsString(firstByte));
return null;
}
}
/**
* Write a Packet to a DataOutput
*
* @param packet
* @param dataOut
* @throws IOException
*/
public void writePacket(Packet packet, DataOutput dataOut) throws IOException {
PacketWriter writer = getWriter(packet);
if (writer != null) {
writePacket(packet, dataOut, writer);
}
}
/**
* 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) {
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;
}
/**
* Can this wireformat process packets of this version
* @param version the version number to test
* @return true if can accept the version
*/
public boolean canProcessWireFormatVersion(int version){
return version <= WIRE_FORMAT_VERSION;
}
/**
* @return the current version of this wire format
*/
public int getCurrentWireFormatVersion(){
return currentWireFormatVersion;
}
/**
* set the current version
* @param version
*/
public void setCurrentWireFormatVersion(int version){
this.currentWireFormatVersion = version;
for (int i =0; i < readers.size(); i++){
PacketReader reader = (PacketReader)readers.get(i);
reader.setWireFormatVersion(version);
}
for (int i =0; i < writers.size(); i++){
PacketWriter writer = (PacketWriter)writers.get(i);
writer.setWireFormatVersion(version);
}
}
protected synchronized final void writePacket(Packet packet, DataOutput dataOut, PacketWriter writer)
throws IOException {
dataOut.writeByte(packet.getPacketType());
internalBytesOut.reset();
writer.writePacket(packet, internalDataOut);
internalDataOut.flush();
//reuse the byte buffer in the ByteArrayOutputStream
byte[] data = internalBytesOut.getData();
int count = internalBytesOut.size();
dataOut.writeInt(count);
//byte[] data = internalBytesOut.toByteArray();
//int count = data.length;
//dataOut.writeInt(count);
packet.setMemoryUsage(count);
dataOut.write(data, 0, count);
}
protected synchronized final Packet readPacket(DataInput dataIn, PacketReader reader) throws IOException {
Packet packet = reader.createPacket();
int length = dataIn.readInt();
packet.setMemoryUsage(length);
// read all the remaining data in one chunk ignoring the header
// TODO sometimes the length should exclude the header?
byte[] data = new byte[length];
dataIn.readFully(data);
//then splat into the internal datainput
internalBytesIn.restart(data);
reader.buildPacket(packet, internalDataIn);
return packet;
}
private Object readResolve() throws ObjectStreamException {
return new DefaultWireFormat();
}
private PacketWriter getWriter(Packet packet) throws IOException {
PacketWriter answer = null;
switch (packet.getPacketType()) {
case Packet.ACTIVEMQ_MESSAGE :
answer = messageWriter;
break;
case Packet.ACTIVEMQ_TEXT_MESSAGE :
answer = textMessageWriter;
break;
case Packet.ACTIVEMQ_OBJECT_MESSAGE :
answer = objectMessageWriter;
break;
case Packet.ACTIVEMQ_BYTES_MESSAGE :
answer = bytesMessageWriter;
break;
case Packet.ACTIVEMQ_STREAM_MESSAGE :
answer = streamMessageWriter;
break;
case Packet.ACTIVEMQ_MAP_MESSAGE :
answer = mapMessageWriter;
break;
case Packet.ACTIVEMQ_MSG_ACK :
answer = messageAckWriter;
break;
case Packet.RECEIPT_INFO :
answer = receiptWriter;
break;
case Packet.CONSUMER_INFO :
answer = consumerInfoWriter;
break;
case Packet.PRODUCER_INFO :
answer = producerInfoWriter;
break;
case Packet.TRANSACTION_INFO :
answer = transactionInfoWriter;
break;
case Packet.XA_TRANSACTION_INFO :
answer = xaTransactionInfoWriter;
break;
case Packet.ACTIVEMQ_BROKER_INFO :
answer = brokerInfoWriter;
break;
case Packet.ACTIVEMQ_CONNECTION_INFO :
answer = connectionInfoWriter;
break;
case Packet.SESSION_INFO :
answer = sessionInfoWriter;
break;
case Packet.DURABLE_UNSUBSCRIBE :
answer = durableUnsubscribeWriter;
break;
case Packet.RESPONSE_RECEIPT_INFO :
answer = reponseReceiptWriter;
break;
case Packet.INT_RESPONSE_RECEIPT_INFO :
answer = intReponseReceiptWriter;
break;
case Packet.CAPACITY_INFO :
answer = capacityInfoWriter;
break;
case Packet.CAPACITY_INFO_REQUEST :
answer = capacityInfoRequestWriter;
break;
case Packet.WIRE_FORMAT_INFO :
answer = wireFormatInfoWriter;
break;
case Packet.KEEP_ALIVE :
answer = keepAliveWriter;
break;
default :
log.error("no PacketWriter for packet: " + packet);
}
return answer;
}
private void initializeReaders() {
messageReader = new ActiveMQMessageReader();
readers.add(messageReader);
textMessageReader = new ActiveMQTextMessageReader();
readers.add(textMessageReader);
objectMessageReader = new ActiveMQObjectMessageReader();
readers.add(objectMessageReader);
bytesMessageReader = new ActiveMQBytesMessageReader();
readers.add(bytesMessageReader);
streamMessageReader = new ActiveMQStreamMessageReader();
readers.add(streamMessageReader);
mapMessageReader = new ActiveMQMapMessageReader();
readers.add(mapMessageReader);
messageAckReader = new MessageAckReader();
readers.add(messageAckReader);
receiptReader = new ReceiptReader();
readers.add(receiptReader);
consumerInfoReader = new ConsumerInfoReader();
readers.add(consumerInfoReader);
producerInfoReader = new ProducerInfoReader();
readers.add(producerInfoReader);
transactionInfoReader = new TransactionInfoReader();
readers.add(transactionInfoReader);
xaTransactionInfoReader = new XATransactionInfoReader();
readers.add(xaTransactionInfoReader);
brokerInfoReader = new BrokerInfoReader();
readers.add(brokerInfoReader);
connectionInfoReader = new ConnectionInfoReader();
readers.add(connectionInfoReader);
sessionInfoReader = new SessionInfoReader();
readers.add(sessionInfoReader);
durableUnsubscribeReader = new DurableUnsubscribeReader();
readers.add(durableUnsubscribeReader);
reponseReceiptReader = new ResponseReceiptReader();
readers.add(reponseReceiptReader);
intReponseReceiptReader = new IntResponseReceiptReader();
readers.add(intReponseReceiptReader);
capacityInfoReader = new CapacityInfoReader();
readers.add(capacityInfoReader);
capacityInfoRequestReader = new CapacityInfoRequestReader();
readers.add(capacityInfoReader);
wireFormatInfoReader = new WireFormatInfoReader(this);
readers.add(wireFormatInfoReader);
keepAliveReader = new KeepAliveReader();
readers.add(keepAliveReader);
}
private void initializeWriters(){
messageWriter = new ActiveMQMessageWriter();
writers.add(messageWriter);
textMessageWriter = new ActiveMQTextMessageWriter();
writers.add(textMessageWriter);
objectMessageWriter = new ActiveMQObjectMessageWriter();
writers.add(objectMessageWriter);
bytesMessageWriter = new ActiveMQBytesMessageWriter();
writers.add(bytesMessageWriter);
streamMessageWriter = new ActiveMQStreamMessageWriter();
writers.add(streamMessageWriter);
mapMessageWriter = new ActiveMQMapMessageWriter();
writers.add(mapMessageWriter);
messageAckWriter = new MessageAckWriter();
writers.add(messageAckWriter);
receiptWriter = new ReceiptWriter();
writers.add(receiptWriter);
consumerInfoWriter = new ConsumerInfoWriter();
writers.add(consumerInfoWriter);
producerInfoWriter = new ProducerInfoWriter();
writers.add(producerInfoWriter);
transactionInfoWriter = new TransactionInfoWriter();
writers.add(transactionInfoWriter);
xaTransactionInfoWriter = new XATransactionInfoWriter();
writers.add(xaTransactionInfoWriter);
brokerInfoWriter = new BrokerInfoWriter();
writers.add(brokerInfoWriter);
connectionInfoWriter = new ConnectionInfoWriter();
writers.add(connectionInfoWriter);
sessionInfoWriter = new SessionInfoWriter();
writers.add(sessionInfoWriter);
durableUnsubscribeWriter = new DurableUnsubscribeWriter();
writers.add(durableUnsubscribeWriter);
reponseReceiptWriter = new ResponseReceiptWriter();
writers.add(reponseReceiptWriter);
intReponseReceiptWriter = new IntResponseReceiptWriter();
writers.add(intReponseReceiptWriter);
capacityInfoWriter = new CapacityInfoWriter();
writers.add(capacityInfoWriter);
capacityInfoRequestWriter = new CapacityInfoRequestWriter();
writers.add(capacityInfoWriter);
wireFormatInfoWriter = new WireFormatInfoWriter();
writers.add(wireFormatInfoWriter);
keepAliveWriter = new KeepAliveWriter();
writers.add(keepAliveWriter);
}
}