Package org.apache.openejb.assembler.classic

Source Code of org.apache.openejb.assembler.classic.ReloadableEntityManagerFactory

/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.openejb.assembler.classic;

import org.apache.openejb.OpenEJBException;
import org.apache.openejb.api.internal.Internal;
import org.apache.openejb.jee.JAXBContextFactory;
import org.apache.openejb.jee.Persistence;
import org.apache.openejb.jee.PersistenceUnitCaching;
import org.apache.openejb.jee.PersistenceUnitValidationMode;
import org.apache.openejb.monitoring.DynamicMBeanWrapper;
import org.apache.openejb.monitoring.LocalMBeanServer;
import org.apache.openejb.monitoring.ObjectNameBuilder;
import org.apache.openejb.persistence.PersistenceUnitInfoImpl;
import org.apache.openejb.util.LogCategory;
import org.apache.openejb.util.Logger;

import javax.management.Description;
import javax.management.MBean;
import javax.management.MBeanServer;
import javax.management.ManagedAttribute;
import javax.management.ManagedOperation;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.OpenDataException;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.SimpleType;
import javax.management.openmbean.TabularData;
import javax.management.openmbean.TabularDataSupport;
import javax.management.openmbean.TabularType;
import javax.persistence.Cache;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnitUtil;
import javax.persistence.SharedCacheMode;
import javax.persistence.ValidationMode;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.metamodel.Metamodel;
import javax.persistence.spi.PersistenceUnitTransactionType;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.Properties;

public class ReloadableEntityManagerFactory implements EntityManagerFactory {
    private static final Logger LOGGER = Logger.getInstance(LogCategory.OPENEJB, ReloadableEntityManagerFactory.class);
    public static final String JAVAX_PERSISTENCE_SHARED_CACHE_MODE = "javax.persistence.sharedCache.mode";
    public static final String JAVAX_PERSISTENCE_VALIDATION_MODE = "javax.persistence.validation.mode";
    public static final String JAVAX_PERSISTENCE_TRANSACTION_TYPE = "javax.persistence.transactionType";

    private ClassLoader classLoader;
    private EntityManagerFactory delegate;
    private EntityManagerFactoryCallable entityManagerFactoryCallable;
    private ObjectName objectName = null;

    public ReloadableEntityManagerFactory(final ClassLoader cl, final EntityManagerFactory emf, EntityManagerFactoryCallable callable) {
        classLoader = cl;
        delegate = emf;
        entityManagerFactoryCallable = callable;
    }

    @Override public EntityManager createEntityManager() {
        return delegate.createEntityManager();
    }

    @Override
    public EntityManager createEntityManager(Map map) {
        return delegate.createEntityManager(map);
    }

    @Override
    public CriteriaBuilder getCriteriaBuilder() {
        return delegate.getCriteriaBuilder();
    }

    @Override
    public Metamodel getMetamodel() {
        return delegate.getMetamodel();
    }

    @Override
    public boolean isOpen() {
        return delegate.isOpen();
    }

    @Override
    public void close() {
        delegate.close();
    }

    @Override
    public Map<String, Object> getProperties() {
        return delegate.getProperties();
    }

    @Override
    public Cache getCache() {
        return delegate.getCache();
    }

    @Override
    public PersistenceUnitUtil getPersistenceUnitUtil() {
        return delegate.getPersistenceUnitUtil();
    }

    public EntityManagerFactory getDelegate() {
        return delegate;
    }

    public void register() throws OpenEJBException {
        final MBeanServer server = LocalMBeanServer.get();
        try {
            server.registerMBean(mBeanify(), generateObjectName());
        } catch (Exception e) {
            throw new OpenEJBException("can't register the mbean for the entity manager factory " + getPUname(), e);
        } catch (NoClassDefFoundError ncdfe) {
            objectName = null;
            LOGGER.error("can't register the mbean for the entity manager factory {}", getPUname());
        }
    }

