org.opentaps.foundation.infrastructure.Infrastructure.java Source code

Java tutorial

Introduction

Here is the source code for org.opentaps.foundation.infrastructure.Infrastructure.java

Source

/*
 * Copyright (c) Open Source Strategies, Inc.
 *
 * Opentaps is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Opentaps 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Opentaps.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.opentaps.foundation.infrastructure;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javolution.util.FastMap;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.event.DeleteEventListener;
import org.hibernate.event.LoadEventListener;
import org.hibernate.event.PersistEventListener;
import org.hibernate.event.SaveOrUpdateEventListener;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.metadata.CollectionMetadata;
import org.hibernate.persister.entity.EntityPersister;
import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.UtilMisc;
import org.ofbiz.entity.Delegator;
import org.ofbiz.entity.DelegatorFactory;
import org.ofbiz.entity.GenericEntityException;
import org.ofbiz.entity.GenericValue;
import org.ofbiz.entity.config.DatasourceInfo;
import org.ofbiz.entity.config.EntityConfigUtil;
import org.ofbiz.security.Security;
import org.ofbiz.service.LocalDispatcher;
import org.opentaps.base.entities.OpentapsConfiguration;
import org.opentaps.base.entities.OpentapsConfigurationType;
import org.opentaps.foundation.entity.hibernate.EcaDeleteEventListener;
import org.opentaps.foundation.entity.hibernate.EcaLoadEventListener;
import org.opentaps.foundation.entity.hibernate.EcaPersistEventListener;
import org.opentaps.foundation.entity.hibernate.EcaSaveEventListener;
import org.opentaps.foundation.entity.hibernate.EcaSaveOrUpdateEventListener;
import org.opentaps.foundation.entity.hibernate.Session;

/**
 * These are the fundamental infrastructure Resources used by opentaps, including the ofbiz dispatcher, delegator,
 * security objects and Hibernate sessions for each delegator.  Typically, all the OFBiz business tier
 * infrastructure can be obtained from their GenericDispatcher.
 *
 */
public class Infrastructure {

    private static final String MODULE = Infrastructure.class.getName();

    private LocalDispatcher dispatcher = null;
    private Delegator delegator = null;
    private Security security = null;
    private GenericValue systemUserLogin = null; // Sometimes, the system user must be used by the Factory or Repository that use the ofbiz Infrastructure
    private User systemUser = null;

    // create this map for store all of session factory
    private static Map<String, SessionFactory> sessionFactories = FastMap.newInstance();
    /** Hibernate dialects maps. */
    public static final HashMap<String, String> DIALECTS = new HashMap<String, String>();
    private static final String HELPER_NAME = "org.ofbiz";
    static {
        DIALECTS.put("hsql", "org.hibernate.dialect.HSQLDialect");
        DIALECTS.put("derby", "org.hibernate.dialect.DerbyDialect");
        DIALECTS.put("mysql", "org.opentaps.foundation.entity.hibernate.OpentapsMySQLDialect");
        DIALECTS.put("postgres", "org.hibernate.dialect.PostgreSQLDialect");
        DIALECTS.put("postnew", "org.hibernate.dialect.PostgreSQLDialect");
        DIALECTS.put("oracle", "org.hibernate.dialect.OracleDialect");
        DIALECTS.put("sapdb", "org.hibernate.dialect.SAPDBDialect");
        DIALECTS.put("sybase", "org.hibernate.dialect.SybaseDialect");
        DIALECTS.put("firebird", "org.hibernate.dialect.FirebirdDialect");
        DIALECTS.put("mssql", "org.hibernate.dialect.SQLServerDialect");

        DIALECTS.put("cloudscape", ""); //not exist mapping Dialect
        DIALECTS.put("daffodil", ""); //not exist mapping Dialect
        DIALECTS.put("axion", ""); //not exist mapping Dialect
        DIALECTS.put("advantage", ""); //not exist mapping Dialect
    }
    /** Hibernate configuration file store path. */
    public static final String HIBERNATE_CFG_PATH = "opentaps/opentaps-common/config/";
    /** Hibernate configuration template path. */
    public static final String HIBERNATE_COMMON_PATH = "opentaps/opentaps-common/config/hibernate.cfg.xml";
    /** Hibernate configuration template path. */
    public static final String HIBERNATE_SEARCH_INDEX_PATH = "runtime/lucene/indexes";
    /** Hibernate configuration file ext. */
    public static final String HIBERNATE_CFG_EXT = ".cfg.xml";
    /** Hibernate entity package name. */
    public static final String ENTITY_PACKAGE = "org.opentaps.base.entities";

