1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
|
/*******************************************************************************
* Copyright (c) 1998, 2014 Oracle and/or its affiliates, IBM Corporation. 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:
* tware, ssmith = 1.0 - Generic JPA deployment (OSGI, EE, SE)
* 11/04/2014 - Rick Curtis
* - 450010 : Add java se test bucket
******************************************************************************/
package org.eclipse.persistence.internal.jpa.deployment;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
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.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;
// Cache the initial puInfos - those used by initialEmSetupImpls
protected Map<String, SEPersistenceUnitInfo> initialPuInfos;
// Cache the initial emSetupImpls - those created and predeployed by JavaSECMPInitializer.initialize method.
protected Map<String, EntityManagerSetupImpl> initialEmSetupImpls;
// Initializers keyed by their initializationClassloaders
protected static Map<ClassLoader, JPAInitializer> initializers = new Hashtable();
/**
* 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, String persistenceUnitUniqueName, String sessionName) {
AbstractSessionLog.getLog().log(SessionLog.FINER, SessionLog.JPA, "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, m);
// Create the temp loader that will not cache classes for entities in our persistence unit
ClassLoader tempLoader = createTempLoader(tempLoaderSet);
persistenceUnitInfo.setNewTempClassLoader(tempLoader);
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.
persistenceUnitInfo.setNewTempClassLoader(persistenceUnitInfo.getClassLoader());
registerTransformer(transformer, persistenceUnitInfo, m);
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) {
SEPersistenceUnitInfo persistenceUnitInfo = null;
if(initialPuInfos != null) {
persistenceUnitInfo = initialPuInfos.get(puName);
}
if(persistenceUnitInfo != null) {
return persistenceUnitInfo;
}
persistenceUnitInfo = (SEPersistenceUnitInfo) m.get(PersistenceUnitProperties.ECLIPSELINK_SE_PUINFO);
if (persistenceUnitInfo != null) {
return persistenceUnitInfo;
}
return findPersistenceUnitInfoInArchives(puName, m);
}
/**
* 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) {
SEPersistenceUnitInfo persistenceUnitInfo = null;
// mkeith - get resource name from prop and include in subsequent call
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);
}
try {
for (Archive archive: pars) {
persistenceUnitInfo = findPersistenceUnitInfoInArchive(puName, archive, m);
if(persistenceUnitInfo != null) {
break;
}
}
} finally {
for (Archive archive: pars) {
archive.close();
}
}
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){
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, SessionLog.JPA, "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, Map properties);
/**
* 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());
}
public EntityManagerSetupImpl extractInitialEmSetupImpl(String puName) {
if(this.initialEmSetupImpls != null) {
return this.initialEmSetupImpls.remove(puName);
} else {
return null;
}
}
/**
* This method initializes the container. Essentially, it will try to load the
* class that contains the list of entities and reflectively call the method that
* contains that list. It will then initialize the container with that list.
*/
public void initialize(Map m) {
boolean keepInitialMaps = keepAllPredeployedPersistenceUnits();
if(keepInitialMaps) {
this.initialPuInfos = new HashMap();
}
// always create initialEmSetupImpls - it's used to check for puName uniqueness in initPersistenceUnits
this.initialEmSetupImpls = new HashMap();
// ailitchev - copied from findPersistenceUnitInfoInArchives: mkeith - get resource name from prop and include in subsequent call
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);
}
try {
for (Archive archive: pars) {
AbstractSessionLog.getLog().log(SessionLog.FINER, SessionLog.JPA, "cmp_init_initialize", archive);
initPersistenceUnits(archive, m);
}
} finally {
for (Archive archive: pars) {
archive.close();
}
this.initialEmSetupImpls = null;
}
}
/**
* Initialize all persistence units found on initializationClassLoader.
* Initialization is a two phase process. First the predeploy process builds the metadata
* and creates any required transformers.
* Second the deploy process creates an EclipseLink session based on that metadata.
*/
protected void initPersistenceUnits(Archive archive, Map m){
Iterator<SEPersistenceUnitInfo> persistenceUnits = PersistenceUnitProcessor.getPersistenceUnits(archive, initializationClassloader).iterator();
while (persistenceUnits.hasNext()) {
SEPersistenceUnitInfo persistenceUnitInfo = persistenceUnits.next();
if(isPersistenceProviderSupported(persistenceUnitInfo.getPersistenceProviderClassName())) {
// puName uniquely defines the pu on a class loader
String puName = persistenceUnitInfo.getPersistenceUnitName();
// don't add puInfo that could not be used standalone (only as composite member).
if (EntityManagerSetupImpl.mustBeCompositeMember(persistenceUnitInfo)) {
continue;
}
// If puName is already in the map then there are two jars containing persistence units with the same name.
// Because both are loaded from the same classloader there is no way to distinguish between them - throw exception.
EntityManagerSetupImpl anotherEmSetupImpl = null;
if (initialEmSetupImpls != null){
anotherEmSetupImpl = this.initialEmSetupImpls.get(puName);
}
if(anotherEmSetupImpl != null) {
EntityManagerSetupImpl.throwPersistenceUnitNameAlreadyInUseException(puName, persistenceUnitInfo, anotherEmSetupImpl.getPersistenceUnitInfo());
}
// Note that session name is extracted only from puInfo, the passed properties ignored.
String sessionName = EntityManagerSetupImpl.getOrBuildSessionName(Collections.emptyMap(), persistenceUnitInfo, puName);
EntityManagerSetupImpl emSetupImpl = callPredeploy(persistenceUnitInfo, m, puName, sessionName);
if (initialEmSetupImpls != null){
this.initialEmSetupImpls.put(puName, emSetupImpl);
}
if (initialPuInfos != null){
this.initialPuInfos.put(puName, persistenceUnitInfo);
}
}
}
}
/**
* Indicates whether initialPuInfos and initialEmSetupImpls are used.
*/
protected boolean keepAllPredeployedPersistenceUnits() {
return false;
}
public ClassLoader getInitializationClassLoader() {
return this.initializationClassloader;
}
}
|