    private ObjectName generateObjectName() {
        ObjectNameBuilder jmxName = new ObjectNameBuilder("openejb.management");
        jmxName.set("ObjectType", "persistence-unit");
        jmxName.set("PersistenceUnit", getPUname());
        objectName = jmxName.build();

        MBeanServer server = LocalMBeanServer.get();
        if (server.isRegistered(objectName)) { // if 2 pu have the same name...a bit uglier but unique
            jmxName.set("PersistenceUnit", getPUname() + "(" + getId() + ")");
            objectName = jmxName.build();
        }

        return objectName;
    }

    private String getPUname() {
        return entityManagerFactoryCallable.getUnitInfo().getPersistenceUnitName();
    }

    private String getId() {
        return entityManagerFactoryCallable.getUnitInfo().getId();
    }

    private Object mBeanify() {
        return new DynamicMBeanWrapper(new JMXReloadableEntityManagerFactory(this));
    }

    public void unregister() throws OpenEJBException {
        if (objectName != null) {
            final MBeanServer server = LocalMBeanServer.get();
            try {
                server.unregisterMBean(objectName);
            } catch (Exception e) {
                throw new OpenEJBException("can't unregister the mbean for the entity manager factory " + getPUname(), e);
            }
        }
    }

    // only this method is synchronized since we want to avoid locks on other methods.
    // it is just to avoid problems due to the "double click syndrom"
    //
    // Note: it uses the old unitInfo but properties can be modified (not managed classes, provider...)
    public synchronized void reload() {
        if (classLoader == null) {
            classLoader = Thread.currentThread().getContextClassLoader();
        }
        try {
            delegate = PersistenceBuilder.createEmf(classLoader, entityManagerFactoryCallable);
        } catch (Exception e) {
            LOGGER.error("can't replace EntityManagerFactory " + delegate, e);
        }
    }

    public synchronized void setSharedCacheMode(SharedCacheMode mode) {
        PersistenceUnitInfoImpl info = entityManagerFactoryCallable.getUnitInfo();
        info.setSharedCacheMode(mode);

        Properties properties = entityManagerFactoryCallable.getUnitInfo().getProperties();
        if (properties.containsKey(JAVAX_PERSISTENCE_SHARED_CACHE_MODE)) {
            properties.setProperty(JAVAX_PERSISTENCE_SHARED_CACHE_MODE, mode.name());
        }
    }

    public synchronized void setValidationMode(ValidationMode mode) {
        PersistenceUnitInfoImpl info = entityManagerFactoryCallable.getUnitInfo();
        info.setValidationMode(mode);

        Properties properties = entityManagerFactoryCallable.getUnitInfo().getProperties();
        if (properties.containsKey(JAVAX_PERSISTENCE_VALIDATION_MODE)) {
            properties.setProperty(JAVAX_PERSISTENCE_VALIDATION_MODE, mode.name());
        }
    }

    public synchronized void setProvider(String providerRaw) {
        final String provider = providerRaw.trim();
        String newProvider;
        if ("hibernate".equals(provider)) {
            newProvider = "org.hibernate.ejb.HibernatePersistence";
        } else if ("openjpa".equals(provider)) {
            newProvider = "org.apache.openjpa.persistence.PersistenceProviderImpl";
        } else if ("eclipse".equals(provider)) {
            newProvider = "oracle.toplink.essentials.PersistenceProvider";
        } else {
            newProvider = provider;
        }

        try {
            classLoader.loadClass(newProvider);
            entityManagerFactoryCallable.getUnitInfo().setPersistenceProviderClassName(newProvider);
        } catch (ClassNotFoundException e) {
            LOGGER.error("can't load new provider " + newProvider, e);
        }
    }

    public synchronized void setTransactionType(PersistenceUnitTransactionType type) {
        PersistenceUnitInfoImpl info = entityManagerFactoryCallable.getUnitInfo();
        info.setTransactionType(type);

        Properties properties = entityManagerFactoryCallable.getUnitInfo().getProperties();
        if (properties.containsKey(JAVAX_PERSISTENCE_TRANSACTION_TYPE)) {
            properties.setProperty(JAVAX_PERSISTENCE_TRANSACTION_TYPE, type.name());
        }
    }