    /**
     * Gets the Hibernate <code>SessionFactory</code> object for the corresponding delegator.
     * A Map of delegatorName to SessionFactory is maintained, and the first time a SessionFactory is requested for.
     * A delegatorName, it is created in the the following way:
     * <ul>
     * <li>First, get the data source for the group helper (ie, "org.ofbiz" in entitygroup.xml) and that delegator</li>
     * <li>Then, get the hibernate cfg xml for the data source</li>
     * <li>Finally, use that hibernate cfg xml to create a SessionFactory</li>
     * </ul>
     * @param delegatorName a <code>String</code> value
     * @return a Hibernate <code>SessionFactory</code> value
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static synchronized SessionFactory getSessionFactory(String delegatorName) {
        SessionFactory sessionFactory = sessionFactories.get(delegatorName);
        // the sessionFactory haven't init before
        if (sessionFactory == null) {
            Debug.logVerbose("building hibernate SessionFactory ...", MODULE);
            AnnotationConfiguration annotationConfiguration = new AnnotationConfiguration();
            Delegator delegator = DelegatorFactory.getDelegator(delegatorName);
            //for support eccas, construct persist event listener arrays
            PersistEventListener[] persistEventListeners = { new EcaPersistEventListener(delegator) };
            //for support eccas, construct load event listener arrays
            LoadEventListener[] loadEventListeners = { new EcaLoadEventListener(delegator) };
            //for support eccas, construct delete event listener arrays
            DeleteEventListener[] deleteEventListeners = { new EcaDeleteEventListener(delegator) };
            //for support eccas, construct saveOrUpdate event listener arrays
            SaveOrUpdateEventListener[] saveOrUpdateEventListeners = {
                    new EcaSaveOrUpdateEventListener(delegator) };
            //for support eccas, construct saveOrUpdate event listener arrays
            SaveOrUpdateEventListener[] saveEventListeners = { new EcaSaveEventListener(delegator) };
            //register our event listener arrays
            annotationConfiguration.getEventListeners().setPersistEventListeners(persistEventListeners);
            annotationConfiguration.getEventListeners().setSaveOrUpdateEventListeners(saveOrUpdateEventListeners);
            annotationConfiguration.getEventListeners().setDeleteEventListeners(deleteEventListeners);
            annotationConfiguration.getEventListeners().setLoadEventListeners(loadEventListeners);
            annotationConfiguration.getEventListeners().setSaveEventListeners(saveEventListeners);
            annotationConfiguration.getEventListeners().setUpdateEventListeners(saveOrUpdateEventListeners);
            //get groupHelpName for retrieve database connection information.
            String groupHelperName = EntityConfigUtil.getDelegatorInfo(delegatorName).groupMap.get(getHelperName());
            Debug.logVerbose("groupHelperName : " + groupHelperName, MODULE);
            //get database source information
            DatasourceInfo datasourceInfo = EntityConfigUtil.getDatasourceInfo(groupHelperName);
            Debug.logVerbose("datasourceInfo.fieldTypeName : " + datasourceInfo.fieldTypeName, MODULE);
            //get hibernate dialect by database type
            String dialect = DIALECTS.get(datasourceInfo.fieldTypeName);
            if (dialect.length() == 0) {
                // some rarely used types are not supported
                Debug.logError("No hibernate dialect defined for the type [" + datasourceInfo.fieldTypeName + "]",
                        MODULE);
                return null;
            }
            annotationConfiguration.setProperty("hibernate.dialect", dialect);
            Debug.logVerbose("configuring SessionFactory ...", MODULE);
            //build a sessionFactory
            String datasourceName = EntityConfigUtil.getDelegatorInfo(delegatorName).groupMap.get(getHelperName());
            Debug.logVerbose("init sessionFactory by datasoure " + datasourceName, MODULE);
            sessionFactory = annotationConfiguration.configure(datasourceName + HIBERNATE_CFG_EXT)
                    .buildSessionFactory();
            Debug.logVerbose("listing loaded entities ...", MODULE);
            //iterator all classes which are success load of hibernate, it just only for debug use.
            if (Debug.isOn(Debug.VERBOSE)) {
                Map metadata = sessionFactory.getAllClassMetadata();
                for (Iterator<EntityPersister> i = metadata.values().iterator(); i.hasNext();) {
                    EntityPersister persister = i.next();
                    String className = persister.getClassMetadata().getEntityName();
                    Debug.logVerbose("SessionFactory Successfully Loaded AnnotatedClass : " + className, MODULE);
                }
            }
            sessionFactories.put(delegatorName, sessionFactory);
        }
        return sessionFactory;
    }

    /**
     * Gets the Hibernate <code>Session</code> object, it return an open session from the getSessionFactory
     * using the delegator already in this Infrastructure object.
     * @return a Hibernate <code>Session</code> value
     * @throws InfrastructureException if an error occurs
     */
    public Session getSession() throws InfrastructureException {
        org.hibernate.Session hibernateSession = getSessionFactory(delegator.getDelegatorName()).openSession();
        Session session = new Session(hibernateSession, delegator);
        return session;
    }

