org.codehaus.stomp.jms.StompSession.java Source code

Java tutorial

Introduction

Here is the source code for org.codehaus.stomp.jms.StompSession.java

Source

/**
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.stomp.jms;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.jms.BytesMessage;
import javax.jms.Connection;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.stomp.ProtocolException;
import org.codehaus.stomp.Stomp;
import org.codehaus.stomp.StompFrame;

/**
 * Represents a logical session (a parallel unit of work) within a Stomp connection
  *
 * @version $Revision: 61 $
 */
public class StompSession {
    private final ProtocolConverter protocolConverter;
    private final Session session;
    private MessageProducer producer;
    private static Map<String, Destination> temporaryDestinations = new HashMap<String, Destination>();
    private final Map<String, StompSubscription> subscriptions = new ConcurrentHashMap<String, StompSubscription>();
    private List<String> created = new ArrayList<String>();
    private Connection connection;
    private InitialContext initialContext;
    private static final Log log = LogFactory.getLog(StompSession.class);

    public StompSession(InitialContext initialContext, ProtocolConverter protocolConverter, Session session,
            Connection connection) throws JMSException {
        this.initialContext = initialContext;
        this.protocolConverter = protocolConverter;
        this.session = session;
        this.connection = connection;
        this.producer = session.createProducer(null);
    }

    public ProtocolConverter getProtocolConverter() {
        return protocolConverter;
    }

    public void close() throws JMSException {
        Iterator<StompSubscription> iterator = subscriptions.values().iterator();
        try {
            while (iterator.hasNext()) {
                iterator.next().close();
            }
        } finally {
            subscriptions.clear();
            connection.close();
        }
    }

    public void sendToJms(StompFrame command)
            throws JMSException, ProtocolException, NamingException, UnsupportedEncodingException {
        Map headers = command.getHeaders();
        String destinationName = (String) headers.remove(Stomp.Headers.Send.DESTINATION);
        Message message = convertFrame(command);
        Destination destination = convertDestination(destinationName, false);

        int deliveryMode = getDeliveryMode(headers);
        int priority = getPriority(headers);
        long timeToLive = getTimeToLive(headers);

        producer.send(destination, message, deliveryMode, priority, timeToLive);
        log.debug("Sent to HQ: " + message.getJMSMessageID());
    }

    public void sendToStomp(Message message, String subscriptionID) throws JMSException, IOException {
        log.debug("Sending to stomp");
        StompFrame frame = convertMessage(message);
        frame.getHeaders().put(Stomp.Headers.Message.SUBSCRIPTION, subscriptionID);
        protocolConverter.sendToStomp(frame);
    }

    public Destination convertDestination(String name, boolean forceNew)
            throws ProtocolException, JMSException, NamingException {
        if (name == null) {
            throw new ProtocolException("No destination is specified!");
        } else if (name.startsWith("/queue/") || name.startsWith("/topic/")) {
            return (Destination) initialContext.lookup("java:" + name);
            // } else if (name.startsWith("/temp-queue/")) {
            // String tempName = name.substring("/temp-queue/".length(), name.length());
            // Destination answer = temporaryDestinations.get(tempName);
            //
            // if (forceNew || answer == null) {
            // return temporaryDestination(tempName, session.createTemporaryQueue());
            // } else {
            // return answer;
            // }
            // } else if (name.startsWith("/temp-topic/")) {
            // String tempName = name.substring("/temp-topic/".length(), name.length());
            // Destination answer = temporaryDestinations.get(tempName);
            // if (forceNew || answer == null) {
            // return temporaryDestination(tempName, session.createTemporaryTopic());
            // } else {
            // return answer;
            // }
        } else {
            throw new ProtocolException("Illegal destination name: [" + name + "] -- StompConnect destinations "
                    + "must begine with one of: /queue/ /topic/ /temp-queue/ /temp-topic/");
        }
    }