    public synchronized void setProperty(String key, String value) {
        PersistenceUnitInfoImpl unitInfo = entityManagerFactoryCallable.getUnitInfo();
        if (unitInfo.getProperties() == null) {
            unitInfo.setProperties(new Properties());
        }
        unitInfo.getProperties().setProperty(key, value);
    }

    public synchronized void removeProperty(String key) {
        PersistenceUnitInfoImpl unitInfo = entityManagerFactoryCallable.getUnitInfo();
        if (unitInfo.getProperties() != null) {
            unitInfo.getProperties().remove(key);
        }
    }

    public Properties getUnitProperties() {
        PersistenceUnitInfoImpl unitInfo = entityManagerFactoryCallable.getUnitInfo();
        if (unitInfo.getProperties() != null) {
            return unitInfo.getProperties();
        }
        return new Properties();
    }

    public List<String> getMappingFiles() {
        return entityManagerFactoryCallable.getUnitInfo().getMappingFileNames();
    }

    public void addMappingFile(String file) {
        if (new File(file).exists()) {
            entityManagerFactoryCallable.getUnitInfo().addMappingFileName(file);
        } else {
            LOGGER.error("file " + file + " doesn't exists");
        }
    }

    public void removeMappingFile(String file) {
        entityManagerFactoryCallable.getUnitInfo().getMappingFileNames().remove(file);
    }

    public List<URL> getJarFileUrls() {
        return entityManagerFactoryCallable.getUnitInfo().getJarFileUrls();
    }

    public void addJarFileUrls(String file) {
        if (new File(file).exists()) { // should we test real urls?
            try {
                entityManagerFactoryCallable.getUnitInfo().getJarFileUrls().add(new URL(file));
            } catch (MalformedURLException e) {
                LOGGER.error("url " + file + " is malformed");
            }
        } else {
            LOGGER.error("url " + file + " is not correct");
        }
    }

    public void removeJarFileUrls(String file) {
        try {
            entityManagerFactoryCallable.getUnitInfo().getJarFileUrls().remove(new URL(file));
        } catch (MalformedURLException e) {
            LOGGER.error("url " + file + " is malformed");
        }
    }

    public List<String> getManagedClasses() {
        return entityManagerFactoryCallable.getUnitInfo().getManagedClassNames();
    }

    public void addManagedClasses(String clazz) {
        entityManagerFactoryCallable.getUnitInfo().getManagedClassNames().add(clazz);
    }

    public void removeManagedClasses(String clazz) {
        entityManagerFactoryCallable.getUnitInfo().getManagedClassNames().remove(clazz);
    }

    @MBean
    @Internal
    @Description("represents a persistence unit managed by OpenEJB")
    public static class JMXReloadableEntityManagerFactory {
        private ReloadableEntityManagerFactory reloadableEntityManagerFactory;

        public JMXReloadableEntityManagerFactory(ReloadableEntityManagerFactory remf) {
            reloadableEntityManagerFactory = remf;
        }

        @ManagedOperation
        @Description("recreate the entity manager factory using new properties")
        public void reload() {
            reloadableEntityManagerFactory.reload();
        }

        @ManagedOperation
        @Description("change the current JPA provider")
        public void setProvider(String provider) {
            reloadableEntityManagerFactory.setProvider(provider);
        }

        @ManagedOperation
        @Description("change the current transaction type")
        public void setTransactionType(String type) {
            try {
                PersistenceUnitTransactionType tt = PersistenceUnitTransactionType.valueOf(type.toUpperCase());
                reloadableEntityManagerFactory.setTransactionType(tt);
            } catch (Exception iae) {
                // ignored
            }
        }

        @ManagedOperation
        @Description("create or modify a property of the persistence unit")
        public void setProperty(String key, String value) {
            reloadableEntityManagerFactory.setProperty(key, value);
        }