    /**
     * Gets the helper name, which is used to map a datasource to a set of entities in the ofbiz entity engine.
     * Currently this just returns the static HELPER_NAME defined in the class,
     * but it's here in case later we need more sophisticated ways to get the helper name.
     * @return a <code>String</code> value
     */
    public static String getHelperName() {
        return HELPER_NAME;
    }

    /**
     * Constructor.
     * @param dispatcher a <code>LocalDispatcher</code> value
     * @exception IllegalArgumentException if the given dispatcher is <code>null</code>
     */
    public Infrastructure(LocalDispatcher dispatcher) throws IllegalArgumentException {
        if (dispatcher == null) {
            throw new IllegalArgumentException("Cannot instantiate Infrastructure from null dispatcher");
        }
        this.dispatcher = dispatcher;
        this.delegator = dispatcher.getDelegator();
        this.security = dispatcher.getSecurity();
    }

    /**
     * Constructor.
     * @param delegator a <code>Delegator</code> value
     * @exception IllegalArgumentException if the given dispatcher is <code>null</code>
     */
    public Infrastructure(Delegator delegator) throws IllegalArgumentException {
        if (delegator == null) {
            throw new IllegalArgumentException("Cannot instantiate Infrastructure from null delegator");
        }
        this.delegator = delegator;
    }

    /**
     * Gets the <code>Security</code> object.
     * @return a <code>Security</code> value
     */
    public Security getSecurity() {
        return this.security;
    }

    /**
     * Gets the <code>LocalDispatcher</code> object.
     * @return a <code>LocalDispatcher</code> value
     */
    public LocalDispatcher getDispatcher() {
        return this.dispatcher;
    }

    /**
     * Gets the <code>Delegator</code> object.
     * @return a <code>Delegator</code> value
     */
    public Delegator getDelegator() {
        return this.delegator;
    }

    /**
     * Loads the system user login for Repositories and Factories that use this Infrastructure, plus all their sub-classes.
     */
    private void loadSystemUserLogin() {
        try {
            this.systemUserLogin = delegator.findByPrimaryKeyCache("UserLogin",
                    UtilMisc.toMap("userLoginId", "system"));
            if (this.systemUserLogin == null) {
                throw new IllegalStateException(
                        "Could not find the [system] UserLogin, it was either not loaded yet or missing.");
            }
            this.systemUser = new User(this.systemUserLogin, delegator);
        } catch (GenericEntityException e) {
            throw new IllegalStateException(e);
        }
    }

    /**
     * Gets the system UserLogin for Factories and Repositories that need them.
     * @return the system <code>UserLogin</code> <code>GenericValue</code>
     */
    public GenericValue getSystemUserLogin() {
        if (systemUserLogin == null) {
            loadSystemUserLogin();
        }
        return systemUserLogin;
    }

    /**
     * Gets the system User for Factories and Repositories that need them.
     * @return the system <code>User</code>
     */
    public User getSystemUser() {
        if (systemUser == null) {
            loadSystemUserLogin();
        }
        return systemUser;
    }

