DBMessageStoreImpl.java :  » JBoss » jbossesb-4.7 » org » jboss » internal » soa » esb » persistence » format » db » Java Open Source

Java Open Source » JBoss » jbossesb 4.7 
jbossesb 4.7 » org » jboss » internal » soa » esb » persistence » format » db » DBMessageStoreImpl.java
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2006, JBoss 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.
 * 
 * (C) 2005-2006,
 * @author daniel.brum@jboss.com
 */

package org.jboss.internal.soa.esb.persistence.format.db;

import java.io.Serializable;
import java.net.URI;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.jboss.internal.soa.esb.message.urigen.DefaultMessageURIGenerator;
import org.jboss.internal.soa.esb.util.Encoding;
import org.jboss.soa.esb.Service;
import org.jboss.soa.esb.client.ServiceInvoker;
import org.jboss.soa.esb.common.Environment;
import org.jboss.soa.esb.common.ModulePropertyManager;
import org.jboss.soa.esb.listeners.message.MessageDeliverException;
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.message.urigen.MessageURIGenerator;
import org.jboss.soa.esb.persistence.manager.ConnectionManager;
import org.jboss.soa.esb.persistence.manager.ConnectionManagerException;
import org.jboss.soa.esb.persistence.manager.ConnectionManagerFactory;
import org.jboss.soa.esb.services.persistence.MessageStore;
import org.jboss.soa.esb.services.persistence.MessageStoreException;
import org.jboss.soa.esb.services.persistence.RedeliverStore;
import org.jboss.soa.esb.util.Util;

public class DBMessageStoreImpl implements RedeliverStore
{
    public static final String DEFAULT_TABLE_NAME = "message";
    public static final String UNCLASSIFIED_CLASSIFICATION = "NONE";
    
  private Logger logger = Logger.getLogger(this.getClass());

  protected ConnectionManager mgr = null;
    
    private Integer maxRedeliverCount = 10;
    private String tableName = DEFAULT_TABLE_NAME;
  
  protected MessageURIGenerator uriGenerator = new DefaultMessageURIGenerator();

  public DBMessageStoreImpl() throws ConnectionManagerException
  {
      mgr = ConnectionManagerFactory.getConnectionManager();
      
      tableName = ModulePropertyManager.getPropertyManager(ModulePropertyManager.DBSTORE_MODULE).getProperty(Environment.MSG_STORE_DB_TABLE_NAME, DEFAULT_TABLE_NAME);
  }

  /* (non-Javadoc)
   * @see org.jboss.soa.esb.services.persistence.MessageStore#getMessageURIGenerator()
   */
  public MessageURIGenerator getMessageURIGenerator() {
    return uriGenerator;
  }

  /**
   * add's a @Message to the database persistence store
   * will set the 'delivered' flag to TRUE by default - assuming that the @Message has been delivered
   * If classification is null or "", then NONE will be used.
   */
  public synchronized URI addMessage (Message message, String classification) throws MessageStoreException
  {
    URI uid = null;
        Connection conn=null;
    try{
      conn = mgr.getConnection();
      uid = uriGenerator.generateMessageURI(message);
      
      if ((classification == null) || (classification.equals("")))
        classification = UNCLASSIFIED_CLASSIFICATION;
      
            insert(uid, message, classification, "TRUE", conn);
    }
    catch (Exception e)
    {
      logger.error(e);
      throw new MessageStoreException(e);
    } 
    finally
    {
      release(conn);
    }
    return uid;
  }

  /**
   * return a @Message based on the passed in key in the form of a JBoss ESB @URI
   * format for URI: "urn:jboss/esb/message/UID#" + UUID.randomUUID()" - see the method in this class @addMessage
   */
  public synchronized Message getMessage (URI uid)
      throws MessageStoreException
  {
    Message message = null;
        Connection conn=null;
    try {
      conn = mgr.getConnection();
      message =  select(uid, conn);
    } catch (Exception e) {
      throw new MessageStoreException(e);
    } finally {
      release(conn);
    }
    return message;
  }
    
    /**
     * return a @Message based on the passed in key in the form of a JBoss ESB @URI
     * format for URI: "urn:jboss/esb/message/UID#" + UUID.randomUUID()" - see the method in this class @addMessage
     */
    public synchronized Message getMessage (URI uid, String classification)
            throws MessageStoreException
    {
        Message message = null;
        Connection conn=null;
        try {
            conn = mgr.getConnection();
            message =  select(uid, classification, conn);
        } catch (Exception e) {
            throw new MessageStoreException(e);
        } finally {
            release(conn);
        }
        return message;
    }
    
