/* * JBoss, Home of Professional Open Source * Copyright 2008, Red Hat, Inc., and others contributors as indicated * by the @authors tag. All rights reserved. * See the copyright.txt in the distribution for a * full listing of individual contributors. * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License, v. 2.1. * This program is distributed in the hope that it will be useful, but WITHOUT A * 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, * v.2.1 along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ package org.jboss.narayana.blacktie.jatmibroker.xatmi; import javax.naming.NamingException; import javax.transaction.InvalidTransactionException; import javax.transaction.SystemException; import javax.annotation.PostConstruct; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.jboss.narayana.blacktie.jatmibroker.core.conf.ConfigurationException; import org.jboss.narayana.blacktie.jatmibroker.core.transport.JtsTransactionImple; import org.jboss.narayana.blacktie.jatmibroker.core.transport.Message; import org.jboss.narayana.blacktie.jatmibroker.core.tx.TransactionException; import org.jboss.narayana.blacktie.jatmibroker.core.tx.TransactionImpl; import org.jboss.narayana.blacktie.jatmibroker.xatmi.impl.BufferImpl; import org.jboss.narayana.blacktie.jatmibroker.xatmi.impl.ConnectionImpl; import org.jboss.narayana.blacktie.jatmibroker.xatmi.impl.SessionImpl; import org.jboss.narayana.blacktie.jatmibroker.xatmi.impl.TPSVCINFO_Impl; import org.jboss.narayana.blacktie.jatmibroker.xatmi.impl.X_OCTET_Impl; import org.jboss.narayana.rest.bridge.inbound.InboundBridge; import org.jboss.narayana.rest.bridge.inbound.InboundBridgeManager; /** * MDB services implementations extend this class as it provides the core service template method. For non MDB services on the * Service interface need be implemented. */ public abstract class BlackTieService implements Service { /** * The logger to use. */ private static final Logger log = LogManager.getLogger(BlackTieService.class); private ConnectionFactory connectionFactory; private String name; protected BlackTieService(String name) throws ConfigurationException { //connectionFactory = ConnectionFactory.getConnectionFactory(); this.name = name; } public String getName() { return name; } @PostConstruct public void init() { log.info("init PostConstruct"); try { connectionFactory = ConnectionFactory.getConnectionFactory(); } catch (ConfigurationException e) { log.warn("init failed with " + e); } } /** * Entry points should pass control to this method as soon as reasonably possible. * * @param serviceName The name of the service * @param message The message to process * @throws ConnectionException * @throws ConnectionException In case communication fails * @throws ConfigurationException * @throws NamingException * @throws SystemException * @throws IllegalStateException * @throws InvalidTransactionException * @throws TransactionException */ protected void processMessage(String serviceName, Message message) throws ConnectionException, ConfigurationException, NamingException, InvalidTransactionException, IllegalStateException, SystemException, TransactionException { log.trace("Service invoked"); if(connectionFactory == null) { connectionFactory = ConnectionFactory.getConnectionFactory(); } ConnectionImpl connection = (ConnectionImpl) connectionFactory.getConnection(); try { boolean hasTx = false; boolean hasTPNOREPLY = (message.flags & Connection.TPNOREPLY) == Connection.TPNOREPLY; boolean responseSendable = !hasTPNOREPLY; // To respond with short rval = Connection.TPFAIL; int rcode = Connection.TPESVCERR; byte[] data = null; int len = 0; int flags = 0; String type = null; String subtype = null; SessionImpl serviceSession = ((ConnectionImpl)connection).createServiceSession(serviceName, message.cd, message.replyTo); InboundBridge inboundBridge = null; try { boolean hasTPCONV = (message.flags & Connection.TPCONV) == Connection.TPCONV; Boolean conversational = (Boolean) connectionFactory.getProperties().get("blacktie." + serviceName + ".conversational"); log.trace(serviceName); boolean isConversational = conversational == true; if (hasTPCONV && isConversational) { X_OCTET odata = new X_OCTET_Impl(null); byte[] ack = new byte[4]; byte[] bytes = "ACK".getBytes(); System.arraycopy(bytes, 0, ack, 0, 3); odata.setByteArray(ack); long result = serviceSession.tpsend(odata, 0); if (result == -1) { log.error("Could not send ack"); serviceSession.close(); return; } else { log.debug("Sent ack"); serviceSession.setCreatedState(message.flags); } } else if (!hasTPCONV && !isConversational) { log.debug("Session was not a TPCONV"); } else { log.error("Session was invoked in an improper manner"); X_OCTET odata = new X_OCTET_Impl(null); byte[] ack = new byte[4]; byte[] bytes = "ERR".getBytes(); System.arraycopy(bytes, 0, ack, 0, 3); odata.setByteArray(bytes); long result = serviceSession.tpsend(odata, 0); if (result == -1) { log.error("Could not send err"); } else { log.error("Error reported"); } serviceSession.close(); return; } log.debug("Created the session"); // THIS IS THE FIRST CALL BufferImpl buffer = null; if (message.type != null && !message.type.equals("")) { buffer = (BufferImpl) connection.tpalloc(message.type, message.subtype); buffer.deserialize(message.data); } TPSVCINFO tpsvcinfo = new TPSVCINFO_Impl(message.serviceName, buffer, message.flags, (hasTPCONV ? serviceSession : null), connection, message.len); log.debug("Prepared the data for passing to the service"); hasTx = (message.control != null && message.control.length() != 0); log.debug("hasTx=" + hasTx + " control: " + message.control); if (hasTx) { // make sure any foreign tx is resumed before calling // the // service routine if(message.control.startsWith("IOR")) { log.debug("resume OTS transaction"); JtsTransactionImple.resume(message.control); } else if(message.control.startsWith("http")) { log.debug("start inbound bridge"); inboundBridge = InboundBridgeManager.getInstance().createInboundBridge(message.control); inboundBridge.start(); } else { log.error(message.control + " is not OTS or RTS when resume the transaction"); } } log.debug("Invoking the XATMI service"); Response response = null; try { response = tpservice(tpsvcinfo); log.debug("Service invoked"); if (!hasTPNOREPLY && response == null) { log.error("Error, expected response but none returned"); } } catch (Throwable t) { log.error("Service error detected", t); } if (!hasTPNOREPLY && serviceSession.getSender() != null) { log.trace("Sending response"); if (response != null) { rval = response.getRval(); rcode = response.getRcode(); if (rval != Connection.TPSUCCESS && rval != Connection.TPFAIL) { rval = Connection.TPFAIL; } } if (connection.hasOpenSessions()) { rcode = Connection.TPESVCERR; rval = Connection.TPFAIL; } if (rval == Connection.TPFAIL) { if (TransactionImpl.current() != null) { try { TransactionImpl.current().rollback_only(); } catch (TransactionException e) { throw new ConnectionException(Connection.TPESYSTEM, "Could not mark transaction for rollback only"); } } } if (response != null) { BufferImpl toSend = (BufferImpl) response.getBuffer(); if (toSend != null) { len = toSend.getLen(); data = toSend.serialize(); type = toSend.getType(); subtype = toSend.getSubtype(); } flags = response.getFlags(); } log.debug("Will return desired message"); } else if (!hasTPNOREPLY && serviceSession.getSender() == null) { log.error("No sender avaible but message to be sent"); responseSendable = false; } else { log.debug("No need to send a response"); } } finally { if (hasTx) { // and suspend it again if(message.control.startsWith("IOR")) { log.debug("suspend OTS transaction"); JtsTransactionImple.suspend(); } else if(message.control.startsWith("http")) { log.debug("inbound bridge stop"); if(inboundBridge != null) { inboundBridge.stop(); } } else { log.error(message.control + " is not OTS or RTS when suspend the transaction"); } } if (responseSendable) { // Even though we can provide the cd we don't as // atmibroker-xatmi doesn't because tpreturn doesn't serviceSession.getSender().send("", rval, rcode, data, len, 0, flags, 0, type, subtype); } } } finally { connection.close(); } } }