package org.deephacks.westty.internal.jpa; import org.deephacks.westty.config.DataSourceConfig; import org.deephacks.westty.config.JpaConfig; import org.scannotation.AnnotationDB; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.enterprise.inject.Produces; import javax.inject.Inject; import javax.inject.Singleton; import javax.persistence.Entity; import javax.persistence.EntityManagerFactory; import javax.persistence.SharedCacheMode; import javax.persistence.ValidationMode; import javax.persistence.spi.ClassTransformer; import javax.persistence.spi.PersistenceProvider; import javax.persistence.spi.PersistenceProviderResolverHolder; import javax.persistence.spi.PersistenceUnitInfo; import javax.persistence.spi.PersistenceUnitTransactionType; import javax.sql.DataSource; import java.io.File; import java.io.IOException; import java.net.JarURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; public class EntityManagerFactoryProducer implements PersistenceUnitInfo { public static final String PERSISTENCE_XML = "META-INF/persistence.xml"; private static final Logger log = LoggerFactory.getLogger(EntityManagerFactoryProducer.class); private List<Class<?>> classes = new ArrayList<>(); private DataSource datasource; private DataSourceConfig dataSourceConfig; private JpaConfig jpaConfig; @Inject public EntityManagerFactoryProducer(DataSource datasource, DataSourceConfig dataSourceConfig, JpaConfig jpaConfig) { this.dataSourceConfig = dataSourceConfig; this.datasource = datasource; this.jpaConfig = jpaConfig; } @Produces @Singleton public EntityManagerFactory produceEntityManagerFactory() { try { final List<Class<?>> entities = getEntities(); add(entities); EntityManagerFactory emf = null; List<PersistenceProvider> providers = getProviders(); Properties properties = jpaConfig.getProperties(); for (PersistenceProvider provider : providers) { emf = provider.createContainerEntityManagerFactory(this,properties); if (emf != null) { break; } } if (emf == null) { log.info("No Persistence provider for EntityManager named " + getPersistenceUnitName()); return null; } else { log.debug("Created persistence unit " + getPersistenceUnitName() + " with entities {}", entities); } return emf; } catch (Exception e) { log.error("Could not create EntityManagerFactory.", e); throw e; } } @Override public String getPersistenceUnitName() { return jpaConfig.getJpaUnit(); } @Override public String getPersistenceProviderClassName() { return jpaConfig.getProvider(); } @Override public PersistenceUnitTransactionType getTransactionType() { return PersistenceUnitTransactionType.valueOf(jpaConfig.getTxType()); } @Override public DataSource getJtaDataSource() { return null; } @Override public DataSource getNonJtaDataSource() { return datasource; } @Override public List<String> getMappingFileNames() { return null; } @Override public List<URL> getJarFileUrls() { return new ArrayList<>(); } @Override public java.net.URL getPersistenceUnitRootUrl() { return null; /*try { File libDir = new ServerConfig().getLibDir(); if(libDir == null){ return null; } return libDir.toURI().toURL(); } catch (MalformedURLException e) { throw new RuntimeException(e); } */ } @Override public List<String> getManagedClassNames() { List<String> classNames = new ArrayList<>(); for (Class<?> cls : classes) { classNames.add(cls.getCanonicalName()); } return classNames; } @Override public boolean excludeUnlistedClasses() { return true; } @Override public SharedCacheMode getSharedCacheMode() { return SharedCacheMode.NONE; } @Override public ValidationMode getValidationMode() { return ValidationMode.AUTO; } @Override public Properties getProperties() { return jpaConfig.getProperties(); } @Override public String getPersistenceXMLSchemaVersion() { throw new UnsupportedOperationException(); } @Override public ClassLoader getClassLoader() { return Thread.currentThread().getContextClassLoader(); } @Override public void addTransformer(ClassTransformer transformer) { throw new UnsupportedOperationException(); } @Override public ClassLoader getNewTempClassLoader() { return null; } public void add(Class<?> cls) { classes.add(cls); } public void add(Class<?>... cls) { classes.addAll(Arrays.asList(cls)); } public void add(Collection<Class<?>> cls) { classes.addAll(cls); } private List<PersistenceProvider> getProviders() { return PersistenceProviderResolverHolder.getPersistenceProviderResolver() .getPersistenceProviders(); } private List<Class<?>> getEntities() { try { AnnotationDB db = new AnnotationDB(); List<Class<?>> entities = new ArrayList<>(); ClassLoader cl = Thread.currentThread().getContextClassLoader(); URL[] jars = getPersistenceArchives(cl); db.scanArchives(jars); Map<String, Set<String>> annotationIndex = db.getAnnotationIndex(); Set<String> classes = annotationIndex.get(Entity.class.getName()); if (classes == null) { return entities; } for (String cls : classes) { Class<?> entity = cl.loadClass(cls); entities.add(entity); } return entities; } catch (Exception e) { throw new RuntimeException(e); } } private URL[] getPersistenceArchives(ClassLoader cl) throws IOException { final List<URL> result = new ArrayList<>(); final Enumeration<URL> urls = cl.getResources(PERSISTENCE_XML); while (urls.hasMoreElements()) { // either a jar or file in a dir URL url = urls.nextElement(); File file = new File(url.getFile()); if (file.exists()) { // navigate on directory above META-INF url = file.getParentFile().getParentFile().toURI().toURL(); } else { url = ((JarURLConnection) url.openConnection()).getJarFileURL(); } result.add(url); } return result.toArray(new URL[0]); } }