    /**
     * Gets a User object by user's login.
     * @return an instance of the <code>User</code>
     */
    public User getUserFromLogin(String login) {
        try {
            GenericValue userLogin = delegator.findByPrimaryKeyCache("UserLogin",
                    UtilMisc.toMap("userLoginId", login));
            if (userLogin == null) {
                throw new IllegalStateException(String.format(
                        "Could not find the [%1$s] UserLogin, it was either not loaded yet or missing.", login));
            }
            return new User(userLogin, delegator);
        } catch (GenericEntityException e) {
            throw new IllegalStateException(e);
        }
    }

    /**
     * Gets a configuration description from the database.
     * @param configTypeId the config type to get
     * @return a <code>String</code> value
     * @exception InfrastructureException if an error occurs
     */
    public String getConfigurationDescription(String configTypeId) throws InfrastructureException {
        Session session = getSession();
        try {
            OpentapsConfigurationType configuration = (OpentapsConfigurationType) session
                    .get(OpentapsConfigurationType.class, configTypeId);
            if (configuration == null) {
                return null;
            }
            return configuration.getDescription();
        } finally {
            session.close();
        }
    }

    /**
     * Gets a configuration value from the database with null default value.
     * @param configTypeId the config type to get
     * @return a <code>String</code> value
     * @exception InfrastructureException if an error occurs
     */
    public String getConfigurationValue(String configTypeId) throws InfrastructureException {
        return getConfigurationValue(configTypeId, null);
    }

    /**
     * Gets a configuration value from the database.  If it's not configured, use user supplied defaultValue, then OpentapsConfigurationType.defaultValue
     * @param configTypeId the config type to get
     * @param defaultValue the value to return if no configuration is set
     * @return a <code>String</code> value
     * @exception InfrastructureException if an error occurs
     */
    public String getConfigurationValue(String configTypeId, String defaultValue) throws InfrastructureException {
        Session session = getSession();
        try {
            OpentapsConfiguration configuration = (OpentapsConfiguration) session.get(OpentapsConfiguration.class,
                    configTypeId);
            if (configuration == null) {
                if (defaultValue != null) {
                    // if user supplied a non-null defaultValue, then use it
                    Debug.logWarning("No value found for configuration [" + configTypeId
                            + "] returning a default of [" + defaultValue + "]", MODULE);
                    return defaultValue;
                } else {
                    // use the default value of the configuration type
                    OpentapsConfigurationType configurationType = (OpentapsConfigurationType) session
                            .get(OpentapsConfigurationType.class, configTypeId);
                    if (configurationType != null) {
                        Debug.logWarning("No value found for configuration [" + configTypeId
                                + "] returning a default of [" + configurationType.getDefaultValue() + "]", MODULE);
                        return configurationType.getDefaultValue();
                    } else {
                        Debug.logWarning("No configuration type [" + configTypeId + "] returning null", MODULE);
                        return null;
                    }
                }
            }
            return configuration.getValue();
        } finally {
            session.close();
        }
    }

    /**
     * Gets a configuration value as boolean from the database with null default value.
     * This is a convenience method to get the common Y/N flags configuration values.
     * @param configTypeId the config type to get
     * @return <code>TRUE</code> if the config value is Y/y, <code>FALSE</code> otherwise (including for null values)
     * @exception InfrastructureException if an error occurs
     */
    public Boolean getConfigurationValueAsBoolean(String configTypeId) throws InfrastructureException {
        return "Y".equalsIgnoreCase(getConfigurationValue(configTypeId));
    }

    /**
     * Gets a configuration value as boolean from the database with null default value.
     * This is a convenience method to get the common Y/N flags configuration values.
     * @param configTypeId the config type to get
     * @param defaultValue the value to return if no configuration is set
     * @return <code>TRUE</code> if the config value is Y/y, <code>FALSE</code> for any other non empty values, <code>defaultValue</code> if no configuration set
     * @exception InfrastructureException if an error occurs
     */
    public Boolean getConfigurationValueAsBoolean(String configTypeId, Boolean defaultValue)
            throws InfrastructureException {
        String configValue = getConfigurationValue(configTypeId);
        if (configValue == null || configValue.length() == 0) {
            return defaultValue;
        } else {
            return "Y".equalsIgnoreCase(configValue);
        }
    }