    protected String convertDestination(Destination d) throws JMSException {
        if (d == null) {
            return null;
        }
        StringBuffer buffer = new StringBuffer();
        if (d instanceof Topic) {
            Topic topic = (Topic) d;
            // if (d instanceof TemporaryTopic) {
            // buffer.append("/temp-topic/");
            // temporaryDestination(topic.getTopicName(), d);
            // } else {
            buffer.append("/topic/");
            // }
            buffer.append(topic.getTopicName());
        } else {
            Queue queue = (Queue) d;
            // if (d instanceof TemporaryQueue) {
            // buffer.append("/temp-queue/");
            // temporaryDestination(queue.getQueueName(), d);
            // } else {
            buffer.append("/queue/");
            // }
            buffer.append(queue.getQueueName());
        }
        return buffer.toString();
    }

    protected int getDeliveryMode(Map headers) throws JMSException {
        Object o = headers.remove(Stomp.Headers.Send.PERSISTENT);
        if (o != null) {
            return "true".equals(o) ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT;
        } else {
            return producer.getDeliveryMode();
        }
    }

    protected int getPriority(Map headers) throws JMSException {
        Object o = headers.remove(Stomp.Headers.Send.PRIORITY);
        if (o != null) {
            return Integer.parseInt((String) o);
        } else {
            return producer.getPriority();
        }
    }

    protected long getTimeToLive(Map headers) throws JMSException {
        Object o = headers.remove(Stomp.Headers.Send.EXPIRATION_TIME);
        if (o != null) {
            return Long.parseLong((String) o);
        } else {
            return producer.getTimeToLive();
        }
    }

    protected void copyStandardHeadersFromMessageToFrame(Message message, StompFrame command) throws JMSException {
        final Map headers = command.getHeaders();
        headers.put(Stomp.Headers.Message.DESTINATION, convertDestination(message.getJMSDestination()));
        headers.put(Stomp.Headers.Message.MESSAGE_ID, message.getJMSMessageID());

        if (message.getJMSCorrelationID() != null) {
            headers.put(Stomp.Headers.Message.CORRELATION_ID, message.getJMSCorrelationID());
        }
        headers.put(Stomp.Headers.Message.EXPIRATION_TIME, "" + message.getJMSExpiration());

        if (message.getJMSRedelivered()) {
            headers.put(Stomp.Headers.Message.REDELIVERED, "true");
        }
        headers.put(Stomp.Headers.Message.PRORITY, "" + message.getJMSPriority());

        if (message.getJMSReplyTo() != null) {
            headers.put(Stomp.Headers.Message.REPLY_TO, convertDestination(message.getJMSReplyTo()));
        }
        headers.put(Stomp.Headers.Message.TIMESTAMP, "" + message.getJMSTimestamp());

        if (message.getJMSType() != null) {
            headers.put(Stomp.Headers.Message.TYPE, message.getJMSType());
        }

        // now lets add all the message headers
        Enumeration names = message.getPropertyNames();
        while (names.hasMoreElements()) {
            String name = (String) names.nextElement();
            Object value = message.getObjectProperty(name);
            headers.put(name, value);
        }
    }

    protected void copyStandardHeadersFromFrameToMessage(StompFrame command, Message msg)
            throws JMSException, ProtocolException, NamingException {
        final Map headers = new HashMap(command.getHeaders());

        // the standard JMS headers
        msg.setJMSCorrelationID((String) headers.remove(Stomp.Headers.Send.CORRELATION_ID));

        Object o = headers.remove(Stomp.Headers.Send.TYPE);
        if (o != null) {
            msg.setJMSType((String) o);
        }

        o = headers.remove(Stomp.Headers.Send.REPLY_TO);
        if (o != null) {
            msg.setJMSReplyTo(convertDestination((String) o, false));
        }

        // now the general headers
        for (Iterator iter = headers.entrySet().iterator(); iter.hasNext();) {
            Map.Entry entry = (Map.Entry) iter.next();
            String name = (String) entry.getKey();
            Object value = entry.getValue();
            msg.setObjectProperty(name, value);
        }
    }

    protected Message convertFrame(StompFrame command)
            throws JMSException, UnsupportedEncodingException, ProtocolException, NamingException {
        final Map headers = command.getHeaders();
        final Message msg;
        if (headers.containsKey(Stomp.Headers.CONTENT_LENGTH)) {
            headers.remove(Stomp.Headers.CONTENT_LENGTH);
            BytesMessage bm = session.createBytesMessage();
            bm.writeBytes(command.getContent());
            msg = bm;
        } else {
            String text = new String(command.getContent(), StandardCharsets.UTF_8);
            msg = session.createTextMessage(text);
        }
        copyStandardHeadersFromFrameToMessage(command, msg);
        return msg;
    }

