/**
*
* 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;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import javax.jms.JMSException;
import org.activemq.message.Packet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Represents a strategy of encoding packets on the wire or on disk using some kind of serialization or wire format.
* <p/>We use a default efficient format for Java to Java communication but other formats to other systems can be used,
* such as using simple text strings when talking to JavaScript or coming up with other formats for talking to C / C#
* languages or proprietary messaging systems we wish to interface with at the wire level etc.
*
* @version $Revision: 1.1.1.1 $
*/
public abstract class AbstractWireFormat implements WireFormat {
private static final Log log = LogFactory.getLog(AbstractWireFormat.class);
protected DataOutputStream transportDataOut;
protected DataInputStream transportDataIn;
protected boolean cachingEnabled;
/**
* Read a packet from a Datagram packet from the given channelID. If the packet is from the same channel ID as it
* was sent then we have a loop-back so discard the packet
*
* @param channelID is the unique channel ID
* @param dpacket
* @return the packet read from the datagram or null if it should be discarded
* @throws IOException
*/
public Packet readPacket(String channelID, DatagramPacket dpacket) throws IOException {
DataInput in = new DataInputStream(new ByteArrayInputStream(dpacket.getData(), dpacket.getOffset(), dpacket
.getLength()));
String id = in.readUTF();
if (channelID == null) {
log
.trace("We do not have a channelID which is probably caused by a synchronization issue, we're receiving messages before we're fully initialised");
}
else if (channelID.equals(id)) {
if (log.isTraceEnabled()) {
log.trace("Discarding packet from id: " + id);
}
return null;
}
int type = in.readByte();
Packet packet = readPacket(type, in);
// if (packet instanceof ActiveMQMessage) {
// System.out.println("##### read packet from channel: " + id + " in channel: " + channelID + " message: " +
// packet);
// }
//
return packet;
}
/**
* Writes the given package to a new datagram
*
* @param channelID is the unique channel ID
* @param packet is the packet to write
* @return @throws IOException
* @throws JMSException
*/
public DatagramPacket writePacket(String channelID, Packet packet) throws IOException, JMSException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataOutputStream dataOut = new DataOutputStream(out);
channelID = channelID != null ? channelID : "";
dataOut.writeUTF(channelID);
writePacket(packet, dataOut);
dataOut.close();
byte[] data = out.toByteArray();
return new DatagramPacket(data, data.length);
}
/**
* Reads the packet from the given byte[]
*
* @param bytes
* @param offset
* @param length
* @return @throws IOException
*/
public Packet fromBytes(byte[] bytes, int offset, int length) throws IOException {
DataInput in = new DataInputStream(new ByteArrayInputStream(bytes, offset, length));
return readPacket(in);
}
/**
* Reads the packet from the given byte[]
*
* @param bytes
* @return @throws IOException
*/
public Packet fromBytes(byte[] bytes) throws IOException {
DataInput in = new DataInputStream(new ByteArrayInputStream(bytes));
return readPacket(in);
}
/**
* A helper method which converts a packet into a byte array
*
* @param packet
* @return a byte array representing the packet using some wire protocol
* @throws IOException
* @throws JMSException
*/
public byte[] toBytes(Packet packet) throws IOException, JMSException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataOutputStream dataOut = new DataOutputStream(out);
writePacket(packet, dataOut);
dataOut.close();
return out.toByteArray();
}
/**
* some transports may register their streams (e.g. Tcp)
*
* @param dataOut
* @param dataIn
*/
public void registerTransportStreams(DataOutputStream dataOut, DataInputStream dataIn) {
transportDataOut = dataOut;
transportDataIn = dataIn;
}
/**
* Some wire formats require a handshake at start-up
*
* @throws IOException
*/
public void initiateClientSideProtocol() throws IOException {
}
/**
* Some wire formats require a handshake at start-up
*
* @throws IOException
*/
public void initiateServerSideProtocol() throws IOException {
}
/**
* @return Returns the enableCaching.
*/
public boolean isCachingEnabled() {
return cachingEnabled;
}
/**
* @param enableCaching The enableCaching to set.
*/
public void setCachingEnabled(boolean enableCaching) {
this.cachingEnabled = enableCaching;
}
/**
* some wire formats will implement their own fragementation
* @return true unless a wire format supports it's own fragmentation
*/
public boolean doesSupportMessageFragmentation(){
return true;
}
/**
* Some wire formats will not be able to understand compressed messages
* @return true unless a wire format cannot understand compression
*/
public boolean doesSupportMessageCompression(){
return true;
}
/**
* @return Returns the transportDataOut.
*/
public DataOutputStream getTransportDataOut() {
return transportDataOut;
}
/**
* @param transportDataOut The transportDataOut to set.
*/
public void setTransportDataOut(DataOutputStream transportDataOut) {
this.transportDataOut = transportDataOut;
}
/**
* @return Returns the transportDataIn.
*/
public DataInputStream getTransportDataIn() {
return transportDataIn;
}
/**
* @param transportDataIn The transportDataIn to set.
*/
public void setTransportDataIn(DataInputStream transportDataIn) {
this.transportDataIn = transportDataIn;
}
/**
* @param dataIn
* @return
* @throws java.io.IOException
*/
public Packet readPacket(DataInput dataIn) throws IOException {
int type = -1;
while ((type = dataIn.readByte()) == 0);
if (type == -1){
throw new IOException("InputStream now closed");
}
return readPacket(type, dataIn);
}
}