ConsumerProcessor.java :  » ESB » cbesb-1.2 » com » bostechcorp » cbesb » runtime » component » jms » processors » Java Open Source

Java Open Source » ESB » cbesb 1.2 
cbesb 1.2 » com » bostechcorp » cbesb » runtime » component » jms » processors » ConsumerProcessor.java
/*
 * ChainBuilder ESB
 *     Visual Enterprise Integration
 * 
 * Copyright (C) 2006 Bostech Corporation
 * 
 * This program is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU General Public License as published by the 
 * Free Software Foundation; either version 2 of the License, or (at your option) 
 * any later version.
 *
 * This program 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 General Public License 
 * for more details.
 * 
 * You should have received a copy of the GNU General Public License along with 
 * this program; if not, write to the Free Software Foundation, Inc., 
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 *
 * $Id: ConsumerProcessor.java 1206 2006-09-23 03:51:32Z elu $
 */
package com.bostechcorp.cbesb.runtime.component.jms.processors;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import javax.jbi.JBIException;
import javax.jbi.messaging.MessageExchange;
import javax.jbi.messaging.NormalizedMessage;
import javax.jms.BytesMessage;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.TextMessage;
import javax.resource.spi.work.Work;
import javax.resource.spi.work.WorkException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.bostechcorp.cbesb.common.runtime.CbesbException;
import com.bostechcorp.cbesb.common.runtime.ConfigurationException;
import com.bostechcorp.cbesb.common.runtime.ResourcesConnectionException;
import com.bostechcorp.cbesb.common.util.ErrorUtil;
import com.bostechcorp.cbesb.runtime.ccsl.jbi.messaging.CbConsumerProcessor;
import com.bostechcorp.cbesb.runtime.ccsl.jbi.messaging.StatusConstants;
import com.bostechcorp.cbesb.runtime.ccsl.lib.ExternalInput;
import com.bostechcorp.cbesb.runtime.ccsl.messages.FaultMessage.FaultMessageTypes;
import com.bostechcorp.cbesb.runtime.ccsl.nmhandler.FaultHandler;
import com.bostechcorp.cbesb.runtime.ccsl.nmhandler.SourceHelper;
import com.bostechcorp.cbesb.runtime.component.jms.JMSEndpoint;
import com.bostechcorp.cbesb.runtime.component.jms.JMSMarshaler;
import com.bostechcorp.cbesb.runtime.component.util.wsdl.WsdlMepConstants;
import com.bostechcorp.cbesb.runtime.jms.JMSConsumerHandler;
import com.bostechcorp.cbesb.runtime.jms.JMSHandler;

public class ConsumerProcessor extends CbConsumerProcessor {

  protected final transient Log logger = LogFactory.getLog(getClass());

  protected AtomicBoolean running = new AtomicBoolean(false);

  
  //TODO Eric Lu : please pay attention to the thread-safety issue here for using any attributes 
  private JMSHandler jmsHandler;

  private JMSEndpoint endpoint;

  // private MessageExchange exchange;

  // added in JMS 1.2
  Message jmsInMessage = null;

  private FaultMessageTypes faultType = null;

  //Important: rename retrysLeft -> retrysCount, we want it compare to endpoint.getMaxRetryCount() directly,
  //So we can support use change MaxRetryCount property of endpoint  dynamically by Admin Console
  protected AtomicInteger retrysCount = new AtomicInteger(0);

//  protected long retryInterval = 0;

  

  private Work pollWork = null;
  
  //  since version 1.2b
  private boolean recoverableInRetryFault=false;
  
  // private boolean needsReply;
  //

  public ConsumerProcessor(JMSEndpoint endpoint) {
    super(endpoint);
    this.endpoint = endpoint;
  }

