/**
*
* 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 org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.activemq.message.ActiveMQDestination;
import org.codehaus.activemq.message.ActiveMQQueue;
import org.codehaus.activemq.message.ActiveMQTopic;
import javax.jms.Connection;
import javax.jms.ConnectionConsumer;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.Session;
import javax.jms.Topic;
import javax.resource.ResourceException;
import javax.resource.spi.work.Work;
import javax.resource.spi.work.WorkException;
import javax.resource.spi.work.WorkManager;
/**
* @version $Revision: 1.11.2.1 $ $Date: 2004/12/14 16:30:52 $
*/
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 long INITIAL_RECONNECT_DELAY = 1000; // 1 second.
private static final long MAX_RECONNECT_DELAY = 1000*30; // 30 seconds.
private static final ThreadLocal threadLocal = new ThreadLocal();
private ConnectionConsumer consumer;
private ServerSessionPoolImpl serverSessionPool;
private ActiveMQDestination dest;
private boolean running;
private Work connectWork;
protected Connection connection;
private long reconnectDelay=INITIAL_RECONNECT_DELAY;
/**
* @param adapter
* @param key
* @throws ResourceException
*/
public ActiveMQAsfEndpointWorker(final ActiveMQResourceAdapter adapter, ActiveMQEndpointActivationKey key)
throws ResourceException {
super(adapter, key);
connectWork = new Work() {
public void release() {
}
synchronized public void run() {
if( !isRunning() )
return;
if( connection!=null )
return;
ActiveMQActivationSpec activationSpec = endpointActivationKey.getActivationSpec();
try {
connection = adapter.makeConnection(activationSpec);
connection.start();
connection.setExceptionListener(new ExceptionListener() {
public void onException(JMSException error) {
reconnect(error);
}
});
if (activationSpec.isDurableSubscription()) {
consumer = connection.createDurableConnectionConsumer((Topic) dest, activationSpec
.getSubscriptionId(), emptyToNull(activationSpec.getMessageSelector()),
serverSessionPool, MAX_MSGS_PER_SESSION);
} else {
consumer = connection.createConnectionConsumer(dest, emptyToNull(activationSpec
.getMessageSelector()), serverSessionPool, MAX_MSGS_PER_SESSION);
}
} catch (JMSException error) {
reconnect(error);
}
}
};
ActiveMQActivationSpec activationSpec = endpointActivationKey.getActivationSpec();
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());
}
}
synchronized public void start() throws WorkException, ResourceException {
if (running)
return;
running = true;
log.debug("Starting");
serverSessionPool = new ServerSessionPoolImpl(this);
connect();
log.debug("Started");
}
/**
*
*/
synchronized public void stop() throws InterruptedException {
if (!running)
return;
running = false;
serverSessionPool.close();
disconnect();
}
private boolean isRunning() {
return running;
}
synchronized private void connect() {
if (!running)
return;
try {
workManager.scheduleWork(connectWork, WorkManager.INDEFINITE, null, null);
} catch (WorkException e) {
running = false;
log.error("Work Manager did not accept work: ",e);
}
}
/**
*
*/
synchronized private void disconnect() {
safeClose(consumer);
consumer=null;
safeClose(connection);
connection=null;
}
synchronized private void reconnect(JMSException error) {
log.debug("Reconnect cause: ", error);
// Only log errors if the server is really down.. And not a temp failure.
if( reconnectDelay == MAX_RECONNECT_DELAY ) {
log.info("Endpoint connection to JMS broker failed: "+error.getMessage());
log.info("Endpoint will try to reconnect to the JMS broker in "+(MAX_RECONNECT_DELAY/1000)+" seconds");
}
try {
disconnect();
Thread.sleep(reconnectDelay);
// Use exponential rollback.
reconnectDelay*=2;
if( reconnectDelay > MAX_RECONNECT_DELAY )
reconnectDelay = MAX_RECONNECT_DELAY;
connect();
} catch (InterruptedException e) {
}
}
protected void registerThreadSession(Session session) {
threadLocal.set(session);
}
protected void unregisterThreadSession(Session session) {
threadLocal.set(null);
}
private String emptyToNull(String value) {
if (value == null || value.length() == 0) {
return null;
}
return value;
}
}