/**
*
* Copyright 2004 Hiram Chirino
*
* 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.ra;
import java.util.ArrayList;
import java.util.LinkedList;
import javax.jms.ConnectionConsumer;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.ServerSession;
import javax.jms.ServerSessionPool;
import javax.jms.Session;
import javax.jms.Topic;
import javax.jms.XASession;
import javax.resource.ResourceException;
import javax.resource.spi.UnavailableException;
import javax.resource.spi.endpoint.MessageEndpoint;
import javax.resource.spi.work.WorkException;
import javax.transaction.xa.XAResource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.activemq.message.ActiveMQQueue;
import org.codehaus.activemq.message.ActiveMQTopic;
/**
* @version $Revision: 1.8 $ $Date: 2004/11/20 05:49:51 $
*/
public class ActiveMQAsfEndpointWorker extends ActiveMQBaseEndpointWorker {
private static final Log log = LogFactory.getLog(ActiveMQAsfEndpointWorker.class);
private static final int MAX_MSGS_PER_SESSION = 1;
private static final int MAX_SESSION = 10;
private static final ThreadLocal threadLocal = new ThreadLocal();
private ConnectionConsumer consumer;
private ServerSessionPoolImpl serverSessionPool;
/**
* @param adapter
* @param key
* @throws ResourceException
*/
public ActiveMQAsfEndpointWorker(ActiveMQResourceAdapter adapter, ActiveMQEndpointActivationKey key) throws ResourceException {
super(adapter, key);
}
public void start() throws WorkException, ResourceException {
log.debug("Starting");
boolean ok = false;
try {
serverSessionPool = new ServerSessionPoolImpl();
ActiveMQActivationSpec activationSpec = endpointActivationKey.getActivationSpec();
Destination dest = null;
if ("javax.jms.Queue".equals(activationSpec.getDestinationType())) {
dest = new ActiveMQQueue(activationSpec.getDestination());
}
else if ("javax.jms.Topic".equals(activationSpec.getDestinationType())) {
dest = new ActiveMQTopic(activationSpec.getDestination());
}
else {
throw new ResourceException("Unknown destination type: " + activationSpec.getDestinationType());
}
if (activationSpec.isDurableSubscription()) {
consumer = getPhysicalConnection().createDurableConnectionConsumer((Topic) dest, activationSpec.getSubscriptionId(), emptyToNull(activationSpec.getMessageSelector()), serverSessionPool, MAX_MSGS_PER_SESSION);
}
else {
consumer = getPhysicalConnection().createConnectionConsumer(dest, emptyToNull(activationSpec.getMessageSelector()), serverSessionPool, MAX_MSGS_PER_SESSION);
}
ok = true;
log.debug("Started");
}
catch (JMSException e) {
throw new ResourceException("Could not start the endpoint.", e);
}
finally {
// We don't want to leak sessions on errors. Keep them around only if
// there were no errors.
if (!ok) {
safeClose(consumer);
}
}
}
/**
*
*/
public void stop() throws InterruptedException {
safeClose(consumer);
serverSessionPool.close();
}
protected void registerThreadSession(Session session) {
threadLocal.set(session);
}
protected void unregisterThreadSession(Session session) {
threadLocal.set(null);
}
class ServerSessionPoolImpl implements ServerSessionPool {
ServerSessionImpl ss;
ArrayList idleSessions = new ArrayList();
LinkedList activeSessions = new LinkedList();
int sessionIds = 0;
int nextUsedSession;
boolean closing = false;
public ServerSessionPoolImpl() {
}
public ServerSessionImpl createServerSessionImpl() throws JMSException {
Session session = createSession();
XAResource xaResource=null;
if (session instanceof XASession) {
xaResource = ((XASession) session).getXAResource();
}
MessageEndpoint endpoint;
try {
endpoint = endpointFactory.createEndpoint( xaResource );
} catch (UnavailableException e) {
// The container could be limiting us on the number of endpoints that are being created.
session.close();
return null;
}
return new ServerSessionImpl(this, session, workManager, endpoint);
}
/**
*/
synchronized public ServerSession getServerSession() throws JMSException {
log.debug("ServerSession requested.");
if (closing) {
throw new JMSException("Session Pool Shutting Down.");
}
if (idleSessions.size() > 0) {
ServerSessionImpl ss = (ServerSessionImpl) idleSessions.remove(idleSessions.size() - 1);
activeSessions.addLast(ss);
log.debug("Using idle session: " + ss);
return ss;
}
else {
// Are we at the upper limit?
if (activeSessions.size() >= MAX_SESSION ) {
// then reuse the allready created sessions..
// This is going to queue up messages into a session for processing.
return getExistingServerSession();
}
ServerSessionImpl ss = createServerSessionImpl();
// We may not be able to create a session due to the conatiner restricting us.
if( ss==null ) {
return getExistingServerSession();
}
activeSessions.addLast(ss);
log.debug("Created a new session: " + ss);
return ss;
}
}
/**
* @return
*/
private ServerSession getExistingServerSession() {
ServerSessionImpl ss = (ServerSessionImpl) activeSessions.removeFirst();
activeSessions.addLast(ss);
log.debug("Reusing an active session: " + ss);
return ss;
}
synchronized public void returnToPool(ServerSessionImpl ss) {
log.debug("Session returned to pool: " + ss);
idleSessions.add(ss);
}
public void close() {
synchronized (this) {
closing = true;
}
}
}
private String emptyToNull(String value) {
if ("".equals(value)) {
return null;
}
return value;
}
}