| /******************************************************************************* |
| * Copyright (c) 1998, 2008 Oracle. All rights reserved. |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 |
| * which accompanies this distribution. |
| * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html |
| * and the Eclipse Distribution License is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * Contributors: |
| * mkeith - Gemini JPA work (INCUBATION) |
| * |
| * This code is being developed under INCUBATION and is not currently included |
| * in the automated EclipseLink build. The API in this code may change, or |
| * may never be included in the product. Please provide feedback through mailing |
| * lists or the bug database. |
| ******************************************************************************/ |
| package org.eclipse.persistence.internal.jpa.deployment; |
| |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.net.URL; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import javax.persistence.spi.ClassTransformer; |
| import javax.persistence.spi.PersistenceUnitInfo; |
| |
| import org.eclipse.gemini.jpa.GeminiUtil; |
| import org.eclipse.persistence.config.PersistenceUnitProperties; |
| import org.eclipse.persistence.exceptions.ValidationException; |
| import org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider; |
| import org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl; |
| import org.eclipse.persistence.jpa.Archive; |
| import org.eclipse.persistence.jpa.PersistenceProvider; |
| import org.eclipse.persistence.logging.AbstractSessionLog; |
| import org.eclipse.persistence.logging.SessionLog; |
| |
| /** |
| * Base class for all JPA initialization classes. This is an abstract class that provides the framework |
| * for JPA initialization (finding and initializing persistence units). Subclasses implement the abstract methods |
| * to provide customized functionality |
| * |
| * @see JavaSESMPInitializer |
| * @see OSGiInitializer |
| * @See EquinoxInitializer |
| * @author tware |
| * |
| */ |
| public abstract class JPAInitializer { |
| |
| // The internal loader is used by applications that do weaving to pre load classes |
| // When this flag is set to false, we will not be able to weave. |
| protected boolean shouldCreateInternalLoader = true; |
| |
| protected ClassLoader initializationClassloader = null; |
| |
| /** |
| * Initialize the logging file if it is specified by the system property. |
| */ |
| public static void initializeTopLinkLoggingFile() { |
| String loggingFile = System.getProperty(PersistenceUnitProperties.LOGGING_FILE); |
| try { |
| if (loggingFile != null) { |
| AbstractSessionLog.getLog().setWriter(new FileWriter(loggingFile)); |
| } |
| } catch (IOException e) { |
| AbstractSessionLog.getLog().log(SessionLog.WARNING, "cmp_init_default_logging_file_is_invalid",loggingFile,e); |
| } |
| } |
| |
| /** |
| * predeploy (with deploy) is one of the two steps required in deployment of entities |
| * This method will prepare to call predeploy, call it and finally register the |
| * transformer returned to be used for weaving. |
| */ |
| public EntityManagerSetupImpl callPredeploy(SEPersistenceUnitInfo persistenceUnitInfo, Map m, PersistenceInitializationHelper persistenceHelper, String persistenceUnitUniqueName, String sessionName) { |
| AbstractSessionLog.getLog().log(SessionLog.FINER, "cmp_init_invoke_predeploy", persistenceUnitInfo.getPersistenceUnitName()); |
| Map mergedProperties = EntityManagerFactoryProvider.mergeMaps(m, persistenceUnitInfo.getProperties()); |
| // Bug#4452468 When globalInstrumentation is null, there is no weaving |
| checkWeaving(mergedProperties); |
| |
| Set tempLoaderSet = PersistenceUnitProcessor.buildClassSet(persistenceUnitInfo, persistenceHelper.getClassLoader(persistenceUnitInfo.getPersistenceUnitName(), m)); |
| // Create the temp loader that will not cache classes for entities in our persistence unit |
| ClassLoader tempLoader = createTempLoader(tempLoaderSet); |
| ((SEPersistenceUnitInfo)persistenceUnitInfo).setNewTempClassLoader(tempLoader); |
| ((SEPersistenceUnitInfo)persistenceUnitInfo).setClassLoader(persistenceHelper.getClassLoader(persistenceUnitInfo.getPersistenceUnitName(), m)); |
| |
| EntityManagerSetupImpl emSetupImpl = new EntityManagerSetupImpl(persistenceUnitUniqueName, sessionName); |
| |
| // A call to predeploy will partially build the session we will use |
| final ClassTransformer transformer = emSetupImpl.predeploy(persistenceUnitInfo, mergedProperties); |
| |
| // After preDeploy it's impossible to weave again - so may substitute the temporary classloader with the real one. |
| // The temporary classloader could be garbage collected even if the puInfo is cached for the future use by other emSetupImpls. |
| ((SEPersistenceUnitInfo)persistenceUnitInfo).setNewTempClassLoader(((SEPersistenceUnitInfo)persistenceUnitInfo).getClassLoader()); |
| |
| registerTransformer(transformer, persistenceUnitInfo); |
| return emSetupImpl; |
| } |
| |
| /** |
| * Check whether weaving is possible and update the properties and variable as appropriate |
| * @param properties The list of properties to check for weaving and update if weaving is not needed |
| */ |
| public abstract void checkWeaving(Map properties); |
| |
| /** |
| * Create a temporary class loader that can be used to inspect classes and then |
| * thrown away. This allows classes to be introspected prior to loading them |
| * with application's main class loader enabling weaving. |
| */ |
| protected abstract ClassLoader createTempLoader(Collection col); |
| |
| protected abstract ClassLoader createTempLoader(Collection col, boolean shouldOverrideLoadClassForCollectionMembers); |
| |
| /** |
| * Find PersistenceUnitInfo corresponding to the persistence unit name. |
| * Returns null if either persistence unit either not found or provider is not supported. |
| */ |
| public SEPersistenceUnitInfo findPersistenceUnitInfo(String puName, Map m, PersistenceInitializationHelper persistenceHelper) { |
| SEPersistenceUnitInfo persistenceUnitInfo = null; |
| if(EntityManagerFactoryProvider.initialPuInfos != null) { |
| persistenceUnitInfo = EntityManagerFactoryProvider.initialPuInfos.get(puName); |
| if(persistenceUnitInfo != null) { |
| return persistenceUnitInfo; |
| } |
| } |
| return findPersistenceUnitInfoInArchives(puName, m, persistenceHelper); |
| } |
| |
| /** |
| * Find PersistenceUnitInfo corresponding to the persistence unit name. |
| * Returns null if either persistence unit either not found or provider is not supported. |
| */ |
| protected SEPersistenceUnitInfo findPersistenceUnitInfoInArchives(String puName, Map m, PersistenceInitializationHelper persistenceHelper) { |
| SEPersistenceUnitInfo persistenceUnitInfo = null; |
| // mkeith - get resource name from prop and include in subsequent call |
| GeminiUtil.debug("JPAInit - findPersistenceUnitInfoInArchives, props = ", m); |
| String descriptorPath = (String) m.get(PersistenceUnitProperties.ECLIPSELINK_PERSISTENCE_XML); |
| final Set<Archive> pars; |
| if (descriptorPath != null) { |
| pars = PersistenceUnitProcessor.findPersistenceArchives(initializationClassloader, descriptorPath); |
| } else { |
| pars = PersistenceUnitProcessor.findPersistenceArchives(initializationClassloader); |
| } |
| for (Archive archive: pars) { |
| persistenceUnitInfo = findPersistenceUnitInfoInArchive(puName, archive, m, persistenceHelper); |
| if(persistenceUnitInfo != null) { |
| break; |
| } |
| } |
| return persistenceUnitInfo; |
| } |
| |
| /** |
| * Find PersistenceUnitInfo corresponding to the persistence unit name in the archive. |
| * Returns null if either persistence unit either not found or provider is not supported. |
| */ |
| protected SEPersistenceUnitInfo findPersistenceUnitInfoInArchive(String puName, Archive archive, Map m, PersistenceInitializationHelper persistenceActivator){ |
| GeminiUtil.debug("JPAInit - findPersistenceUnitInfoInArchive, puName = ", puName); |
| Iterator<SEPersistenceUnitInfo> persistenceUnits = PersistenceUnitProcessor.getPersistenceUnits(archive, initializationClassloader).iterator(); |
| while (persistenceUnits.hasNext()) { |
| SEPersistenceUnitInfo persistenceUnitInfo = persistenceUnits.next(); |
| if(isPersistenceProviderSupported(persistenceUnitInfo.getPersistenceProviderClassName()) && persistenceUnitInfo.getPersistenceUnitName().equals(puName)) { |
| return persistenceUnitInfo; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Returns whether the given persistence provider class is supported by this implementation |
| * @param providerClassName |
| * @return |
| */ |
| public boolean isPersistenceProviderSupported(String providerClassName){ |
| return (providerClassName == null) || providerClassName.equals("") || providerClassName.equals(EntityManagerFactoryProvider.class.getName()) || providerClassName.equals(PersistenceProvider.class.getName()); |
| } |
| |
| /** |
| * Create a list of java.lang.Class that contains the classes of all the entities |
| * that we will be deploying. |
| */ |
| protected Set loadEntityClasses(Collection entityNames, ClassLoader classLoader) { |
| Set entityClasses = new HashSet(); |
| |
| // Load the classes using the loader passed in |
| AbstractSessionLog.getLog().log(SessionLog.FINER, "cmp_loading_entities_using_loader", classLoader); |
| for (Iterator iter = entityNames.iterator(); iter.hasNext();) { |
| String entityClassName = (String)iter.next(); |
| try { |
| entityClasses.add(classLoader.loadClass(entityClassName)); |
| } catch (ClassNotFoundException cnfEx) { |
| throw ValidationException.entityClassNotFound(entityClassName, classLoader, cnfEx); |
| } |
| } |
| return entityClasses; |
| } |
| |
| /** |
| * Register a transformer. This method should be overridden to provide the appropriate transformer |
| * registration for the environment |
| * @param transformer |
| * @param persistenceUnitInfo |
| */ |
| public abstract void registerTransformer(final ClassTransformer transformer, PersistenceUnitInfo persistenceUnitInfo); |
| |
| /** |
| * Indicates whether puName uniquely defines the persistence unit. |
| */ |
| public boolean isPersistenceUnitUniquelyDefinedByName() { |
| return true; |
| } |
| |
| /** |
| * In case persistence unit is not uniquely defined by name |
| * this method is called to generate a unique name. |
| */ |
| public String createUniquePersistenceUnitName(PersistenceUnitInfo puInfo) { |
| return PersistenceUnitProcessor.buildPersistenceUnitName(puInfo.getPersistenceUnitRootUrl(), puInfo.getPersistenceUnitName()); |
| } |
| } |