    /**
     * remove a @Message based on the passed in key in the form of a JBoss ESB @URI
     * format for URI: "urn:jboss/esb/message/UID#" + UUID.randomUUID()" - see the method in this class @removeMessage
     * If classification is null or "", then NONE will be used.
     */
    public synchronized int removeMessage (URI uid, String classification)
            throws MessageStoreException
    {
        int response;
        Connection conn=null;
        try {
            conn = mgr.getConnection();
            
            if ((classification == null) || (classification.equals("")))
              classification = UNCLASSIFIED_CLASSIFICATION;
            
            response =  delete(uid, classification, conn);
        } catch (Exception e) {
            throw new MessageStoreException(e);
        } finally {
            release(conn);
        }
        return response;
    }
  
  /**
   * 
   * @param uid - key for message to set undelivered flag on
   * @throws MessageStoreException
   */
  public void setUndelivered(URI uid) throws MessageStoreException
    {
    String sql = "update "+tableName+" set delivered = 'FALSE' where uuid=?";
        Connection conn=null;
    try {
      conn = mgr.getConnection();
            PreparedStatement ps = conn.prepareStatement(sql);
            try
            {
                ps.setString(1, uid.toString());
                ps.execute();
            }
            finally
            {
                ps.close();
            }
        } catch (Exception e) {
      throw new MessageStoreException(e);
    } finally {
      release(conn);
    }
    
  }
  
  public void setDelivered(URI uid) throws MessageStoreException{
    String sql = "update "+tableName+" set delivered = 'TRUE' where uuid=?";
        Connection conn=null;
    try {
      conn = mgr.getConnection();
            PreparedStatement ps = conn.prepareStatement(sql);
            try
            {
                ps.setString(1, "FALSE");
                ps.execute();
            }
            finally
            {
                ps.close() ;
            }
    } catch (Exception e) {
      throw new MessageStoreException(e);
    } finally {
      release(conn);
    }
  }
  
  /**
   * This method can be used to retrieve a collection of all the undelivered (delivered=FALSE) from the message-store
   * You should test for 'null' on the return type to see if any messages exist in the collection
   * @return Map<URI, Message> - a collection of all the undelivered messages in the message-store
   * @throws MessageStoreException
   */
  public Map<URI, Message> getUndeliveredMessages(String classification) throws MessageStoreException {
    HashMap<URI, Message> messages = new HashMap<URI, Message>();
    String sql = "select uuid from "+tableName+" where delivered='FALSE'";
        if (classification!=null) {
            sql += " and classification=?";
        }
        Connection conn=null;
    try
    {
      conn = mgr.getConnection();
      PreparedStatement stmt = null;
      ResultSet rs = null;
      try
      {
              stmt = conn.prepareStatement(sql);
              if (classification != null)
              {
                stmt.setString(1, classification) ;
              }
              rs = stmt.executeQuery();
              
              while (rs.next()) {
                URI uid = new URI(rs.getString(1));
                Message msg = getMessage(uid);
                messages.put(uid, msg);
              }
      }
      finally
      {
          try
          {
                  if (rs != null)
                rs.close();
          }
          catch (final Exception ex)
          {
        logger.warn("Could not close ResultSet.", ex);
          }
          
          try
          {
                  if (stmt != null)
                stmt.close();
          }
          catch (final Exception ex)
          {
        logger.warn("Could not close Statement.", ex);
          }
      }

    }
    catch (Exception e)
    {
      throw new MessageStoreException(e);
    } 
    finally
    {
      release(conn);
    }
    logger.info("retrieved " + messages.size() + " undelivered messages");
    return messages;
    
  }
    