  protected void doStart() throws ConfigurationException,
      ResourcesConnectionException, JMSException, WorkException,
      InterruptedException {

    // try {
    String initialContextFactory = null;
    String providerUrl = null;
    String connectionFactoryName = null;
    String userName = null;
    String password = null;

    if (endpoint.getJndiInitialContextFactory() != null)
      initialContextFactory = endpoint.getJndiInitialContextFactory();

    if (endpoint.getJndiProviderUrl() != null)
      providerUrl = endpoint.getJndiProviderUrl();

    if (endpoint.getJndiConnectionFactoryName() != null)
      connectionFactoryName = endpoint.getJndiConnectionFactoryName();
    
    logger.debug("defaultMep:"+endpoint.getDefaultMep());
    
    if (!endpoint.getDefaultMep().equals(WsdlMepConstants.IN_ONLY)) {
      // creating a tranactional/nonTransactional handler
      logger.info("Creating transactional JMS Handler");
      jmsHandler = new JMSConsumerHandler(initialContextFactory, providerUrl,
          connectionFactoryName, userName, password, endpoint
              .getDestinationStyle(), endpoint
              .getTargetDestinationName(), endpoint
              .getReplyDestinationName(), endpoint
              .isTransactional(),endpoint.getDLQ());
      // jmsHandler.setExceptionListener(this);
            //retry relate to transaction.
      if (endpoint.isTransactional() && endpoint.isRetry()) // getting retry settings
      {
//        synchronized(retrysCount)
//        {retrysCount.set(endpoint.getMaxRetryCount());
//         retrysCount.notify();
//         }
        //retryInterval = endpoint.getRetryInterval();
        logger.debug("Retry mode enabled. "+endpoint.getMaxRetryCount()+" retry's count with interval of "+endpoint.getRetryInterval()+" ms");
      }else
      {
        logger.debug("Retry mode Disabled.");
      }

    } else// Inonly Mep:  non transactional handler
    {
      //Transaction not supported for InOnly MEP
      logger.info("Creating nontransactional JMS Handler");
      jmsHandler = new JMSConsumerHandler(initialContextFactory, providerUrl,
          connectionFactoryName, userName, password, endpoint
              .getDestinationStyle(), endpoint
              .getTargetDestinationName(), endpoint
              .getReplyDestinationName(), false,endpoint.getDLQ());  
    }

    synchronized (running) {
      synchronized(retrysCount){
      pollWork = new Work() {
        public void release() {}
        public void run() 
        {ConsumerProcessor.this.poll();}
      };
      endpoint.getServiceUnit().getComponent().getWorkManager()
          .startWork(pollWork);
      running.wait();
      retrysCount.wait();
      }
    }
  }
  protected void doStop(boolean retryStopped) throws Exception {
    logger.debug("try to stop.........");
    if(jmsHandler!=null) {
      logger.debug("try to role back and close jmshandler");
      jmsHandler.rollback();
      jmsHandler.close();
    }
    logger.debug("try to set  running to false");
    synchronized(retrysCount)
    {
      retrysCount.incrementAndGet();  // decreasing retrys left
      retrysCount.notify();
    }
    synchronized(running) {
      running.set(false);
      running.notify();
    }
    logger.debug("setted running to false");
    logger.debug("stop done");
    if(retryStopped)
      endpoint.setState(StatusConstants.STATUS_RETRY_STOPPRD);
    else
      endpoint.setState(StatusConstants.STATUS_DOWN);

  }
  /**
   * transacted pool
   */
  protected void poll() {
    synchronized (running) {
      running.set(true);
      running.notify();
    }
    try {
      while (running.get()) {
        logger.info("Consumer polling message from queue.");
        jmsInMessage = null;
        // just in case the selector is used, then we filter the recived
        // messages based on selector
        if (endpoint.isEnableQuery()) {
          jmsInMessage = jmsHandler.receiveFiltered(endpoint
              .getQueryExpression(), false,true);
        } else {
          //jmsInMessage = jmsHandler.receive();
          jmsInMessage = jmsHandler.receiveFiltered("", false,true);
        }

        if (jmsInMessage != null) {
          
          debugJmsMessageProperties(jmsInMessage);  // Print properties
          
          ExternalInput input = jmsMessageToExternalInput();

          while (input.hasMoreData()) {
            // exchange = null;
            long startProcessTime=System.currentTimeMillis();
            faultType = null;// forget any previous error
            logger.debug("POLL() BEFORE PROCESS(INPUT)");
            process(input); // this does a callback to transform()
            logger.debug("POLL() AFTER PROCESS(INPUT)");
            
            if (faultType != null){
              //Recoverable fault, already  roleback in doProcessFault() method
              if(faultType.equals(FaultMessageTypes.RECOVERABLE)){
                synchronized (pollWork){
                  pollWork.wait(endpoint.getRetryInterval());
                }
              break;
              }
              //UnRecoverable falut, already commit in DoProcessFault() method 
              //else continue;
            }
            //No fault
            else {
              jmsHandler.commit();
              if(!endpoint.getState().equals(StatusConstants.STATUS_UP))
                endpoint.setState(StatusConstants.STATUS_UP);

            }
            endpoint.sendMessageProcessedNotification(System.currentTimeMillis()-startProcessTime);
            
          }
        }
        if(jmsHandler.isClosed()) {
          logger.info("jmsHandler closed");

          break;
        }
      }
      
    } catch (Exception e) {
      ErrorUtil.printError("Exception in poll(): ", e);
  
    } finally {
      synchronized (running) {
        running.set(false);
        running.notify();
        logger.info("Polling Stoped; \"running\" flag set to False");
      }
    }
  }