    /**
     * Sets the configuration value for a configTypeId inside its own transaction.
     * @param configTypeId a <code>String</code> value
     * @param value a <code>String</code> value
     * @param comments a <code>String</code> value
     * @exception InfrastructureException if an error occurs
     */
    public void setConfigurationValue(String configTypeId, String value, String comments)
            throws InfrastructureException {
        Session session = getSession();
        // we should check if exists OpentapsConfiguration firstly
        OpentapsConfiguration configuration = (OpentapsConfiguration) session.get(OpentapsConfiguration.class,
                configTypeId);
        if (configuration == null) {
            configuration = new OpentapsConfiguration();
        }
        configuration.setConfigTypeId(configTypeId);
        configuration.setValue(value);
        configuration.setComments(comments);
        // saveOrUpdate will try to update when id not null, so we should use save to instead of it.
        session.save(configuration);
        session.flush();
        session.close();
    }

    /**
     * Evict all entries of entityName from the second-level cache.
     * @param entityName a <code>String</code> value
     */
    public void evictHibernateCache(String entityName) {
        evictHibernateCache(entityName, null);
    }

    /**
     * Evict an entry from the second-level cache.
     * @param entityName the name of the entity
     * @param id a <code>Serializable</code> instance
     */
    public void evictHibernateCache(String entityName, Serializable id) {
        if (entityName.indexOf(".") < 0) {
            // if entity name haven't package, then add it
            entityName = ENTITY_PACKAGE + "." + entityName;
        }
        try {
            Class<?> persistentClass = Class.forName(entityName);
            evictHibernateCache(persistentClass, id);
        } catch (ClassNotFoundException e) {
            Debug.logError(e, MODULE);
        }
    }

    /**
     * Evict all entries of persistentClass from the second-level cache.
     * @param persistentClass a <code>Class</code> instance
     */
    public void evictHibernateCache(Class<?> persistentClass) {
        evictHibernateCache(persistentClass, null);
    }

    /**
     * Evict an entry from the second-level cache.
     * @param persistentClass a <code>Class</code> instance
     * @param id a <code>Serializable</code> instance
     */
    public void evictHibernateCache(Class<?> persistentClass, Serializable id) {
        SessionFactory sessionFactory = sessionFactories.get(delegator.getDelegatorName());
        evictHibernateCache(sessionFactory, persistentClass, id);
    }

    /**
     * Evict an entry from the second-level cache.
     * @param sessionFactory a <code>SessionFactory</code> instance
     * @param persistentClass a <code>Class</code> instance
     * @param id a <code>Serializable</code> instance
     */
    public void evictHibernateCache(SessionFactory sessionFactory, Class<?> persistentClass, Serializable id) {
        if (sessionFactory != null) {
            ClassMetadata classMetadata = sessionFactory.getClassMetadata(persistentClass);
            // ensure the persistentClass is an entity class
            if (classMetadata != null) {
                if (id == null) {
                    sessionFactory.evict(persistentClass);
                } else {
                    sessionFactory.evict(persistentClass, id);
                }
            }
        }
    }

    /**
     * Clear hibernate second-level cache.
     */
    public void evictHibernateCache() {
        SessionFactory sessionFactory = sessionFactories.get(delegator.getDelegatorName());
        evictHibernateCache(sessionFactory);
    }

    /**
     * Clear hibernate second-level cache.
     * @param sessionFactory a <code>SessionFactory</code> instance
     */
    @SuppressWarnings("unchecked")
    public void evictHibernateCache(SessionFactory sessionFactory) {
        if (sessionFactory != null) {
            Map<String, CollectionMetadata> roleMap = sessionFactory.getAllCollectionMetadata();
            for (String roleName : roleMap.keySet()) {
                sessionFactory.evictCollection(roleName);
            }
            Map<String, ClassMetadata> entityMap = sessionFactory.getAllClassMetadata();
            for (String entityName : entityMap.keySet()) {
                sessionFactory.evictEntity(entityName);
            }
            sessionFactory.evictQueries();
        }
    }
}