/**
*
* 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 EDU.oswego.cs.dl.util.concurrent.Latch;
import EDU.oswego.cs.dl.util.concurrent.SynchronizedBoolean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.activemq.ActiveMQConnectionConsumer;
import org.codehaus.activemq.ActiveMQSession;
import org.codehaus.activemq.message.ActiveMQMessage;
import org.codehaus.activemq.message.ActiveMQQueue;
import org.codehaus.activemq.message.ActiveMQTopic;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Topic;
import javax.jms.XASession;
import javax.resource.ResourceException;
import javax.resource.spi.endpoint.MessageEndpoint;
import javax.resource.spi.work.Work;
import javax.resource.spi.work.WorkEvent;
import javax.resource.spi.work.WorkException;
import javax.resource.spi.work.WorkListener;
import javax.resource.spi.work.WorkManager;
import javax.transaction.xa.XAResource;
/**
* @version $Revision: 1.6 $ $Date: 2004/11/03 09:56:56 $
*/
public class ActiveMQPollingEndpointWorker extends ActiveMQBaseEndpointWorker implements Work {
private static final Log log = LogFactory.getLog(ActiveMQPollingEndpointWorker.class);
private static final int MAX_WORKERS = 10;
private SynchronizedBoolean started = new SynchronizedBoolean(false);
private SynchronizedBoolean stopping = new SynchronizedBoolean(false);
private Latch stopLatch = new Latch();
private ActiveMQConnectionConsumer consumer;
private CircularQueue workers;
static WorkListener debugingWorkListener = new WorkListener() {
//The work listener is useful only for debugging...
public void workAccepted(WorkEvent event) {
}
public void workRejected(WorkEvent event) {
log.warn("Work rejected: " + event, event.getException());
}
public void workStarted(WorkEvent event) {
}
public void workCompleted(WorkEvent event) {
}
};
/**
* @param adapter
* @param key
* @throws ResourceException
*/
public ActiveMQPollingEndpointWorker(ActiveMQResourceAdapter adapter, ActiveMQEndpointActivationKey key) throws ResourceException {
super(adapter, key);
}
public void start() throws WorkException, ResourceException {
ActiveMQActivationSpec activationSpec = endpointActivationKey.getActivationSpec();
boolean ok = false;
try {
workers = new CircularQueue(MAX_WORKERS, stopping);
for (int i = 0; i < workers.size(); i++) {
ActiveMQSession session = createSession();
XAResource xaresource = null;
if (session instanceof XASession) {
if (!transacted) {
throw new ResourceException("You cannot use an XA Connection with a non transacted endpoint.");
}
xaresource = ((XASession) session).getXAResource();
}
MessageEndpoint endpoint = endpointFactory.createEndpoint(xaresource);
workers.returnObject(new InboundEndpointWork(session, endpoint, workers));
}
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 (emptyToNull(activationSpec.getSubscriptionName()) != null) {
consumer = (ActiveMQConnectionConsumer) getPhysicalConnection().createDurableConnectionConsumer((Topic) dest, activationSpec.getSubscriptionName(), emptyToNull(activationSpec.getMessageSelector()), null, 0);
}
else {
consumer = (ActiveMQConnectionConsumer) getPhysicalConnection().createConnectionConsumer(dest, emptyToNull(activationSpec.getMessageSelector()), null, 0);
}
ok = true;
log.debug("Started");
workManager.scheduleWork(this, WorkManager.INDEFINITE, null, debugingWorkListener);
ok = true;
}
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);
}
}
}
private String emptyToNull(String value) {
if ("".equals(value)) {
return null;
}
return value;
}
/**
*
*/
public void stop() throws InterruptedException {
stopping.set(true);
workers.notifyWaiting();
if (started.compareTo(true) == 0) {
stopLatch.acquire();
}
safeClose(consumer);
}
/**
* @see javax.resource.spi.work.Work#release()
*/
public void release() {
}
/**
* The WorkManager has started up and we now need to pull message off
* the destination and push them to an endpoint.
*
* @see java.lang.Runnable#run()
*/
public void run() {
started.set(true);
try {
while (!stopping.get()) {
ActiveMQMessage message = consumer.receive(500);
if (message != null) {
InboundEndpointWork worker = (InboundEndpointWork) workers.get();
// Did we get stopped?
if (worker == null) {
break;
}
worker.setMessage(message);
workManager.scheduleWork(worker, WorkManager.INDEFINITE, null, debugingWorkListener);
}
}
// Try to collect the workers so that none are running.
workers.drain();
}
catch (Throwable e) {
log.info("dispatcher: ", e);
}
finally {
stopLatch.release();
}
}
}