Package org.activemq.store.jdbc

Source Code of org.activemq.store.jdbc.JDBCPersistenceAdapter

/**
*
* Copyright 2004 Hiram Chirino
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**/
package org.activemq.store.jdbc;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;

import javax.jms.JMSException;
import javax.sql.DataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.activemq.io.WireFormat;
import org.activemq.io.impl.StatelessDefaultWireFormat;
import org.activemq.store.MessageStore;
import org.activemq.store.PersistenceAdapter;
import org.activemq.store.TopicMessageStore;
import org.activemq.store.TransactionStore;
import org.activemq.store.jdbc.adapter.DefaultJDBCAdapter;
import org.activemq.store.vm.VMTransactionStore;
import org.activemq.util.FactoryFinder;
import org.activemq.util.JMSExceptionHelper;

import EDU.oswego.cs.dl.util.concurrent.ClockDaemon;
import EDU.oswego.cs.dl.util.concurrent.ThreadFactory;

/**
* A {@link PersistenceAdapter} implementation using JDBC for
* persistence storage.
*
* This persistence adapter will correctly remember prepared XA transactions,
* but it will not keep track of local transaction commits so that operations
* performed against the Message store are done as a single uow.
*
* @version $Revision: 1.1 $
*/
public class JDBCPersistenceAdapter implements PersistenceAdapter {

    private static final Log log = LogFactory.getLog(JDBCPersistenceAdapter.class);
    private static FactoryFinder factoryFinder = new FactoryFinder("META-INF/services/org/activemq/store/jdbc/");

    private WireFormat wireFormat = new StatelessDefaultWireFormat();
    private DataSource dataSource;
    private JDBCAdapter adapter;
  private String adapterClass;
  private VMTransactionStore transactionStore;
    private boolean dropTablesOnStartup=false;
    private ClockDaemon clockDaemon;
    private Object clockTicket;

    public JDBCPersistenceAdapter() {
    }

    public JDBCPersistenceAdapter(DataSource ds, WireFormat wireFormat) {
        this.dataSource = ds;
        this.wireFormat = wireFormat;
    }

    public Map getInitialDestinations() {
        return null;
    }

    public MessageStore createQueueMessageStore(String destinationName) throws JMSException {
        if (adapter == null) {
            throw new IllegalStateException("Not started");
        }
        MessageStore store = new JDBCMessageStore(this, adapter, wireFormat.copy(), destinationName);
        if( transactionStore!=null ) {
            store = transactionStore.proxy(store);
        }
        return store;
    }

    public TopicMessageStore createTopicMessageStore(String destinationName) throws JMSException {
        if (adapter == null) {
            throw new IllegalStateException("Not started");
        }
        TopicMessageStore store = new JDBCTopicMessageStore(this, adapter, wireFormat.copy(), destinationName);
        if( transactionStore!=null ) {
            store = transactionStore.proxy(store);
        }
        return store;
    }

    public TransactionStore createTransactionStore() throws JMSException {
        if (adapter == null) {
            throw new IllegalStateException("Not started");
        }
        if( this.transactionStore == null ) {
            this.transactionStore = new VMTransactionStore();
        }
        return this.transactionStore;
    }

    public void beginTransaction() throws JMSException {
        try {
            Connection c = dataSource.getConnection();
            c.setAutoCommit(false);
            TransactionContext.pushConnection(c);
        }
        catch (SQLException e) {
            throw JMSExceptionHelper.newJMSException("Failed to create transaction: " + e, e);
        }
    }

    public void commitTransaction() throws JMSException {
        Connection c = TransactionContext.popConnection();
        if (c == null) {
            log.warn("Commit while no transaction in progress");
        }
        else {
            try {
                c.commit();
            }
            catch (SQLException e) {
                throw JMSExceptionHelper.newJMSException("Failed to commit transaction: " + c + ": " + e, e);
            }
            finally {
                try {
                    c.close();
                }
                catch (Throwable e) {
                }
            }
        }
    }

    public void rollbackTransaction() {
        Connection c = TransactionContext.popConnection();
        try {
            c.rollback();
        }
        catch (SQLException e) {
            log.warn("Cannot rollback transaction due to: " + e, e);
        }
        finally {
            try {
                c.close();
            }
            catch (Throwable e) {
            }
        }
    }


