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()); } } } } } }