  private ExternalInput jmsMessageToExternalInput()
      throws Exception {
    String charset = endpoint.getCharset();
    String readStyle = endpoint.getReadStyle();
    String recType = endpoint.getRecordType();
    int rpm = Integer.parseInt(endpoint.getRecordsPerMessage());
    ExternalInput input = null;
    if (jmsInMessage instanceof TextMessage) {
      TextMessage tm = (TextMessage) jmsInMessage;
      input = new ExternalInput(new StringReader(tm.getText()), charset,
          readStyle, recType, rpm);
    } else if (jmsInMessage instanceof BytesMessage) {
      BytesMessage bm = (BytesMessage) jmsInMessage;
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      byte[] buf = new byte[2048];
      for (int l = 0; (l = bm.readBytes(buf)) > 0;)
        baos.write(buf, 0, l);
      input = new ExternalInput(new ByteArrayInputStream(baos
          .toByteArray()), charset, readStyle, recType, rpm);
    } else
      throw new Exception("unsupported JMS message type " + jmsInMessage);
    return input;
  }

  public void transform(Object data, MessageExchange me) throws Exception {
    super.transform(data, me);
    // getting all properties from jmsInMessage and setting them to
    // NMExchange
    JMSMarshaler.addMetatataToNMExchange(me, jmsInMessage);
    // exchange = me;
  }