    public void start() throws JMSException {
        beginTransaction();
        Connection c = null;
        try {
            // Load the right adapter for the database
            adapter = null;

            try {
              c = getConnection();
            }
            catch (SQLException e) {
                throw JMSExceptionHelper.newJMSException("Could not get a database connection: "+e,e);                                
            }

            // If the adapter class is not specified.. try to dectect they right type by getting
            // info from the database.
            if( adapterClass == null ) {
             
                try {
   
                  // Make the filename file system safe.
                  String dirverName = c.getMetaData().getDriverName();
                  dirverName = dirverName.replaceAll("[^a-zA-Z0-9\\-]", "_").toLowerCase();
 
                  try {
                    adapter = (DefaultJDBCAdapter) factoryFinder.newInstance(dirverName);
                        log.info("Database driver recognized: [" + dirverName + "]");
                  }
                  catch (Throwable e) {
                      log.warn("Database driver NOT recognized: [" + dirverName + "].  Will use default JDBC implementation.");
                  }
                   
              }
              catch (SQLException e) {
                    log.warn("JDBC error occured while trying to detect database type.  Will use default JDBC implementation: "+e.getMessage());
                    log.debug("Reason: " + e, e);                   
              }
             
            } else {
                try {
                  Class clazz = JDBCPersistenceAdapter.class.getClassLoader().loadClass(adapterClass);
                  adapter = (DefaultJDBCAdapter)clazz.newInstance();
                }
                catch (Throwable e) {
                    log.warn("Invalid JDBC adapter class class (" + adapterClass + ").  Will use default JDBC implementation.");
                    log.debug("Reason: " + e, e);
                }
            }
           
            // Use the default JDBC adapter if the
            // Database type is not recognized.
            if (adapter == null) {
                adapter = new DefaultJDBCAdapter();
            }

            if( dropTablesOnStartup ) {
                try {
                    adapter.doDropTables(c);
                }
                catch (SQLException e) {
                    log.warn("Cannot drop tables due to: " + e, e);
                }
            }
            try {
                adapter.doCreateTables(c);
            }
            catch (SQLException e) {
                log.warn("Cannot create tables due to: " + e, e);
            }
            adapter.initSequenceGenerator(c);

        }
        finally {
            commitTransaction();
        }
       
        // Cleanup the db periodically.
        clockTicket = getClockDaemon().executePeriodically(1000 * 60 * 5, new Runnable() {
            public void run() {
                cleanup();
            }
        }, false);
        cleanup();
    }

    protected void cleanup() {
        Connection c = null;
        try {
            log.debug("Cleaning up old messages.");
            c = getConnection();           
            adapter.doDeleteOldMessages(c);
        } catch (JMSException e) {
            log.warn("Old message cleanup failed due to: " + e, e);
        } catch (SQLException e) {
            log.warn("Old message cleanup failed due to: " + e, e);
        } finally {
            returnConnection(c);
            log.debug("Cleanup done.");
        }
    }
   
    public void setClockDaemon(ClockDaemon clockDaemon) {
        this.clockDaemon = clockDaemon;
    }

    public ClockDaemon getClockDaemon() {
        if (clockDaemon == null) {
            clockDaemon = new ClockDaemon();
            clockDaemon.setThreadFactory(new ThreadFactory() {
                public Thread newThread(Runnable runnable) {
                    Thread thread = new Thread(runnable, "Cleanup Timmer");
                    thread.setDaemon(true);
                    return thread;
                }
            });
        }
        return clockDaemon;
    }

    public synchronized void stop() throws JMSException {
        if (clockTicket != null) {
            // Stop the periodical cleanup.
            ClockDaemon.cancel(clockTicket);
            clockTicket=null;
            clockDaemon.shutDown();
        }
    }

    public DataSource getDataSource() {
        return dataSource;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public WireFormat getWireFormat() {
        return wireFormat;
    }

    public void setWireFormat(WireFormat wireFormat) {
        this.wireFormat = wireFormat;
    }

    public Connection getConnection() throws SQLException {
        Connection answer = TransactionContext.peekConnection();
        if (answer == null) {
            answer = dataSource.getConnection();
            answer.setAutoCommit(true);
        }
        return answer;
    }

    public void returnConnection(Connection connection) {
        if (connection == null) {
            return;
        }
        Connection peek = TransactionContext.peekConnection();
        if (peek != connection) {
            try {
                connection.close();
            }
            catch (SQLException e) {
            }
        }
    }
 
    /**
   * @return Returns the adapterClass.
   */
  public String getAdapterClass() {
    return adapterClass;
  }
 
  /**
   * @param adapterClass The adapterClass to set.
   */
  public void setAdapterClass(String adapterClass) {
    this.adapterClass = adapterClass;
  }
    /**
     * @return Returns the dropTablesOnStartup.
     */
    public boolean getDropTablesOnStartup() {
        return dropTablesOnStartup;
    }
    /**
     * @param dropTablesOnStartup The dropTablesOnStartup to set.
     */
    public void setDropTablesOnStartup(boolean dropTablesOnStartup) {
        this.dropTablesOnStartup = dropTablesOnStartup;
    }
}
TOP

Related Classes of org.activemq.store.jdbc.JDBCPersistenceAdapter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.