org.eurocarbdb.servlet.init.EurocarbApplicationContextHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.eurocarbdb.servlet.init.EurocarbApplicationContextHandler.java

Source

/*
*   EuroCarbDB, a framework for carbohydrate bioinformatics
*
*   Copyright (c) 2006-2009, Eurocarb project, or third-party contributors as
*   indicated by the @author tags or express copyright attribution
*   statements applied by the authors.  
*
*   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, as published by the Free Software Foundation.
*   A copy of this license accompanies this distribution in the file LICENSE.txt.
*
*   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 Lesser General Public License
*   for more details.
*
*   Last commit: $Rev: 1986 $ by $Author: glycoslave $ on $Date:: 2010-09-08 #$  
*/

package org.eurocarbdb.servlet.init;

//  stdlib imports
import java.util.Set;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;

//  3rd party imports
import org.apache.log4j.Logger;

import org.apache.commons.configuration.ConfigurationUtils;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.CompositeConfiguration;

import com.opensymphony.xwork.ActionProxyFactory;
import com.opensymphony.xwork.config.entities.ActionConfig;
import com.opensymphony.webwork.sitegraph.XWorkConfigRetriever;

//  eurocarb imports
import org.eurocarbdb.tranche.TrancheAdmin;

import org.eurocarbdb.dataaccess.Eurocarb;
import org.eurocarbdb.dataaccess.EntityManager;
import org.eurocarbdb.dataaccess.HibernateEntityManager;

import org.eurocarbdb.dataaccess.core.Contributor;
import org.eurocarbdb.dataaccess.core.GlycanSequence;
import org.eurocarbdb.dataaccess.core.BiologicalContext;
import org.eurocarbdb.dataaccess.core.Reference;
import org.eurocarbdb.dataaccess.core.Evidence;

//  static imports
import static org.eurocarbdb.util.StringUtils.join;
import static org.eurocarbdb.util.StringUtils.CR;

/**
*   This class is called when the Eurocarbdb web app context is started
*   or stopped. On startup, it is responsible for the following:
*<ol>
*   <li>Loading the eurocarbdb application properties file</li>
*   <li>Starting the Tranche server (global file system), 
*       if configured to do so ('ecdb.tranche.enabled' property)</li>
*   <li>Initialising Hibernate, and ensuring that the database 
*       is receiving connections and can be queried</li>
*   <li>Checking the current Action configuration is sane</li>
*</ol>
*
*   @author          mjh
*   @version         $Rev: 1986 $
*/
public class EurocarbApplicationContextHandler implements ServletContextListener {

    //~~~~~~~~~~~~~~~~~~~~~~ STATIC FIELDS ~~~~~~~~~~~~~~~~~~~~~~~~//

    /** Logging handle. */
    static final Logger log = Logger.getLogger(EurocarbApplicationContextHandler.class);

    /** Default name of app config file */
    public static final String ECDB_APP_PROPERTIES_FILE = "eurocarbdb-application.properties";

    //~~~~~~~~~~~~~~~~~~~~~~~~~~ FIELDS ~~~~~~~~~~~~~~~~~~~~~~~~~~~//

    //~~~~~~~~~~~~~~~~~~~~~~~~~~ METHODS ~~~~~~~~~~~~~~~~~~~~~~~~~~//

    /**
    *   Called when the servlet context is started. 
    *
    *   @see ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
    */
    public void contextInitialized(ServletContextEvent arg0) {
        initConfig();

        startTrancheIfNeeded();

        checkDataStore();

        checkActions();
    }

    /* (non-Javadoc)
    *   @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
    */
    public void contextDestroyed(ServletContextEvent arg0) {
        stopTrancheIfNeeded();
    }

    //~~~~~~~~~~~~~~~~~~~~~~~~ PRIVATE METHODS ~~~~~~~~~~~~~~~~~~~~//

    /**
    *   Iterates through the list of all currently known actions
    *   and checks that the action class is loadable.
    */
    protected void checkActions() {
        log.debug("checking actions...");

        StringBuilder sb = new StringBuilder();

        //  get current webwork config
        Set<String> namespaces = (Set<String>) XWorkConfigRetriever.getNamespaces();
        Set<String> action_names;

        for (String ns : namespaces) {
            action_names = (Set<String>) XWorkConfigRetriever.getActionNames(ns);
            sb.append(
                    "    namespace " + (ns.length() > 0 ? ns : '/') + " has " + action_names.size() + " actions\n");

            List<String> sorted_action_names = new ArrayList(action_names);
            Collections.sort(sorted_action_names);

            ActionConfig ac;
            Set<String> result_names;
            for (String action_name : sorted_action_names) {
                ac = XWorkConfigRetriever.getActionConfig(ns, action_name);
                String class_name = ac.getClassName();

                //  loading of action classes is somewhat redundant since it 
                //  appears to have already been done in first call to XWorkConfigRetriever
                try {
                    Class.forName(class_name);
                } catch (ClassNotFoundException ex) {
                    log.warn("Couldn't load action class for action '" + action_name + "': ", ex);
                }

                /*
                result_names = (Set<String>) ac.getResults().keySet();
                sb.append(
                "        "
                + action_name
                + " ("
                + join( ", ", result_names )
                + ")\n"
                );
                */
            }
        }

        log.info("action config OK:\n" + sb);

        return;
    }

