All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ow2.bonita.pvm.internal.ejb.CommandReceiverMDB Maven / Gradle / Ivy

/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.ow2.bonita.pvm.internal.ejb;

import java.io.Serializable;

import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.MessageDrivenBean;
import javax.ejb.MessageDrivenContext;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;

import org.ow2.bonita.pvm.internal.jobexecutor.ExecuteJobCmd;
import org.ow2.bonita.pvm.job.Job;
import org.ow2.bonita.util.Command;
import org.ow2.bonita.util.ExceptionManager;
import org.ow2.bonita.util.Log;

/**
 * Message driven command receiver.
 * 
 * 

Configuration

* *

* The command receiver listens for messages on the destination established * during deployment. Upon delivery, this bean extracts a {@linkplain Command * command} from the message according to the format described in the * {@link #onMessage(Message) onMessage} method. * *

* If the message does not match the expected format, it is forwarded to the * message destination referenced by jms/DeadLetterQueue. No * further processing is done on the message. *

* *

* After extraction, the receiver dispatches the command to the * {@linkplain LocalCommandExecutor local command executor} specified by the EJB * reference ejb/LocalCommandExecutor. *

* *

* In case the incoming message includes a replyTo destination, the * result of the command execution is wrapped into a message and sent there. The * resource manager connection factory reference * jms/CommandConnectionFactory specifies the factory used to * obtain JMS connections. *

* * @author Jim Rigsbee * @author Tom Baeyens * @author Alejandro Guizar */ public class CommandReceiverMDB implements MessageDrivenBean, MessageListener { private MessageDrivenContext messageDrivenContext; private LocalCommandExecutor commandExecutor; private Connection jmsConnection; private Destination deadLetterQueue; private static final long serialVersionUID = 1L; private static final Log LOG = Log.getLog(CommandReceiverMDB.class.getName()); /** * Processes a command message. * *

Message format

* *

* The incoming messages must conform to one of the following formats. *

* *
    *
  • Command object. The body of the message is a Java * {@linkplain ObjectMessage object} that implements the {@link Command} * interface. The header properties of the message, if any, are ignored.
  • *
  • Job reference. The message contains a header property * called jobId of type long which references a * saved {@linkplain Job job} that is outstanding for execution. The body of * the message, if any, is ignored.
  • *
*/ public void onMessage(Message message) { try { // extract command from message Command< ? > command = extractCommand(message); if (command == null) { discard(message); return; } // execute command via local command executor bean Object result = commandExecutor.execute(command); // send a response back if a "reply to" destination is set Destination replyTo = message.getJMSReplyTo(); if (replyTo != null && (result instanceof Serializable || result == null)) { sendResult((Serializable) result, replyTo, message.getJMSMessageID()); } } catch (JMSException e) { String msg = ExceptionManager.getInstance().getFullMessage( "bp_CRMDB_1", message); throw new EJBException(msg, e); } } @SuppressWarnings("unchecked") private static Command< ? > extractCommand(Message message) throws JMSException { Command< ? > command = null; // messages can contain serialized commands if (message instanceof ObjectMessage) { ObjectMessage objectMessage = (ObjectMessage) message; Serializable body = objectMessage.getObject(); LOG.debug("received object message with body " + body); if (body instanceof Command) { command = (Command< ? >) body; } else { LOG.info("WARNING: ignoring object message, body is not a command: " + message); } } else if (message.getObjectProperty("jobId") != null) { // messages can also contain a jobId property long jobId = message.getLongProperty("jobId"); LOG.debug("received message with jobImpl id " + jobId); // create a command with the given jobId command = new ExecuteJobCmd(jobId); } else { LOG.info("WARNING: ignoring message, unknown format: " + message); } return command; } private void discard(Message message) throws JMSException { // if a dead letter queue is configured, send the message there if (deadLetterQueue != null) { Session jmsSession = createSession(); try { jmsSession.createProducer(deadLetterQueue).send(message); } finally { jmsSession.close(); } } else { // reject the message messageDrivenContext.setRollbackOnly(); } } private Session createSession() throws JMSException { /* * if the connection supports xa, the session will be transacted, else the * session will auto acknowledge; in either case no explicit transaction * control must be performed - see ejb 2.1 section 17.3.5 */ return jmsConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); } private void sendResult(Serializable result, Destination destination, String correlationId) throws JMSException { LOG.debug("sending result " + result + " to " + destination); Session jmsSession = createSession(); try { Message resultMessage = jmsSession.createObjectMessage(result); resultMessage.setJMSCorrelationID(correlationId); jmsSession.createProducer(destination).send(resultMessage); } finally { jmsSession.close(); } } public void setMessageDrivenContext(MessageDrivenContext messageDrivenContext) { this.messageDrivenContext = messageDrivenContext; } public void ejbCreate() { try { Context context = new InitialContext(); LocalCommandExecutorHome commandExecutorHome = (LocalCommandExecutorHome) context .lookup("java:comp/env/ejb/LocalCommandExecutor"); ConnectionFactory jmsConnectionFactory = (ConnectionFactory) context .lookup("java:comp/env/jms/CommandConnectionFactory"); try { deadLetterQueue = (Destination) context .lookup("java:comp/env/jms/DeadLetterQueue"); } catch (NameNotFoundException e) { LOG .info("dead letter queue not specified, messages with unknown formats will be rejected"); } context.close(); commandExecutor = commandExecutorHome.create(); jmsConnection = jmsConnectionFactory.createConnection(); } catch (NamingException e) { String message = ExceptionManager.getInstance().getFullMessage("bp_CRMDB_2"); throw new EJBException(message, e); } catch (CreateException e) { String message = ExceptionManager.getInstance().getFullMessage("bp_CRMDB_3"); throw new EJBException(message, e); } catch (JMSException e) { String message = ExceptionManager.getInstance().getFullMessage("bp_CRMDB_4"); throw new EJBException(message, e); } } public void ejbRemove() { if (jmsConnection != null) { try { jmsConnection.close(); } catch (JMSException e) { LOG.debug("could not close jms connection", e); } jmsConnection = null; } commandExecutor = null; messageDrivenContext = null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy