package org.jbpm.task.service.jms;
import java.io.Serializable;
import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.naming.Context;
import javax.naming.InitialContext;
import org.jbpm.task.service.BaseHandler;
import org.jbpm.task.service.TaskClientConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JMSTaskClientConnector implements TaskClientConnector {
private static final Logger logger = LoggerFactory.getLogger(JMSTaskClientConnector.class);
protected QueueConnection connection;
protected QueueSession session;
protected Queue queue;
protected Queue responseQueue;
protected final BaseJMSHandler handler;
protected final String name;
protected AtomicInteger counter;
private MessageProducer producer;
private Properties connectionProperties;
private Context context;
private String selector;
public JMSTaskClientConnector(String name, BaseJMSHandler handler, Properties connectionProperties, Context context) {
if (name == null) {
throw new IllegalArgumentException("Name can not be null");
}
this.name = name;
this.handler = handler;
this.connectionProperties = connectionProperties;
this.context = context;
this.counter = new AtomicInteger();
}
public boolean connect(String address, int port) {
return connect();
}
public boolean connect() {
if (this.session != null) {
//throw new IllegalStateException("Already connected. Disconnect first.");
return true;
}
try {
String connFactoryName = connectionProperties.getProperty(TaskServiceConstants.TASK_CLIENT_CONNECTION_FACTORY_NAME);
String transactedQueueString = connectionProperties.getProperty(TaskServiceConstants.TASK_CLIENT_TRANSACTED_QUEUE_NAME);
String acknowledgeModeString = connectionProperties.getProperty(TaskServiceConstants.TASK_CLIENT_ACKNOWLEDGE_MODE_NAME);
String queueName = connectionProperties.getProperty(TaskServiceConstants.TASK_CLIENT_QUEUE_NAME_NAME);
String responseQueueName = connectionProperties.getProperty(TaskServiceConstants.TASK_CLIENT_RESPONSE_QUEUE_NAME_NAME);
boolean transactedQueue = Boolean.valueOf(transactedQueueString);
int acknowledgeMode = Session.DUPS_OK_ACKNOWLEDGE; //default
if ("AUTO_ACKNOWLEDGE".equals(acknowledgeModeString)) {
acknowledgeMode = Session.AUTO_ACKNOWLEDGE;
} else if ("CLIENT_ACKNOWLEDGE".equals(acknowledgeModeString)) {
acknowledgeMode = Session.CLIENT_ACKNOWLEDGE;
}
Context ctx = this.context;
if (ctx == null) {
ctx = new InitialContext();
}
QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup(connFactoryName);
this.connection = factory.createQueueConnection();
this.session = this.connection.createQueueSession(transactedQueue, acknowledgeMode);
this.queue = this.session.createQueue(queueName);
this.responseQueue = this.session.createQueue(responseQueueName);
this.producer = this.session.createProducer(this.queue);
this.connection.start();
return true;
} catch (Exception e) {
logger.error(e.getMessage());
}
return false;
}
private Object readMessage(ObjectMessage serverMessage) throws JMSException {
return serverMessage.getObject();
}
public void disconnect() {
if (this.producer != null) {
try {
this.producer.close();
} catch (Exception e) {
} finally {
this.producer = null;
}
}
if (this.session != null) {
try {
this.session.close();
} catch (Exception e) {
} finally {
this.session = null;
}
}
if (this.connection != null) {
try {
this.connection.close();
} catch (Exception e) {
} finally {
this.connection = null;
}
}
}
public void write(Object object) {
try {
ObjectMessage message = this.session.createObjectMessage();
this.selector = UUID.randomUUID().toString();
Thread responseThread = new Thread(new Responder(selector));
responseThread.start();
message.setStringProperty(TaskServiceConstants.SELECTOR_NAME, this.selector);
message.setObject((Serializable)object);
this.producer.send(message);
this.session.commit();
} catch (Throwable e) {
throw new RuntimeException("Error creating message", e);
}
}
public AtomicInteger getCounter() {
return this.counter;
}
public BaseHandler getHandler() {
return this.handler;
}
public String getName() {
return this.name;
}
protected class Responder implements Runnable {
private final String selector;
protected Responder(String selector) {
this.selector = selector;
}
public void run() {
MessageConsumer consumer = null;
try {
consumer = session.createConsumer(responseQueue, " " + TaskServiceConstants.SELECTOR_NAME + " like '" + selector + "%' ");
ObjectMessage serverMessage = (ObjectMessage) consumer.receive();
if (serverMessage != null) {
((JMSTaskClientHandler) handler).messageReceived(session, readMessage(serverMessage), responseQueue, selector);
}
} catch (JMSException e) {
if (!"102".equals(e.getErrorCode())) {
throw new RuntimeException("No se pudo recibir respuesta JMS", e);
}
logger.info(e.getMessage());
return;
} catch (Exception e) {
throw new RuntimeException("Error inesperado recibiendo respuesta JMS", e);
} finally {
if (consumer != null) {
try {
consumer.close();
} catch (Exception e) {
logger.info("No se pudo cerrar el consumer: " + e.getMessage());
}
}
}
}
}
}