    /**
    *   Checks that it's possible to connect to the (default) data
    *   store, start a transaction, and perform a basic query.
    */
    protected void checkDataStore() {
        log.debug("checking data store exists and is queryable...");
        try {
            EntityManager em = Eurocarb.getEntityManager();
            em.beginUnitOfWork();

            turn_genetic_query_optimiser_off();

            int count_cb = em.countAll(Contributor.class);
            int count_gs = em.countAll(GlycanSequence.class);
            int count_bc = em.countAll(BiologicalContext.class);
            int count_rf = em.countAll(Reference.class);
            int count_ev = em.countAll(Evidence.class);

            if (em.getQuery(Contributor.class.getName() + ".ACTIVE_ADMINISTRATORS").list().size() == 0) {
                throw new Exception(
                        "There are not active administrator users.\nCowardly refusing to start webapp\n");
            }

            em.endUnitOfWork();

            log.info(join("\n    ", "data store OK; default data store has:", count_cb + " contributor(s)",
                    count_gs + " glycan sequence(s)", count_bc + " biological context(s)",
                    count_rf + " reference(s)", count_ev + " evidence"));
        } catch (org.hibernate.MappingNotFoundException ex) {
            log.fatal("Could not query the data store: " + ex + "-- did you perhaps forget to add a new mapping "
                    + "file to the hibernate.cfg.xml?");
            throw new RuntimeException(ex);
        } catch (Exception ex) {
            log.fatal("Could not query the data store: " + ex);
            throw new RuntimeException(ex);
        }
    }

    /** 
    *   Effectively turn postgres genetic query optimiser off.
    *   This is *critical* for good performance of substructure queries. 
    *   This psql option can also be set via psql's own configuration 
    *   file but we set it here to make sure.
    */
    private void turn_genetic_query_optimiser_off() {
        int max = org.eurocarbdb.dataaccess.core.seq.SubstructureQuery.MAX_SUBSTRUCTURE_RESIDUES;
        try {
            log.debug("setting genetic query optimiser threshold to " + max);
            ((HibernateEntityManager) Eurocarb.getEntityManager()).getHibernateSession()
                    .createSQLQuery("set geqo_threshold = " + max).executeUpdate();
        } catch (Exception ex) {
            log.warn("Caught exception while turning off genetic query optimiser", ex);
        }
    }

    protected void startTrancheIfNeeded() {
        if (Eurocarb.getConfiguration().getBoolean("ecdb.tranche.enabled")) {
            log.info("starting the Tranche server (set ecdb.tranche.enabled=false to disable)");
            TrancheAdmin.StartServer();
        } else
            log.debug("Tranche not started (ecdb.tranche.enabled=false)");
    }

    protected void stopTrancheIfNeeded() {
        if (Eurocarb.getConfiguration().getBoolean("ecdb.tranche.enabled")) {
            log.info("shutting down the Tranche server");
            TrancheAdmin.StopServer();
        }
    }

    /**
    *   Loads the main application properties file, given by {@link ECDB_APP_PROPERTIES_FILE}.
    *   Note that core-api properties take precedence over application properties;
    *   ideally there shouldn't be any property name collisions in the first place.
    */
    protected void initConfig() {
        //  need to call getConfiguration before adding our config so 
        //  that core-api config gets initialised and logged first. 
        CompositeConfiguration config = Eurocarb.getConfiguration();

        log.info("adding eurocarbdb application configuration: " + ECDB_APP_PROPERTIES_FILE);
        try {
            config.addConfiguration(new PropertiesConfiguration(ECDB_APP_PROPERTIES_FILE));
        } catch (ConfigurationException ex) {
            throw new RuntimeException(ex);
        }

        if (log.isInfoEnabled()) {
            log.info("Configured eurocarb-application properties:\n" + CR + ConfigurationUtils.toString(config));
        }
    }

} // end class