EntityManagerFactoryBuilderImpl.java :  » J2EE » jfox » org » jfox » entity » Java Open Source

Java Open Source » J2EE » jfox 
jfox » org » jfox » entity » EntityManagerFactoryBuilderImpl.java
/*
 * JFox - The most lightweight Java EE Application Server!
 * more details please visit http://www.huihoo.org/jfox or http://www.jfox.org.cn.
 *
 * JFox is licenced and re-distributable under GNU LGPL.
 */
package org.jfox.entity;

import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.NamedNativeQueries;
import javax.persistence.NamedNativeQuery;
import javax.persistence.PersistenceException;
import javax.persistence.QueryHint;
import javax.sql.DataSource;
import javax.transaction.TransactionManager;

import org.apache.log4j.Logger;
import org.enhydra.jdbc.pool.StandardXAPoolDataSource;
import org.enhydra.jdbc.standard.StandardXADataSource;
import org.jfox.ejb3.naming.JNDIContextHelper;
import org.jfox.ejb3.transaction.JTATransactionManager;
import org.jfox.entity.cache.CacheConfig;
import org.jfox.framework.annotation.Service;
import org.jfox.framework.component.ASMClassLoader;
import org.jfox.framework.component.ActiveComponent;
import org.jfox.framework.component.Component;
import org.jfox.framework.component.ComponentContext;
import org.jfox.framework.component.ComponentInitialization;
import org.jfox.framework.component.ComponentUnregistration;
import org.jfox.framework.component.Module;
import org.jfox.framework.event.ModuleEvent;
import org.jfox.framework.event.ModuleListener;
import org.jfox.framework.event.ModuleLoadingEvent;
import org.jfox.framework.event.ModuleUnloadedEvent;
import org.jfox.util.XMLUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * @author <a href="mailto:jfox.young@gmail.com">Young Yang</a>
 */