    /**
     * This method can be used to retrieve a collection of all from the message-store
     * You should test for 'null' on the return type to see if any messages exist in the collection
     * @return Map<URI, Message> - a collection of all the undelivered messages in the message-store
     * @throws MessageStoreException
     */
    public Map<URI, Message> getAllMessages(String classification) throws MessageStoreException {
        HashMap<URI, Message> messages = new HashMap<URI, Message>();
        String sql = "select uuid, message from "+tableName;
        if (classification!=null) {
            sql += " where classification=?";
        }
        Connection conn=null;
        try
        {
            conn = mgr.getConnection();
            PreparedStatement stmt = null;
            ResultSet rs = null;
            
            try
            {
                stmt = conn.prepareStatement(sql);
                if (classification != null)
                {
                    stmt.setString(1, classification) ;
                }
                rs = stmt.executeQuery();
                
                while (rs.next()) {
                    URI uid = new URI(rs.getString(1));
                    Message msg = Util.deserialize((Serializable) Encoding.decodeToObject( rs.getString(2)));
                    messages.put(uid, msg);
                }
            }
            finally
            {
          try
        {
          if (rs != null)
        rs.close();
        }
        catch (final Exception ex)
        {
      logger.warn("Could not close ResultSet.", ex);
        }
        
        try
        {
          if (stmt != null)
        stmt.close();
        }
        catch (final Exception ex)
        {
      logger.warn("Could not close Statement.", ex);
        }
            }
        }
        catch (Exception e)
        {
            throw new MessageStoreException(e);
        } 
        finally
        {
            release(conn);
        }
        logger.debug("retrieved " + messages.size() + " " + classification + " messages");
        return messages;
        
    }

  private void release (Connection conn)
  {

    if (conn != null)
    {
      try
      {
        conn.close();
      }
      catch (Exception e2)
      {
                logger.warn(e2.getMessage(), e2);
      }
    }
  }
    /**
     * 
     */
    public boolean redeliver(URI uuid) throws MessageStoreException
    {
        boolean isDelivered=false;
        boolean error=false;

        Connection con = null;
        
        try
        {
            con = mgr.getConnection();
            con.setAutoCommit(false);
        }
        catch (final SQLException e)
        {
            if (logger.isDebugEnabled()) {
                logger.debug("dbms doesn't support setAutoCommit(false), deadlocks may occur under normal processing.");
                logger.debug(e.getMessage(), e);
            }
        } 
           
        try
        {
            Message message=select(uuid, con);
            
            if (message!=null && delete(uuid, RedeliverStore.CLASSIFICATION_RDLVR, con)==1) {
                //now any good db should have set a read lock on this record, until we commit.
                //if exception is thrown up the delivery count on the message
                //if exceeds the maxcount then update the classification to DLQ.
                Service to = (Service) message.getProperties().getProperty(ServiceInvoker.DELIVER_TO);
                try {
                    ServiceInvoker si = new ServiceInvoker(to.getCategory(), to.getName());
                    message.getProperties().setProperty(RedeliverStore.IS_REDELIVERY, true);
                    si.deliverAsync(message);
                    isDelivered=true;
                } catch (MessageDeliverException e) {
                    logger.debug(e.getMessage(), e);
                }
                
                if (isDelivered) {
                    //the message is delivered, we're good so remove it from the store
                    delete(uuid, RedeliverStore.CLASSIFICATION_RDLVR, con);
                } else {
                    //the message was not delivered
                    if (message.getProperties().getProperty(DELIVER_COUNT)==null) {
                        //apparently it was the first time
                        message.getProperties().setProperty(RedeliverStore.DELIVER_COUNT, Integer.valueOf("1"));
                        logger.debug("attempt 1 to redeliver " + uuid + " failed");
                        insert(uuid, message, MessageStore.CLASSIFICATION_RDLVR, "FALSE", con);
                    } else {
                        Integer redeliverCount = (Integer) message.getProperties().getProperty(DELIVER_COUNT);
                        if (redeliverCount < maxRedeliverCount || maxRedeliverCount < 0) {
                            //up the count
                            message.getProperties().setProperty(RedeliverStore.DELIVER_COUNT, ++redeliverCount);
                            logger.debug("attempt " + redeliverCount + " to redeliver " + uuid + " failed");
                            insert(uuid, message, MessageStore.CLASSIFICATION_RDLVR, "FALSE", con);
                        } else {
                            //undeliverable, send to the DLQ
                            logger.warn(" giving up and writing " + uuid + " to " + MessageStore.CLASSIFICATION_DLQ);
                            insert(uuid, message, MessageStore.CLASSIFICATION_DLQ, "FALSE", con);
                        }
                    }
                }
            }
        }
        catch (final SQLException e)
        {
            logger.warn("DBMessageStoreImpl caught exception "+e+". Will force transaction to rollback.");
            
            error=true;
        } 
        finally
        {
            if (con!=null) {
                try {
                    if (!error) {
                        con.commit();
                    } else {
                        con.rollback();
                    }
                } catch (SQLException e) {
                    logger.error(e);
                }
                try {
                    con.close();
                } catch (Exception e2) {
                    logger.error(e2);
                }
            }
        }
        return isDelivered; 
    }
    
    
    private Message select(URI uid, Connection connection) 
        throws SQLException, MessageStoreException
    {
        Message message=null;
        String selectSql = "select * from "+tableName+" where uuid=?";
        PreparedStatement selectStmt = null;
        ResultSet rs = null;
        
        try
        {
            selectStmt = connection.prepareStatement(selectSql);
            selectStmt.setObject(1, uid.toString());
            rs = selectStmt.executeQuery();
            
            if (rs.next()) {
                try {
                    message = Util.deserialize((Serializable) Encoding.decodeToObject(rs.getString("message")));
                } catch (Exception e) {
                    throw new MessageStoreException(e);
                }
            }
        }
        finally
        {
            try
      {
        if (rs != null)
      rs.close();
      }
      catch (final Exception ex)
      {
    logger.warn("Could not close ResultSet.", ex);
      }
      
      try
      {
        if (selectStmt != null)
      selectStmt.close();
      }
      catch (final Exception ex)
      {
    logger.warn("Could not close Statement.", ex);
      }
        }
        return message;
    }
    
