DatagramFactory.java :  » JMS » UberMQ » com » ubermq » jms » common » datagram » impl » Java Open Source

Java Open Source » JMS » UberMQ 
UberMQ » com » ubermq » jms » common » datagram » impl » DatagramFactory.java
package com.ubermq.jms.common.datagram.impl;


import com.ubermq.jms.common.datagram.*;
import com.ubermq.kernel.*;
import java.io.*;
import java.nio.*;
import org.apache.log4j.*;

/**
 * The standard UberMQ datagram protocol handler, aka DatagramFactory. This
 * class also implements message and control datagram creation as well as protocol
 * handling.
 *
 * <PRE>
 * UBERMQ DATAGRAM HEADER:
 * ------
 * SOH = 0xea   1 byte      1 in 255 chance this is a real datagram.
 * ------
 * size         4 bytes     the size of the data in addition to header data.
 * ------
 * </PRE>
 *
 * followed by <code>size - 5</code> bytes of datagram specific data.
 *
 */
public class DatagramFactory
    implements IDatagramFactory,
    IMessageDatagramFactory,
    IControlDatagramFactory,
    IAckDatagramFactory,
    java.io.Serializable
{
    private static final Logger log = Logger.getLogger(DatagramFactory.class);
    public static final long serialVersionUID = 1L;

    public final static byte UBERMQ_START_OF_HEADER = (byte)0xea;
    public final static int UBERMQ_HEADER_LENGTH = 6;
    public static final int UBERMQ_TYPE_POSITION = 5;

    public static final int DGRAM_CONTROL = 1;
    public static final int DGRAM_ACK = 2;
    public static final int DGRAM_MSG = 3;

    private static final DatagramFactory theInstance;
    private static final DatagramFactoryHolder theHolder;

    static {
        theInstance = new DatagramFactory();
        theHolder = new DatagramFactoryHolder(theInstance);
    }

    /**
     * singleton pattern. this is a stateless object.
     */
    DatagramFactory() {}
    private Object readResolve() {return theInstance;}

    /**
     * Gets the instance of the UberMQ datagram factory.
     * @return a datagram factory instance.
     */
    public static DatagramFactory getInstance() {return theInstance;}

    /**
     * Gets a datagram factory holder representing the factory singleton.
     * @return a factory holder
     */
    public static DatagramFactoryHolder getHolder() {return theHolder;}

    public int frame(ByteBuffer bb)
        throws IOException
    {
        if (bb.remaining() < UBERMQ_HEADER_LENGTH)
            return UBERMQ_HEADER_LENGTH;

        int boundary = bb.position();
        try {
            if (bb.get() == UBERMQ_START_OF_HEADER) {
                return UBERMQ_HEADER_LENGTH + bb.getInt();
            } else {
                bb.position(boundary);
                log.debug(com.ubermq.util.Utility.displayBuffer(bb));
                throw new IOException("packet header byte not detected");
            }
        } finally {
            bb.position(boundary);
        }
    }

    public IDatagram incoming(ByteBuffer bb)
        throws IllegalArgumentException
    {
        // get the type byte.
        bb.position(UBERMQ_TYPE_POSITION);
        int datagramType = bb.get();

        // move past all header data
        bb.position(UBERMQ_HEADER_LENGTH);

        // read the datagram.
        try {
            IDatagram d = createDatagramInstance(datagramType);
            d.incoming(bb);
            return d;
        }
        catch(IllegalArgumentException iae) {throw iae;}
        catch(Exception io) {throw new IllegalArgumentException(io.toString());}
    }

    IDatagram createDatagramInstance(int type)
    {
        switch(type)
        {
            case DGRAM_ACK:
                return new AckDatagram();
            case DGRAM_CONTROL:
                return new ControlDatagram();
            case DGRAM_MSG:
                return new MessageDatagram();
            default:
                return null;
        }
    }

    public void outgoing(ByteBuffer bb, IDatagram d)
    {
        // output the UBER start byte,
        // then a zero placeholder for the size,
        // then the datagram type (this implementation only uses
        // the low order byte)
        bb.put(UBERMQ_START_OF_HEADER);
        bb.putInt(0);
        bb.put((byte)(0xFF & d.getDatagramType()));

        // write the datagram out
        d.outgoing(bb);

        // update the length byte
        int position = bb.position();
        bb.position(1);
        bb.putInt(position - UBERMQ_HEADER_LENGTH);
        bb.position(position);
    }

    ///// IControlDatagramFactory methods

    /**
     * Creates or resurrects a durable subscription, with the given name and
     * topic specification.
     */
    public IControlDatagram durableSubscribe(String durable, String topic)
    {
        return durableSubscribe(durable, topic, null);
    }

    /**
     * Creates or resurrects a durable subscription, with the given name,
     * topic specification and selector.
     */
    public IControlDatagram durableSubscribe(String durable, String topic, String selector)
    {
        return new ControlDatagram(ControlDatagram.CONTROL_DURABLE_SUB,
                                   new ControlDatagram.DurableSubscribeDatagramImpl(durable, topic, selector));
    }

    /**
     * Indicates that the durable subscription is switching to disconnected mode.
     */
    public IControlDatagram durableGoingAway(String durable)
    {
        return new ControlDatagram(ControlDatagram.CONTROL_DURABLE_GOING_AWAY,
                                   new ControlDatagram.DurableGoingAwayDatagramImpl(durable));
    }

    /**
     * Recovers a durable subscription, resending all unacknowledged messages.
     */
    public IControlDatagram durableRecover(String durable)
    {
        return new ControlDatagram(ControlDatagram.CONTROL_DURABLE_RECOVER,
                                   new ControlDatagram.DurableRecoverDatagramImpl(durable));
    }

    /**
     * Permanently removes the named durable subscription.
     */
    public IControlDatagram durableUnsubscribe(String durable)
    {
        return new ControlDatagram(ControlDatagram.CONTROL_DURABLE_UNSUB,
                                   new ControlDatagram.DurableUnSubDatagramImpl(durable));
    }

    /**
     * Subscribes to the given topic specification. The topic specification
     * is not defined here; it is only meaningful to the recipient.
     */
    public IControlDatagram subscribe(String topic)
    {
        return subscribe(topic, null);
    }

    /**
     * Subscribes to the given topic specification and message selector.
     * Both are interpreted by the peer.
     *
     */
    public IControlDatagram subscribe(String topic, String selector)
    {
        return new ControlDatagram(ControlDatagram.CONTROL_SUB,
                                   new ControlDatagram.SubscribeDatagramImpl(topic, selector));
    }

    /**
     * Unsubscribe from the topic specification given. The same specification
     * should have been given in a prior subscribe() call.
     */
    public IControlDatagram unsubscribe(String topic)
    {
        return new ControlDatagram(ControlDatagram.CONTROL_UNSUB,
                                   new ControlDatagram.UnsubscribeDatagramImpl(topic));
    }

    /**
     * Informs the peer that this connection should be considered as a
     * clustering propagation connection, and any messages emerging from it
     * should be interpreted as repeated.
     */
    public IControlDatagram cluster()
    {
        return new ControlDatagram(ControlDatagram.CONTROL_CLUSTER,
                                   new ControlDatagram.ClusterDatagramImpl());
    }

    /**
     * Gives the peer the unique identifier of this clustering connection.
     */
    public IControlDatagram clusterPeer(String peerId)
    {
        return new ControlDatagram(ControlDatagram.CONTROL_CLUSTER_PEER_ID,
                                   new ControlDatagram.ClusterPeerDatagramImpl(peerId));
    }

    /**
     * Asks the connection peer to begin sending messages.
     */
    public IControlDatagram start()
    {
        return new ControlDatagram(ControlDatagram.CONTROL_START,
                                   new ControlDatagram.StartDatagramImpl());
    }

    /**
     * Asks the connection peer to stop sending messages.
     */
    public IControlDatagram stop()
    {
        return new ControlDatagram(ControlDatagram.CONTROL_STOP,
                                   new ControlDatagram.StopDatagramImpl());
    }

    /**
     * The null operation. This can be used for connection keep alive.
     */
    public IControlDatagram noop()
    {
        return new ControlDatagram(ControlDatagram.CONTROL_NOOP,
                                   new ControlDatagram.NoopDatagramImpl());
    }

    /**
     * Starts receiving messages from the named queue, with
     * the specified message selector (or null for none).
     * @param queue the name of the queue
     * @param selector a message selector, or null to allow all messages.
     * @return a control datagram
     */
    public IControlDatagram queueStart(String queue, String selector)
    {
        return new ControlDatagram(ControlDatagram.CONTROL_QUEUE_START,
                                   new ControlDatagram.QueueStartDatagramImpl(queue, selector));
    }

    /**
     * Stops receiving messages from the named queue.
     * @param queue the name of the queue
     * @return a control datagram
     */
    public IControlDatagram queueStop(String queue)
    {
        return new ControlDatagram(ControlDatagram.CONTROL_QUEUE_STOP,
                                   new ControlDatagram.QueueStopDatagramImpl(queue));
    }

    /**
     * Deletes a queue.
     * @param queue the name of the queue.
     */
    public IControlDatagram queueDelete(String queue)
    {
        return new ControlDatagram(ControlDatagram.CONTROL_QUEUE_DELETE,
                                   new ControlDatagram.QueueDeleteDatagramImpl(queue));
    }

    /**
     * Creates an acknowledgement datagram for a message. The acknowledgement
     * may be positive or negative.
     * @param id the message identifier
     * @param nack true if the Ack is negative, false otherwise
     */
    public IAckDatagram ack(MessageId id, boolean nack)
    {
        return new AckDatagram(id, nack);
    }

    /**
     * Creates an acknowledgement datagram that is unrelated to a message.
     * @param nack true if the Ack is negative, false otherwise
     */
    public IAckDatagram ack(boolean nack)
    {
        return new AckDatagram(nack);
    }

    /////// MessageFactory

    public IMessageDatagram createMessage()
    {
        return new MessageDatagram();
    }

    public IMessageDatagram createMessage(String topic)
    {
        return new MessageDatagram(topic);
    }

    /////// Ack Factory

    /**
     * Creates a negative acknowledgement (NACK) datagram in reference
     * to the specified message identifier.
     * @param id a message identifier
     */
    public IAckDatagram nack(MessageId id)
    {
        return new AckDatagram(id, true);
    }

    /**
     * Creates an acknowledgement datagram for the given message identifier.
     * This creates a positive ack.
     * @param id a message identifier
     */
    public IAckDatagram ack(MessageId id)
    {
        return new AckDatagram(id, false);
    }

    /**
     * Creates an acknowledgement datagram with no contextual information.
     * This creates a positive ack.
     */
    public IAckDatagram ack()
    {
        return new AckDatagram(false);
    }

    /**
     * Creates a negative acknowledgement (NACK) datagram
     * with no contextual information.
     */
    public IAckDatagram nack()
    {
        return new AckDatagram(true);
    }


}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.