        @ManagedOperation
        @Description("remove a property of the persistence unit if it exists")
        public void removeProperty(String key) {
            reloadableEntityManagerFactory.removeProperty(key);
        }

        @ManagedOperation
        @Description("add a mapping file")
        public void addMappingFile(String file) {
            reloadableEntityManagerFactory.addMappingFile(file);
        }

        @ManagedOperation
        @Description("remove a mapping file")
        public void removeMappingFile(String file) {
            reloadableEntityManagerFactory.removeMappingFile(file);
        }

        @ManagedOperation
        @Description("add a managed class")
        public void addManagedClass(String clazz) {
            reloadableEntityManagerFactory.addManagedClasses(clazz);
        }

        @ManagedOperation
        @Description("remove a managed class")
        public void removeManagedClass(String clazz) {
            reloadableEntityManagerFactory.removeManagedClasses(clazz);
        }

        @ManagedOperation
        @Description("add a jar file")
        public void addJarFile(String file) {
            reloadableEntityManagerFactory.addJarFileUrls(file);
        }

        @ManagedOperation
        @Description("remove a jar file")
        public void removeJarFile(String file) {
            reloadableEntityManagerFactory.removeJarFileUrls(file);
        }

        @ManagedOperation
        @Description("change the shared cache mode if possible (value is ok)")
        public void setSharedCacheMode(String value) {
            try {
                SharedCacheMode mode = SharedCacheMode.valueOf(value.trim().toUpperCase());
                reloadableEntityManagerFactory.setSharedCacheMode(mode);
            } catch (Exception iae) {
                // ignored
            }
        }

        @ManagedOperation
        @Description("change the validation mode if possible (value is ok)")
        public void setValidationMode(String value) {
            try {
                ValidationMode mode = ValidationMode.valueOf(value.trim().toUpperCase());
                reloadableEntityManagerFactory.setValidationMode(mode);
            } catch (Exception iae) {
                // ignored
            }
        }

        @ManagedOperation
        @Description("dump the current configuration for this persistence unit in a file")
        public void dump(String file) {
            PersistenceUnitInfoImpl info = reloadableEntityManagerFactory.entityManagerFactoryCallable.getUnitInfo();

            Persistence.PersistenceUnit pu = new Persistence.PersistenceUnit();
            pu.setJtaDataSource(info.getJtaDataSourceName());
            pu.setNonJtaDataSource(info.getNonJtaDataSourceName());
            pu.getClazz().addAll(info.getManagedClassNames());
            pu.getMappingFile().addAll(info.getMappingFileNames());
            pu.setName(info.getPersistenceUnitName());
            pu.setProvider(info.getPersistenceProviderClassName());
            pu.setTransactionType(info.getTransactionType().name());
            pu.setExcludeUnlistedClasses(info.excludeUnlistedClasses());
            pu.setSharedCacheMode(PersistenceUnitCaching.fromValue(info.getSharedCacheMode().name()));
            pu.setValidationMode(PersistenceUnitValidationMode.fromValue(info.getValidationMode().name()));
            for (URL url : info.getJarFileUrls()) {
                pu.getJarFile().add(url.toString());
            }
            for (String key : info.getProperties().stringPropertyNames()) {
                Persistence.PersistenceUnit.Properties.Property prop = new Persistence.PersistenceUnit.Properties.Property();
                prop.setName(key);
                prop.setValue(info.getProperties().getProperty(key));
                if (pu.getProperties() == null) {
                    pu.setProperties(new Persistence.PersistenceUnit.Properties());
                }
                pu.getProperties().getProperty().add(prop);
            }

            Persistence persistence = new Persistence();
            persistence.setVersion(info.getPersistenceXMLSchemaVersion());
            persistence.getPersistenceUnit().add(pu);

            try {
                FileWriter writer = new FileWriter(file);
                JAXBContext jc = JAXBContextFactory.newInstance(Persistence.class);
                Marshaller marshaller = jc.createMarshaller();
                marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
                marshaller.marshal(persistence, writer);
                writer.close();
            } catch (Exception e) {
                LOGGER.error("can't dump pu " + reloadableEntityManagerFactory.getPUname() + " in file " + file, e);
            }
        }

