001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.activemq; 019 020import java.util.concurrent.atomic.AtomicInteger; 021 022import javax.jms.ConnectionConsumer; 023import javax.jms.IllegalStateException; 024import javax.jms.JMSException; 025import javax.jms.ServerSession; 026import javax.jms.ServerSessionPool; 027import javax.jms.Session; 028 029import org.apache.activemq.command.ConsumerInfo; 030import org.apache.activemq.command.MessageDispatch; 031 032/** 033 * For application servers, <CODE>Connection</CODE> objects provide a special 034 * facility for creating a <CODE>ConnectionConsumer</CODE> (optional). The 035 * messages it is to consume are specified by a <CODE>Destination</CODE> and a 036 * message selector. In addition, a <CODE>ConnectionConsumer</CODE> must be 037 * given a <CODE>ServerSessionPool</CODE> to use for processing its messages. 038 * <p/> 039 * <P> 040 * Normally, when traffic is light, a <CODE>ConnectionConsumer</CODE> gets a 041 * <CODE>ServerSession</CODE> from its pool, loads it with a single message, 042 * and starts it. As traffic picks up, messages can back up. If this happens, a 043 * <CODE>ConnectionConsumer</CODE> can load each <CODE>ServerSession</CODE> 044 * with more than one message. This reduces the thread context switches and 045 * minimizes resource use at the expense of some serialization of message 046 * processing. 047 * 048 * @see javax.jms.Connection#createConnectionConsumer 049 * @see javax.jms.Connection#createDurableConnectionConsumer 050 * @see javax.jms.QueueConnection#createConnectionConsumer 051 * @see javax.jms.TopicConnection#createConnectionConsumer 052 * @see javax.jms.TopicConnection#createDurableConnectionConsumer 053 */ 054 055public class ActiveMQConnectionConsumer implements ConnectionConsumer, ActiveMQDispatcher { 056 057 private ActiveMQConnection connection; 058 private ServerSessionPool sessionPool; 059 private ConsumerInfo consumerInfo; 060 private boolean closed; 061 062 /** 063 * Create a ConnectionConsumer 064 * 065 * @param theConnection 066 * @param theSessionPool 067 * @param theConsumerInfo 068 * @throws JMSException 069 */ 070 protected ActiveMQConnectionConsumer(ActiveMQConnection theConnection, ServerSessionPool theSessionPool, ConsumerInfo theConsumerInfo) throws JMSException { 071 this.connection = theConnection; 072 this.sessionPool = theSessionPool; 073 this.consumerInfo = theConsumerInfo; 074 075 this.connection.addConnectionConsumer(this); 076 this.connection.addDispatcher(consumerInfo.getConsumerId(), this); 077 this.connection.syncSendPacket(this.consumerInfo); 078 } 079 080 /** 081 * Gets the server session pool associated with this connection consumer. 082 * 083 * @return the server session pool used by this connection consumer 084 * @throws JMSException if the JMS provider fails to get the server session 085 * pool associated with this consumer due to some internal 086 * error. 087 */ 088 089 public ServerSessionPool getServerSessionPool() throws JMSException { 090 if (closed) { 091 throw new IllegalStateException("The Connection Consumer is closed"); 092 } 093 return this.sessionPool; 094 } 095 096 /** 097 * Closes the connection consumer. <p/> 098 * <P> 099 * Since a provider may allocate some resources on behalf of a connection 100 * consumer outside the Java virtual machine, clients should close these 101 * resources when they are not needed. Relying on garbage collection to 102 * eventually reclaim these resources may not be timely enough. 103 * 104 * @throws JMSException 105 */ 106 107 public void close() throws JMSException { 108 if (!closed) { 109 dispose(); 110 this.connection.asyncSendPacket(this.consumerInfo.createRemoveCommand()); 111 } 112 113 } 114 115 public void dispose() { 116 if (!closed) { 117 this.connection.removeDispatcher(consumerInfo.getConsumerId()); 118 this.connection.removeConnectionConsumer(this); 119 closed = true; 120 } 121 } 122 123 public void dispatch(MessageDispatch messageDispatch) { 124 try { 125 messageDispatch.setConsumer(this); 126 127 ServerSession serverSession = sessionPool.getServerSession(); 128 Session s = serverSession.getSession(); 129 ActiveMQSession session = null; 130 131 if (s instanceof ActiveMQSession) { 132 session = (ActiveMQSession)s; 133 } else if (s instanceof ActiveMQTopicSession) { 134 ActiveMQTopicSession topicSession = (ActiveMQTopicSession)s; 135 session = (ActiveMQSession)topicSession.getNext(); 136 } else if (s instanceof ActiveMQQueueSession) { 137 ActiveMQQueueSession queueSession = (ActiveMQQueueSession)s; 138 session = (ActiveMQSession)queueSession.getNext(); 139 } else { 140 connection.onClientInternalException(new JMSException("Session pool provided an invalid session type: " + s.getClass())); 141 return; 142 } 143 144 session.dispatch(messageDispatch); 145 serverSession.start(); 146 } catch (JMSException e) { 147 connection.onAsyncException(e); 148 } 149 } 150 151 public String toString() { 152 return "ActiveMQConnectionConsumer { value=" + consumerInfo.getConsumerId() + " }"; 153 } 154 155 public void clearMessagesInProgress(AtomicInteger transportInterruptionProcessingComplete) { 156 // future: may want to deal with rollback of in progress messages to track re deliveries 157 // before indicating that all is complete. 158 } 159 160 public ConsumerInfo getConsumerInfo() { 161 return consumerInfo; 162 } 163}