    private Message select(URI uid, String classification, Connection connection) 
    throws SQLException, MessageStoreException
    {
        Message message=null;
        String selectSql = "select * from "+tableName+" where uuid=? and classification=?";
        PreparedStatement selectStmt = null;
        ResultSet rs = null;
        
        try
        {
            selectStmt = connection.prepareStatement(selectSql);
            selectStmt.setObject(1, uid.toString());
            selectStmt.setObject(2, classification);
            rs = selectStmt.executeQuery();
            
            if (rs.next()) {
                try {
                    message = Util.deserialize((Serializable) Encoding.decodeToObject(rs.getString("message")));
                } catch (Exception e) {
                    throw new MessageStoreException(e);
                }
            }
        }
        finally
        {
            try
      {
        if (rs != null)
      rs.close();
      }
      catch (final Exception ex)
      {
    logger.warn("Could not close ResultSet.", ex);
      }
      
      try
      {
        if (selectStmt != null)
      selectStmt.close();
      }
      catch (final Exception ex)
      {
    logger.warn("Could not close Statement.", ex);
      }
        }
        return message;
    }
    
    private int delete(URI uid, String classification, Connection connection)
        throws SQLException
    {
        String deleteSql = "delete from "+tableName+" where uuid=? and classification=?";
        PreparedStatement stmt = null;
        int result;
        
        try
        {
            stmt = connection.prepareStatement(deleteSql);
            
            stmt.setObject(1, uid.toString());
            stmt.setObject(2, classification);
            result = stmt.executeUpdate();
        }
        finally
        {
            try
            {
                if (stmt != null)
                stmt.close();
            }
            catch (final Exception ex)
            {
          logger.warn("Could not close Statement.", ex);
            }
        }
        
        return result;
    }
    
    private void insert(URI uid, Message message, String classification, String delivered, Connection conn) 
        throws SQLException, MessageStoreException
    {
        String sql = "insert into "+tableName+"(uuid, type, message, delivered, classification) values(?,?,?,?,?)";
        PreparedStatement ps = null;
        
        try
        {
            ps = conn.prepareStatement(sql);
            ps.setString(1, uid.toString());
            ps.setString(2, message.getType().toString());
            try {
                String messageString = Encoding.encodeObject(Util.serialize(message));
                ps.setString(3, messageString);
            } catch (Exception e) {
                throw new MessageStoreException(e);
            }
            ps.setString(4, "TRUE");
            ps.setString(5, classification);
            ps.execute();
        }
        finally
        {
            if (ps != null)
          ps.close();
        }
    }
    

    public Integer getMaxRedeliverCount() {
        return maxRedeliverCount;
    }

    public void setMaxRedeliverCount(Integer maxRedeliverCount) {
        this.maxRedeliverCount = maxRedeliverCount;
    }

}
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.