        @ManagedAttribute
        @Description("get all properties")
        public TabularData getProperties() {
            return tabularData("properties", "properties type",
                    "Property of " + reloadableEntityManagerFactory.getPUname(),
                    reloadableEntityManagerFactory.getUnitProperties());
        }

        @ManagedAttribute
        @Description("get all mapping files")
        public TabularData getMappingFiles() {
            return tabularData("mappingfile", "mapping file type",
                    "Mapping file of " + reloadableEntityManagerFactory.getPUname(),
                    reloadableEntityManagerFactory.getMappingFiles(), Info.FILE);
        }

        @ManagedAttribute
        @Description("get all jar files")
        public TabularData getJarFiles() {
            return tabularData("jarfile", "jar file type",
                    "Jar file of " + reloadableEntityManagerFactory.getPUname(),
                    reloadableEntityManagerFactory.getJarFileUrls(), Info.URL);
        }

        @ManagedAttribute
        @Description("get all managed classes")
        public TabularData getManagedClasses() {
            return tabularData("managedclass", "managed class type",
                    "Managed class of " + reloadableEntityManagerFactory.getPUname(),
                    reloadableEntityManagerFactory.getManagedClasses(), Info.CLASS);
        }

        private TabularData tabularData(String typeName, String typeDescription, String description, List<?> list, Info info) {
            String[] names = new String[list.size()];
            Object[] values= new Object[names.length];
            int i = 0;
            for (Object o : list) {
                names[i] = o.toString();
                values[i++] = info.info(reloadableEntityManagerFactory.classLoader, o);
            }
            return tabularData(typeName, typeDescription, names, values);
        }

        private static TabularData tabularData(String typeName, String typeDescription, String description, Properties properties) {
            String[] names = properties.keySet().toArray(new String[properties.size()]);
            Object[] values = new Object[names.length];
            for (int i = 0; i < values.length; i++) {
                values[i] = properties.get(names[i]).toString(); // hibernate put objects in properties for instance
            }
            return tabularData(typeName, typeDescription, names, values);
        }

        private static TabularData tabularData(String typeName, String typeDescription, String[] names, Object[] values) {
            if (names.length == 0) {
                return null;
            }

            OpenType<?>[] types = new OpenType<?>[names.length];
            for (int i = 0; i < types.length; i++) {
                types[i] = SimpleType.STRING;
            }

            try {
                CompositeType ct = new CompositeType(typeName, typeDescription, names, names, types);
                TabularType type = new TabularType(typeName, typeDescription, ct, names);
                TabularDataSupport data = new TabularDataSupport(type);

                CompositeData line = new CompositeDataSupport(ct, names, values);
                data.put(line);

                return data;
            } catch (OpenDataException e) {
                return null;
            }
        }

        private enum Info {
            URL, NONE, FILE, CLASS;

            public String info(ClassLoader cl, Object o) {
                switch (this) {
                    case URL:
                        try {
                            if (((URL) o).openConnection().getContentLength() > 0) {
                                return "valid";
                            }
                        } catch (IOException e) {
                            // ignored
                        }
                        return "not valid";

                    case FILE:
                        File file;
                        if (o instanceof String) {
                            file = new File((String) o);
                        } else if (o instanceof File) {
                            file = (File) o;
                        } else {
                            return "unknown";
                        }
                        return "exist? " + file.exists();

                    case CLASS:
                        try {
                            cl.loadClass((String) o);
                            return "loaded";
                        } catch (ClassNotFoundException e) {
                            return "unloadable";
                        }

                    default:
                        return "-";
                }
            }
        }
    }
}
TOP

Related Classes of org.apache.openejb.assembler.classic.ReloadableEntityManagerFactory

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.