/* * The contents of this file are subject to the terms * of the Common Development and Distribution License * (the "License"). You may not use this file except * in compliance with the License. * * You can obtain a copy of the license at * glassfish/bootstrap/legal/CDDLv1.0.txt or * https://glassfish.dev.java.net/public/CDDLv1.0.html. * See the License for the specific language governing * permissions and limitations under the License. * * When distributing Covered Code, include this CDDL * HEADER in each file and include the License file at * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable, * add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your * own identifying information: Portions Copyright [yyyy] * [name of copyright owner] */ // Copyright (c) 1998, 2005, Oracle. All rights reserved. package oracle.toplink.essentials.ejb.cmp3; import java.lang.instrument.ClassFileTransformer; import java.io.File; import java.util.Map; import java.util.Collection; import java.util.Iterator; import java.util.Vector; import java.util.HashMap; import java.net.URL; import javax.persistence.*; import javax.persistence.spi.*; import oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerFactoryImpl; import oracle.toplink.essentials.internal.ejb.cmp3.JavaSECMPInitializer; import oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerSetupImpl; import oracle.toplink.essentials.ejb.cmp3.persistence.PersistenceUnitProcessor; import oracle.toplink.essentials.threetier.ServerSession; import oracle.toplink.essentials.logging.AbstractSessionLog; import oracle.toplink.essentials.logging.SessionLog; import java.util.Properties; import oracle.toplink.essentials.tools.schemaframework.SchemaManager; /** * This is the TopLink EJB 3.0 provider * The default constructor can be used to build the provider by reflection, after which it can * be used to create EntityManagerFactories */ public class EntityManagerFactoryProvider implements javax.persistence.spi.PersistenceProvider { // The following constants are used in persistence xml to specify properties public static final String JDBC_DRIVER_PROPERTY = "jdbc.driver"; public static final String JDBC_CONNECTION_STRING_PROPERTY = "jdbc.connection.string"; public static final String JDBC_USER_PROPERTY = "jdbc.user"; public static final String JDBC_PASSWORD_PROPERTY = "jdbc.password"; public static final String TOPLINK_PLATFORM_PROPERTY = "toplink.platform.class.name"; public static final String TOPLINK_SERVER_PLATFORM_PROPERTY = "toplink.server.platform.class.name"; public static final String TOPLINK_EXTERNAL_TRANSACTION_CONTROLLER_PROPERTY = "toplink.external.transaction.controller.class.name"; public static final String TOPLINK_LOGGING_LEVEL = "toplink.logging.level"; public static final String TOPLINK_ORM_THROW_EXCEPTIONS = "toplink.orm.throw.exceptions"; private static final String TOPLINK_VALIDATION_ONLY_PROPERTY = "oracle.toplink.essentials.ValidationOnly"; public static final String DDL_GENERATION = "ddl-generation"; public static final String CREATE_ONLY = "createtables"; public static final String DROP_AND_CREATE = "dropandcreate"; public static final String NONE = "none"; public static final String APP_LOCATION = "application-location"; public static final String CREATE_JDBC_DDL_FILE = "create-ddl-jdbc-file-name"; public static final String DROP_JDBC_DDL_FILE = "drop-ddl-jdbc-file-name"; public static final String DEFAULT_APP_LOCATION = "." + File.separator; public static final String DEFAULT_CREATE_JDBC_FILE_NAME = "createDDL.jdbc"; public static final String DEFAULT_DROP_JDBC_FILE_NAME = "dropDDL.jdbc"; public static final String JAVASE_DB_INTERACTION = "INTERACT_WITH_DB"; // Store previously created application entity manager factories here. For an application based // provider, only one factory will exist for each name public HashMap applicationEntityManagerFactories = null; /** * A default constructor is required by all Providers accoring the the EJB 3.0 specification */ public EntityManagerFactoryProvider() { applicationEntityManagerFactories = new HashMap(); } /** * This is the method that will be used by javax.persistence.Persistence to get an * EntityManagerFactory. javax.persistence.Persistence is used by J2SE EJB 3.0 users * @see {@link Persistence#createEntityManagerFactory()}. */ public EntityManagerFactory createEntityManagerFactory(String emName, Map m){ String name = emName; if (name == null){ name = ""; } EntityManagerFactory emf = applicationEntityManagerFactories.get(name); if (emf != null){ return emf; } ServerSession session = getServerSession(name, m); if (session != null){ emf = new EntityManagerFactoryImpl(session); session.login(); //PG-> generateDDLFiles(session, getPersistenceUnitProperties(name, m), true); //PG-> return emf; } return null; } /** * This method should be called by containers that wish to integrate with TopLink's * EJB 3.0 provider. * In order to use TopLink's weaving capabilities to allow lazy loading and change * tracking * @param info * @return */ public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info){ EntityManagerSetupImpl emSetupImpl = new EntityManagerSetupImpl(); ClassLoader tempLoader = info.getTempClassLoader(); Collection entities = buildEntityList(info, tempLoader); ClassFileTransformer transformer = emSetupImpl.predeploy(entities, tempLoader, info); if (transformer != null){ info.addTransformer(transformer); } ClassLoader realLoader = info.getClassLoader(); entities = buildEntityList(info, realLoader); ServerSession session = emSetupImpl.deploy(entities, realLoader); boolean validationOnly = info.getProperties().getProperty( TOPLINK_VALIDATION_ONLY_PROPERTY, "false"). equalsIgnoreCase("true"); if(validationOnly) { session.initializeDescriptors(); } else { session.login(); generateDDLFiles(session, info.getProperties(), false); } return new EntityManagerFactoryImpl(session); } private void generateDDLFiles(ServerSession session, Properties props, boolean inSEmode) { boolean createTables = false, shouldDropFirst = false; String appLocation; String createDDLJdbc; String dropDDLJdbc; String ddlGeneration = NONE; if(null == props) return; ddlGeneration = props.getProperty(DDL_GENERATION, NONE); ddlGeneration = ddlGeneration.toLowerCase(); if(ddlGeneration.equals(NONE)) return; if(ddlGeneration.equals(CREATE_ONLY) || ddlGeneration.equals(DROP_AND_CREATE)) { createTables = true; if(ddlGeneration.equals(DROP_AND_CREATE)) { shouldDropFirst = true; } } if(createTables) { appLocation = props.getProperty( APP_LOCATION, DEFAULT_APP_LOCATION); createDDLJdbc = props.getProperty( CREATE_JDBC_DDL_FILE, DEFAULT_CREATE_JDBC_FILE_NAME); dropDDLJdbc = props.getProperty( DROP_JDBC_DDL_FILE, DEFAULT_DROP_JDBC_FILE_NAME); SchemaManager mgr = new SchemaManager(session); if(inSEmode) { runInSEMode(mgr, shouldDropFirst); } writeDDLsToFiles(mgr, shouldDropFirst, appLocation, createDDLJdbc, dropDDLJdbc); } } /** * Create a list of the entities that will be deployed. This list is build from the information * provided in the PersistenceUnitInfo argument. * The list contains Classes specified in the PersistenceUnitInfo's class list and also * files that are annotated with @Entity, @Embeddable and @EmbeddableSuperclass in * the jar files provided in the persistence info. * This list of classes will used by TopLink to build a deployment project and to * decide what classes to weave. * @param info * @param loader * @return */ public static Collection buildEntityList(PersistenceUnitInfo info, ClassLoader loader) { Vector classNames = new Vector(); classNames.addAll(info.getManagedClassNames()); Iterator i = info.getJarFileUrls().iterator(); while (i.hasNext()){ classNames.addAll(PersistenceUnitProcessor.getPersistentClassNamesFromURL((URL)i.next(), loader)); } if (!info.excludeUnlistedClasses()){ classNames.addAll(PersistenceUnitProcessor.getPersistentClassNamesFromURL(info.getPersistenceUnitRootUrl(), loader)); } Vector entityList = new Vector(); i = classNames.iterator(); String className = null; while (i.hasNext()){ try{ className = (String)i.next(); Class entityClass = loader.loadClass(className); entityList.add(entityClass); } catch (ClassNotFoundException exc){ AbstractSessionLog.getLog().log(SessionLog.CONFIG, "exception_loading_entity_class", className, exc); } } return entityList; } /** * @see {@link Persistence#createEntityManagerFactory()}. */ protected ServerSession getServerSession(String emName, Map m) { JavaSECMPInitializer initializer = JavaSECMPInitializer.getJavaSECMPInitializer(m); return initializer.getServerSession(emName, m); } /** * Get the named property from the map of provided properties. If it is not available * in that map, check the System properties * @param propertyName * @param providedProperties * @return the value of the give property */ public static String getConfigProperty(String propertyName, Map providedProperties) { String property = (String)providedProperties.get(propertyName); if (property == null) { property = System.getProperty(propertyName); } return property; } protected Properties getPersistenceUnitProperties(String emName, Map m) { JavaSECMPInitializer initializer = JavaSECMPInitializer.getJavaSECMPInitializer(m); return initializer.getPersistenceUnitProperties(emName); } private void runInSEMode(SchemaManager mgr, boolean shouldDropFirst) { boolean interactWithDB = getJava2dbSystemProperty(); if (!interactWithDB) return; createOrReplaceDefaultTables(mgr, shouldDropFirst); } private boolean getJava2dbSystemProperty() { String str = System.getProperty(JAVASE_DB_INTERACTION, "true"); return Boolean.valueOf(str.toLowerCase()).booleanValue(); } private void createOrReplaceDefaultTables( SchemaManager mgr, boolean shouldDropFirst) { if (shouldDropFirst) mgr.replaceDefaultTables(); else mgr.createDefaultTables(); } private void writeDDLsToFiles(SchemaManager mgr, boolean shouldDropFirst, String appLocation, String createDDLJdbc, String dropDDLJdbc) { // Ensure that the appLocation string ends with File.seperator appLocation = addFileSeperator(appLocation); if (null != createDDLJdbc) { String createJdbcFileName = appLocation + createDDLJdbc; mgr.outputCreateDDLToFile(createJdbcFileName); } if (null != dropDDLJdbc) { String dropJdbcFileName = appLocation + dropDDLJdbc; mgr.outputDropDDLToFile(dropJdbcFileName); } mgr.setCreateSQLFiles(false); createOrReplaceDefaultTables(mgr, shouldDropFirst); } private String addFileSeperator(String appLocation) { int strLength = appLocation.length(); if (appLocation.substring(strLength -1, strLength).equals(File.separator)) return appLocation; else return appLocation + File.separator; } }