  @Override
  protected void doProcessFault(NormalizedMessage nm, String fault)
      throws JMSException, InterruptedException, ConfigurationException,Exception {
    // /if there is any kind of fault
    // message then just put the JMSMessage back in the queue
    recoverableInRetryFault=false;
    FaultHandler fh = new FaultHandler(fault);

    logger.info("Consumer endpoint '" + endpoint.getEndpoint()
        + "' reports error: " + fh.getMessage());
    if (fh.getEndpointString() != null)
      logger.info("The error was occured at the endpoint: "
          + fh.getEndpointString());

     logger.debug("Fault handler: isRecoverable="+fh.isRecoverable());

    if (fh.isRecoverable()) {
      faultType = FaultMessageTypes.RECOVERABLE;
      

      jmsHandler.rollback();
//      send notification
      endpoint.sendJMSTransactionRollBackNotification();

      logger
          .info("JMS Rollback in doProcessFault, fault is Recoverable");

      if (endpoint.isRetry()) { // if in retry mode
        logger.debug("JMS Is in retry Mode: retryInterval="
            + endpoint.getRetryInterval() + "; Retry's count=" + retrysCount.get());
        
        //Thread.sleep(retryInterval); // wait a while,
        synchronized(retrysCount)
        {
          retrysCount.incrementAndGet();  // decreasing retrys left
          retrysCount.notify();
        }
        // stop message pooling
        if (retrysCount.get() >=endpoint.getMaxRetryCount()){
          logger.info("retry count exceeded");
          doStop(true);
          //send notification
          logger.debug("send notification :retry count exceeded");
          endpoint.sendJMSRetryCountExceededNotification();
          logger.debug("set state:retry stooped");
        }else
        {
          recoverableInRetryFault=true;
          endpoint.setState(StatusConstants.STATUS_RETRY_STARTED);
            
        }
      } else // if in noRetry mode and recoverable fault
      // then just stop the component and roll back
      {
        doStop(false);
  
      }

    } else {
      faultType = FaultMessageTypes.UNRECOVERABLE;
            logger.debug("before write to DLQ");
            jmsHandler.writeToDLQ(jmsInMessage);
            logger.debug("after write to DLQ");
//          send notification
            endpoint.sendJMSDLQNotification();
            logger.debug("after sent DLQ notification");
          jmsHandler.commit();
      logger.info("JMS Commit in doProcessFault, Fault is Urecoverable");
    }
  }

  /*
   * Process out situation
   * 
   * @see com.bostechcorp.cbesb.runtime.ccsl.jbi.messaging.BaseConsumerProcessor#doProcessOut(javax.jbi.messaging.NormalizedMessage,
   *      java.lang.String)
   */
  @Override
  protected void doProcessOut(NormalizedMessage nm, String s,
      MessageExchange exchange) throws JMSException,
      ConfigurationException, TransformerConfigurationException,
      IOException, TransformerException {
    String charset = endpoint.getCharset();

    //TODO: does reply in consumer need to check savaMetadata 
    Message jmsReply = JMSMarshaler.normalizedToJMS(exchange
        .getMessage("out"), exchange, endpoint.getWriteStyle(),
        charset, jmsHandler.getSession(),false);
    // getting all properties from mExchange and setting them to the
    // jms message
    // JMSMarshaler.addMetatataToJms(jmsReply, exchange);

    // sending the message to reply queue
    jmsHandler.reply(jmsInMessage, jmsReply);
    // Process the Out message and write it into the reply queue.
  }

  /* (non-Javadoc)
   * @see com.bostechcorp.cbesb.runtime.ccsl.jbi.messaging.CbConsumerProcessor#doProcessFault(javax.jbi.messaging.NormalizedMessage)
   */
  @Override
  protected String doProcessFault(NormalizedMessage nm) throws JBIException,
  CbesbException {
    //needs to be overwritten because of the bug 474
    String fault = null;
    if (nm != null) {
      fault = SourceHelper.createString(nm.getContent());
    }
    try {
      doProcessFault(nm, fault);
      //since version 1.2b
      if (recoverableInRetryFault) return "retry";
      //
    } catch (Exception e) {
      throw CbesbException.create(e);
    }
    return fault;
  }
  
  /**
   * Print out at DEBUG level, jms message properties 
   * @param msg
   * @throws JMSException
   */
  protected void debugJmsMessageProperties(Message msg) throws JMSException
  {
    Enumeration enumeration=msg.getPropertyNames();
    String result="JMS Message Properies:\n";
    while (enumeration.hasMoreElements())
    {
      String propName =(String)enumeration.nextElement();
      Object propValue = msg.getObjectProperty(propName);
      result+=("["+propName+"]"+"="+propValue)+"\n";
    }
    result+=("JMS Message Properies:(endprint)--->")+"\n";
    logger.debug(result);
  }
  
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.