    protected StompFrame convertMessage(Message message) throws JMSException, UnsupportedEncodingException {
        StompFrame command = new StompFrame();
        command.setAction(Stomp.Responses.MESSAGE);
        Map headers = new HashMap(25);
        command.setHeaders(headers);

        copyStandardHeadersFromMessageToFrame(message, command);

        if (message instanceof TextMessage) {
            TextMessage msg = (TextMessage) message;
            command.setContent(msg.getText().getBytes(StandardCharsets.UTF_8));
        } else if (message instanceof BytesMessage) {

            BytesMessage msg = (BytesMessage) message;
            byte[] data = new byte[(int) msg.getBodyLength()];
            msg.readBytes(data);

            headers.put(Stomp.Headers.CONTENT_LENGTH, "" + data.length);
            command.setContent(data);
        }
        return command;
    }

    public Message receiveFromJms(String destinationName, Map headers)
            throws JMSException, ProtocolException, NamingException {
        long ttl = getTimeToLive(headers);
        log.trace("Consuming message - ttl=" + ttl);
        Destination destination = convertDestination(destinationName, true);
        MessageConsumer consumer = session.createConsumer(destination);
        Message message;
        if (ttl > 0) {
            message = consumer.receive(ttl);
        } else {
            message = consumer.receive();
        }
        if (message != null) {
            // As this is a dequeue, automatically acknowledge the message
            message.acknowledge();
        }
        consumer.close();
        log.trace("Received message: " + message);
        return message;
    }

    public MessageConsumer createConsumer(Map headers) throws ProtocolException, JMSException, NamingException {
        String selector = (String) headers.remove(Stomp.Headers.Subscribe.SELECTOR);
        String destinationName = (String) headers.get(Stomp.Headers.Subscribe.DESTINATION);
        Destination destination = convertDestination(destinationName, true);

        MessageConsumer consumer;
        if (destination instanceof Topic) {
            boolean noLocal = false;
            String value = (String) headers.get(Stomp.Headers.Subscribe.NO_LOCAL);
            if (value != null && "true".equalsIgnoreCase(value)) {
                noLocal = true;
            }

            String subscriberName = (String) headers.get(Stomp.Headers.Subscribe.DURABLE_SUBSCRIPTION_NAME);
            if (subscriberName != null) {
                consumer = session.createDurableSubscriber((Topic) destination, subscriberName, selector, noLocal);
            } else {
                consumer = session.createConsumer(destination, selector, noLocal);
            }
        } else {
            consumer = session.createConsumer(destination, selector);
        }
        return consumer;
    }

    public StompSubscription subscribe(String subscriptionId, StompFrame command)
            throws ProtocolException, JMSException, NamingException {
        if (subscriptions.size() > 0) {
            throw new ProtocolException("This connection already has a subscription");
        }

        StompSubscription subscription = (StompSubscription) subscriptions.get(subscriptionId);
        if (subscription != null) {
            throw new ProtocolException("There already is a subscription for: " + subscriptionId
                    + ". Either use unique subscription IDs or do not create multiple subscriptions for the same destination");
        } else {
            subscription = new StompSubscription(this, subscriptionId, command);
            subscriptions.put(subscriptionId, subscription);
        }
        return subscription;
    }

    public void unsubscribe(String subscriptionId) throws ProtocolException, JMSException {
        StompSubscription subscription = (StompSubscription) subscriptions.remove(subscriptionId);
        if (subscription == null) {
            throw new ProtocolException("Cannot unsubscribe as mo subscription exists for id: " + subscriptionId);
        }
        subscription.close();
    }

    public void resume() throws JMSException {
        log.debug("Resuming session: " + session);

        Iterator<StompSubscription> iterator = subscriptions.values().iterator();
        while (iterator.hasNext()) {
            StompSubscription next = iterator.next();
            next.resume();
        }
    }

    public void recover() throws JMSException {
        log.debug("Recovering session: " + session);
        session.recover();
    }
}