@Service(id = "EntityManagerFactoryBuilder", active = true, singleton = true, priority = Integer.MIN_VALUE)
public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuilder, Component, ComponentInitialization, ComponentUnregistration, ModuleListener, ActiveComponent {

    protected static Logger logger = Logger.getLogger(EntityManagerFactoryBuilderImpl.class);

    private final static String PERSISTENCE_CONFIG_FILE = "META-INF/persistence.xml";

    //TransactionManager
    private TransactionManager transactionManager = null;


    /**
     * Entity Manager Factory Map
     * unit name => EntityManagerFactoryImpl
     */
    private static Map<String, EntityManagerFactoryImpl> emFactoryMap = new HashMap<String, EntityManagerFactoryImpl>();
    /**
     * query name => query template
     */
    private static Map<String, NamedSQLTemplate> namedSQLTemplates = new HashMap<String, NamedSQLTemplate>();

    private Document xmlDocument = null;

    private static boolean inited = false;
    private boolean containerManaged = true;

    private EntityTransaction entityTransaction = null;

    public static final String DEFAULT_UNITNAME = "default";
    public static final String QUERY_HINT_KEY_FORM_CAHCE_PREFIX = "cache.";
    public static final String QUERY_HINT_KEY_FOR_JDBC_COMPATIBLE = "jdbc.compatible";

    public EntityManagerFactoryBuilderImpl() {

    }

    /**
     *  Persistence.createEntityManagerFactory 
     *  EntityManagerFactoryBuilderImpl NamedQuery
     *
     * @param name unit name
     */
    public static EntityManagerFactoryImpl getEntityManagerFactoryByName(String name) {
        if (!inited) { // 
            EntityManagerFactoryBuilderImpl entityManagerFactoryBuilder = new EntityManagerFactoryBuilderImpl();
            entityManagerFactoryBuilder.containerManaged = false;
            //  EntityManagerFactory
            entityManagerFactoryBuilder.initEntityManagerFactories();
            ASMClassLoader asmClassLoader = new ASMClassLoader(entityManagerFactoryBuilder.getClass().getClassLoader());
            Set<Class> namedQueryClasses = new HashSet<Class>();
            namedQueryClasses.addAll(Arrays.asList(asmClassLoader.findClassAnnotatedWith(NamedNativeQueries.class)));
            namedQueryClasses.addAll(Arrays.asList(asmClassLoader.findClassAnnotatedWith(NamedNativeQuery.class)));
            entityManagerFactoryBuilder.registerNamedQueriesByClasses(namedQueryClasses.toArray(new Class[namedQueryClasses.size()]));
            inited = true;
        }
        return emFactoryMap.get(name);
    }

    public static EntityManagerFactory getDefaultEntityManagerFactory() {
        if (emFactoryMap.size() != 1) {
            throw new PersistenceException("More than one unitName, can not decide default!");
        }
        return emFactoryMap.values().toArray(new EntityManagerFactory[1])[0];
    }

    public static Collection<EntityManagerFactoryImpl> getEntityManagerFactories() {
        return Collections.unmodifiableCollection(emFactoryMap.values());
    }

    /**
     *  @Resource  name 
     */
    public static DataSource getDefaultDataSource() {
        return ((EntityManagerFactoryImpl)getDefaultEntityManagerFactory()).getDataSource();
    }

    /**
     *  @Resource  name 
     *
     * @param unitName unit name, same as @resource name
     */
    public static DataSource getDataSourceByUnitName(String unitName) {
        EntityManagerFactoryImpl emf = emFactoryMap.get(unitName);
        if (emf == null) {
            throw new PersistenceException("Can not find DataSource with unitName: " + unitName);
        }
        else {
            return emf.getDataSource();
        }
    }

    /**
     * get data source by Mapped Name, if inject by @PersistenceContext(mappedName="")
     *
     * @param mappedName mapped name, same as jndi name
     */
    public static DataSource getDataSourceByMappedName(String mappedName) {
        for (EntityManagerFactory emf : emFactoryMap.values()) {
            StandardXAPoolDataSource dataSource = (StandardXAPoolDataSource)(((EntityManagerFactoryImpl)emf).getDataSource());
            if ((dataSource.getDataSourceName().equals(mappedName))) {
                return dataSource;
            }
        }
        throw new PersistenceException("Can not find DataSource with mappedName: " + mappedName);
    }

    public static Collection<NamedSQLTemplate> getNamedSQLTemplates() {
        return Collections.unmodifiableCollection(namedSQLTemplates.values());
    }

    //get CacheConfig by unit & cacheConfigName
    public static CacheConfig getCacheConfig(String unitName) {
        EntityManagerFactoryImpl emf = getEntityManagerFactoryByName(unitName);
        if (emf != null) {
            return emf.getCacheConfig();
        }
        else {
            return null;
        }
    }

    public void postContruct(ComponentContext componentContext) {
        inited = true;
    }

    public void postInject() {
        containerManaged = true;
        initEntityManagerFactories();
    }

    public void postUnregister() {

        for (EntityManagerFactory emFactory : emFactoryMap.values()) {
            // will close data source
            emFactory.close();
        }
        emFactoryMap.clear();
        namedSQLTemplates.clear();
    }

    public boolean preUnregister(ComponentContext context) {
        return true;
    }

    public boolean isContainerManaged() {
        return containerManaged;
    }

    public void moduleChanged(ModuleEvent moduleEvent) {

        if (moduleEvent instanceof ModuleLoadingEvent) {
            Module module = moduleEvent.getModule();
            Class[] namedQueriesClasses = module.getModuleClassLoader().findClassAnnotatedWith(NamedNativeQueries.class);
            registerNamedQueriesByClasses(namedQueriesClasses);
        }

        if (moduleEvent instanceof ModuleUnloadedEvent) {
            Module module = moduleEvent.getModule();
            Iterator<Map.Entry<String, NamedSQLTemplate>> it = namedSQLTemplates.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, NamedSQLTemplate> entry = it.next();
                NamedSQLTemplate sqlTemplate = entry.getValue();
                //  NamedSQLTemplate
                if (sqlTemplate.getDefinedClass().getClassLoader() == module.getModuleClassLoader()) {
                    logger.info("Unregister Named Query defined in class: " + sqlTemplate.getDefinedClass().getName() + ", template SQL: " + sqlTemplate.getTemplateSQL());
                    it.remove();
                }
            }
        }

    }

    private void initEntityManagerFactories() {
        URL url = this.getClass().getClassLoader().getResource(PERSISTENCE_CONFIG_FILE);
        if (url == null) {
            logger.warn("Can not found persistence config file: " + PERSISTENCE_CONFIG_FILE);
            return;
        }
        logger.info("Initializing EntityManagers use: " + PERSISTENCE_CONFIG_FILE);
        transactionManager = JTATransactionManager.getIntsance();
        //  EntityTransaction
        entityTransaction = new EntityTransactionImpl(transactionManager);

        try {
            xmlDocument = XMLUtils.loadDocument(url);
            Element rootElement = xmlDocument.getDocumentElement();
            List<Element> persistenceUnits = XMLUtils.getElementsByTagName(rootElement, "persistence-unit");
            for (Element element : persistenceUnits) {
                EntityManagerFactoryImpl emFactory = createEntityManagerFactory(element);
                emFactoryMap.put(emFactory.getUnitName(), emFactory);
                //  JNDi
                if (isContainerManaged()) {
                    //jta-data-source
                    JNDIContextHelper.getInitalContext().bind(((StandardXAPoolDataSource)emFactory.getDataSource()).getDataSourceName(), emFactory);
                }
            }
        }
        catch (Exception e) {
            logger.error("Create document for " + PERSISTENCE_CONFIG_FILE + " error!", e);
        }
    }


    public EntityTransaction getEntityTransaction() {
        return entityTransaction;
    }

    private EntityManagerFactoryImpl createEntityManagerFactory(Element element) throws Exception {
        String unitName = XMLUtils.getAtrributeValue(element, "name");
        String jndiName = "java:/" + unitName;
        String jtaDataSource = XMLUtils.getChildElementValueByTagName(element, "jta-data-source");
        if (jtaDataSource != null && !jtaDataSource.trim().equals("")) {
            jndiName = jtaDataSource;
        }

        Map<String, String> properties = new HashMap<String, String>();
        List<Element> propertysElements = XMLUtils.getElementsByTagName(element, "property");
        for (Element propElement : propertysElements) {
            properties.put(XMLUtils.getAtrributeValue(propElement, "name"), XMLUtils.getAtrributeValue(propElement, "value"));
        }

        StandardXADataSource sxds = new StandardXADataSource();
        StandardXAPoolDataSource sxpds = new StandardXAPoolDataSource();
        sxpds.setJdbcTestStmt("select 1");
        // check connection after checkOut from xapool, if closed, expire it and reconnect
        sxpds.setCheckLevelObject(4);
        sxpds.setDataSourceName(jndiName);

        // cache config
        CacheConfig cacheConfig = null;
        for (Map.Entry<String, String> entry : properties.entrySet()) {
            String name = entry.getKey();
            String value = entry.getValue();
            if (name.equalsIgnoreCase("driver")) {
                sxds.setDriverName(value);
            }
            else if (name.equalsIgnoreCase("url")) {
                sxds.setUrl(value);
            }
            else if (name.equalsIgnoreCase("username")) {
                sxpds.setUser(value);
                sxds.setUser(value);
            }
            else if (name.equalsIgnoreCase("password")) {
                sxds.setPassword(value);
                sxpds.setPassword(value);
            }
            else if (name.equals("checkLevelObject")) {
                sxpds.setCheckLevelObject(Integer.parseInt(value));
            }
            else if (name.equalsIgnoreCase("minSize")) {
                sxpds.setMinSize(Integer.parseInt(value));
            }
            else if (name.equalsIgnoreCase("maxSize")) {
                sxpds.setMaxSize(Integer.parseInt(value));
            }
            else if (name.equalsIgnoreCase("lifeTime")) {
                sxpds.setLifeTime(Long.parseLong(value));
            }
            else if (name.equalsIgnoreCase("sleepTime")) {
                sxpds.setSleepTime(Long.parseLong(value));
            }
            else if (name.equalsIgnoreCase("deadLockRetryWait")) {
                sxpds.setDeadLockRetryWait(Long.parseLong(value));
            }
            else if (name.equalsIgnoreCase("deadLockMaxWait")) {
                sxpds.setDeadLockMaxWait(Long.parseLong(value));
            }
            else if (name.startsWith(QUERY_HINT_KEY_FORM_CAHCE_PREFIX)) {
                // construct cache config
                if (cacheConfig == null) {
                    cacheConfig = new CacheConfig(unitName);
                }
                String property = name.substring(name.lastIndexOf(".") + 1);
                if (property.equalsIgnoreCase("TTL")) {
                    cacheConfig.setTTL(Long.parseLong(value));
                }
                else if (property.equalsIgnoreCase("algorithm")) {
                    if (value.equalsIgnoreCase("LFU")) {
                        cacheConfig.setAlgorithm(CacheConfig.Algorithm.LFU);
                    }
                    else if (value.equalsIgnoreCase("FIFO")) {
                        cacheConfig.setAlgorithm(CacheConfig.Algorithm.FIFO);
                    }
                    else {
                        cacheConfig.setAlgorithm(CacheConfig.Algorithm.LRU);
                    }
                }
                else if (property.equalsIgnoreCase("maxIdleTime")) {
                    cacheConfig.setMaxIdleTime(Long.parseLong(value));
                }
                else if (property.equalsIgnoreCase("maxSize")) {
                    cacheConfig.setMaxSize(Integer.parseInt(value));
                }
                else if (property.equalsIgnoreCase("maxMemorySize")) {
                    cacheConfig.setMaxMemorySize(Long.parseLong(value));
                }
                else {
                    logger.warn("Illegal JPA cache property name: " + name);
                }
            }
            else {
                logger.warn("Illegal JPA persistence.xml property name: " + name);
            }
        }
        sxpds.setTransactionManager(transactionManager);
        sxpds.setDataSource(sxds);

        // create EntityManagerFactory
        return new EntityManagerFactoryImpl(unitName, jndiName, this, sxpds, cacheConfig);
    }

    private void registerNamedQueriesByClasses(Class[] classes) {
        for (Class<?> beanClass : classes) {
            List<String> queryNames = new ArrayList<String>();
            if (beanClass.isAnnotationPresent(NamedNativeQueries.class)) {
                NamedNativeQueries namedNativeQueries = beanClass.getAnnotation(NamedNativeQueries.class);
                for (NamedNativeQuery namedNativeQuery : namedNativeQueries.value()) {
                    this.registerNamedQuery(namedNativeQuery, beanClass);
                    queryNames.add(namedNativeQuery.name());
                }
            }
            if (beanClass.isAnnotationPresent(NamedNativeQuery.class)) {
                NamedNativeQuery namedNativeQuery = beanClass.getAnnotation(NamedNativeQuery.class);
                this.registerNamedQuery(namedNativeQuery, beanClass);
                queryNames.add(namedNativeQuery.name());
            }
            logger.info("Register NamedQuery for Class: " + beanClass.getName() + ", " + Arrays.toString(queryNames.toArray(new String[queryNames.size()])));
        }
    }

    public void registerNamedQuery(NamedNativeQuery namedNativeQuery, Class<?> definedClass) {
        if (namedSQLTemplates.containsKey(namedNativeQuery.name())) {
            logger.warn("NamedQuery " + namedNativeQuery.name() + " has registered by " + namedSQLTemplates.get(namedNativeQuery.name()).getDefinedClass() + ".");
        }
        else {
            NamedSQLTemplate sqlTemplate = new NamedSQLTemplate(namedNativeQuery, definedClass);
            QueryHint[] hints = namedNativeQuery.hints();
            if (hints.length > 0) {
                //  jdbc.compatible
                for (QueryHint hint : hints) {
                    if (hint.name().equals(QUERY_HINT_KEY_FOR_JDBC_COMPATIBLE)) {
                        String compatibleDatabaseTypes = hint.value();
                        for(String compatibleDbType : compatibleDatabaseTypes.split(",")){
                            //query_name = getUserInfo.MYSQL
                            compatibleDbType = compatibleDbType.trim();
                            if(compatibleDbType.length() > 0) {
                                namedSQLTemplates.put(sqlTemplate.getName() + "." + compatibleDbType.trim().toUpperCase(), sqlTemplate);
                            }
                        }
                    }
                    else {
                        namedSQLTemplates.put(sqlTemplate.getName(), sqlTemplate);
                    }
                }
            }
            else {
                namedSQLTemplates.put(sqlTemplate.getName(), sqlTemplate);
            }
        }
    }

    public NamedSQLTemplate getNamedQuery(String name, String dbType) {
        NamedSQLTemplate sqlTemplate = namedSQLTemplates.get(name + "." + dbType.toUpperCase());
        if(sqlTemplate == null) {
            sqlTemplate = namedSQLTemplates.get(name);
        }
        return sqlTemplate;
    }

    public Document getPersistenceXMLDocument() {
        return xmlDocument;
    }

    public static void main(String[] args) {
        EntityManagerFactory entityManagerFactory = EntityManagerFactoryBuilderImpl.getEntityManagerFactoryByName("DefaultMysqlDS");
        System.out.println(entityManagerFactory);
    }
}
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.