Tom, Andrei, Wonseok,
Attached is the changed file with the ideas for fixing this problem. I
didn't test it yet, but would like to start the discussion as the practice
shows that changing EMSetupImpl is a painful exercise.
Probably the main change for you guys is replacing void with a boolean
as the returning type for updateSessionName(). Please do not panic, but
suggest your ideas if you don't like it - I need to know if the name has
changed and would like to avoid saving the name, then comparing it again
after it had been replaced or not: the comparison is done inside the method
anyway. Keep in mind that if the server platform has changed, I need the
new session name before fixing the loggers.
As you can see, in case of the server platform change, all of the loggers
need to be replaced (we can probably go further and check the actual logger
type change, but I don't think it's worth the effort), in particular when
the value is unset in the Map.
If only the session name change, it seems to be enough to update the session
in the existing logger (and do not touch the default logger at all).
Wonseok, that also meant moving initOrUpdateLogging() outside the
updateLoggers() call. I also removed parameters from the method signature
where they are available as instance variable.
If you all agree, I'll start running the tests. If not, I'd like to sort
everything out before going further.
thanks,
-marina
/*
* 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, 2006, Oracle. All rights reserved.
package oracle.toplink.essentials.internal.ejb.cmp3;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.util.*;
import java.lang.reflect.Constructor;
import javax.persistence.spi.PersistenceUnitInfo;
import javax.persistence.spi.ClassTransformer;
import javax.persistence.PersistenceException;
import oracle.toplink.essentials.config.TopLinkProperties;
import oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider;
import oracle.toplink.essentials.internal.databaseaccess.DatasourcePlatform;
import oracle.toplink.essentials.internal.ejb.cmp3.base.PropertiesHandler;
import oracle.toplink.essentials.internal.weaving.TransformerFactory;
import oracle.toplink.essentials.jndi.JNDIConnector;
import oracle.toplink.essentials.logging.AbstractSessionLog;
import oracle.toplink.essentials.logging.DefaultSessionLog;
import oracle.toplink.essentials.logging.SessionLog;
import oracle.toplink.essentials.internal.security.PrivilegedAccessHelper;
import oracle.toplink.essentials.internal.security.PrivilegedClassForName;
import oracle.toplink.essentials.internal.sessions.AbstractSession;
import oracle.toplink.essentials.sequencing.Sequence;
import oracle.toplink.essentials.sessions.*;
import oracle.toplink.essentials.threetier.ReadConnectionPool;
import oracle.toplink.essentials.threetier.ServerSession;
import oracle.toplink.essentials.internal.ejb.cmp3.metadata.MetadataProcessor;
import oracle.toplink.essentials.tools.sessionmanagement.SessionManager;
import oracle.toplink.essentials.descriptors.ClassDescriptor;
import oracle.toplink.essentials.internal.ejb.cmp3.base.CMP3Policy;
import oracle.toplink.essentials.platform.server.CustomServerPlatform;
import oracle.toplink.essentials.platform.server.ServerPlatform;
import oracle.toplink.essentials.platform.server.NoServerPlatform;
import oracle.toplink.essentials.exceptions.*;
import oracle.toplink.essentials.internal.helper.EJB30ConversionManager;
import javax.persistence.spi.PersistenceUnitTransactionType;
import oracle.toplink.essentials.internal.ejb.cmp3.jdbc.base.DataSourceImpl;
import oracle.toplink.essentials.tools.sessionconfiguration.DescriptorCustomizer;
import oracle.toplink.essentials.tools.sessionconfiguration.SessionCustomizer;
import oracle.toplink.essentials.internal.security.SecurableObjectHolder;
import static oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider.*;
/**
* INTERNAL:
* A TopLink specific implementer of the EntityManagerInitializer interface.
*/
public class EntityManagerSetupImpl {
/*
* Design Pattern in use: Builder pattern
* EntityManagerSetupImpl, MetadataProcessor and MetadataProject
* play the role of director, builder and product respectively.
* See processORMetadata which is the factory method.
*/
protected MetadataProcessor processor = null;
protected PersistenceUnitInfo persistenceUnitInfo = null;
protected Map predeployProperties = null;
// may be positive only in STATE_DEPLOYED
protected int deploymentCount = 0;
protected ServerSession session = null;
protected ServerPlatform serverPlatform = null;
protected boolean isInContainerMode = false;
// indicates whether weaving was used on the first run through predeploy (in STATE_INITIAL)
protected boolean enableLazyForOneToOne = false;
protected SecurableObjectHolder securableObjectHolder = new SecurableObjectHolder();
public static final String STATE_INITIAL = "Initial";
public static final String STATE_PREDEPLOYED = "Predeployed";
public static final String STATE_DEPLOYED = "Deployed";
public static final String STATE_UNDEPLOYED = "Undeployed";
protected String state = STATE_INITIAL;
public static final String ERROR_LOADING_XML_FILE = "error_loading_xml_file";
public static final String EXCEPTION_LOADING_ENTITY_CLASS = "exception_loading_entity_class";
/**
* This method can be used to ensure the session represented by emSetupImpl
* is removed from the SessionManager.
*/
protected void removeSessionFromGlobalSessionManager() {
if (session != null){
if(session.isConnected()) {
session.logout();
}
SessionManager.getManager().getSessions().remove(session.getName());
}
}
/**
* 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 @MappedSuperclass 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 loader
* @return
*/
private Collection<Class> buildEntityList(ClassLoader loader) {
ArrayList<Class> entityList = new ArrayList<Class>();
for (String className : processor.getProject().getEntityNames()) {
try {
Class entityClass = loader.loadClass(className);
entityList.add(entityClass);
} catch (ClassNotFoundException exc) {
AbstractSessionLog.getLog().log(SessionLog.WARNING,
"exception_loading_entity_class", className, exc);
}
}
return entityList;
}
/**
* Deploy a persistence session and return an EntityManagerFactory.
*
* Deployment takes a session that was partially created in the predeploy call and makes it whole.
*
* This means doing any configuration that requires the real class definitions for the entities. In
* the predeploy phase we were in a stage where we were not let allowed to load the real classes.
*
* Deploy could be called several times - but only the first call does the actual deploying -
* additional calls allow to update session properties (provided the session is not connected) and
* encrease deploymentCount (which decreased by calls to undeploy method).
*
* @param realClassLoader The class loader that was used to load the entity classes. This loader
* will be maintained for the lifespan of the loaded classes.
* @param additionalProperties added to predeployProperties for updateServerSession overriding existing properties.
* In JSE case it allows to alter properties in main (as opposed to preMain where preDeploy is called).
* @return An EntityManagerFactory to be used by the Container to obtain EntityManagers
*/
public synchronized ServerSession deploy(ClassLoader realClassLoader, Map additionalProperties) {
if(state != STATE_PREDEPLOYED && state != STATE_DEPLOYED) {
throw new PersistenceException(EntityManagerSetupException.cannotDeployWithoutPredeploy(persistenceUnitInfo.getPersistenceUnitName()));
}
session.log(SessionLog.FINEST, SessionLog.PROPERTIES, "deploy_begin", new Object[]{getPersistenceUnitInfo().getPersistenceUnitName(), state, deploymentCount});
try {
Map deployProperties = mergeMaps(additionalProperties, predeployProperties);
translateOldProperties(deployProperties, session);
if(state == STATE_PREDEPLOYED) {
// The project is initially created using class names rather than classes. This call will make the conversion
session.getProject().convertClassNamesToClasses(realClassLoader);
// listeners and queries require the real classes and are therefore built during deploy using the realClassLoader
processor.setClassLoader(realClassLoader);
processor.addEntityListeners();
processor.addNamedQueries();
// free the resouces that we don't need any more.
processor.cleanup();
processor = null;
initServerSession(deployProperties);
if (session.getIntegrityChecker().hasErrors()){
session.handleException(new IntegrityException(session.getIntegrityChecker()));
}
session.getDatasourcePlatform().getConversionManager().setLoader(realClassLoader);
}
deploymentCount++;
state = STATE_DEPLOYED;
try{
updateServerSession(deployProperties);
if(!session.isConnected()) {
if(isValidationOnly(deployProperties, false)) {
session.initializeDescriptors();
} else {
login(session, deployProperties);
generateDDLFiles(session, deployProperties, !isInContainerMode);
}
}
} catch (RuntimeException exception) {
cleanUpSessionManager();
throw exception;
}
return session;
} catch (oracle.toplink.essentials.exceptions.ValidationException exception) {
throw new javax.persistence.PersistenceException(exception);
} finally {
session.log(SessionLog.FINEST, SessionLog.PROPERTIES, "deploy_end", new Object[]{getPersistenceUnitInfo().getPersistenceUnitName(), state, deploymentCount});
if(state == STATE_UNDEPLOYED) {
session = null;
}
}
}
/**
* INTERNAL:
* Adds descriptors plus sequencing info found on the project to the session.
*/
protected void addProjectToSession(ServerSession session, Project project) {
DatasourcePlatform sessionPlatform = (DatasourcePlatform)session.getDatasourceLogin().getDatasourcePlatform();
DatasourcePlatform projectPlatform = (DatasourcePlatform)project.getDatasourceLogin().getDatasourcePlatform();
if (!sessionPlatform.hasDefaultSequence() && projectPlatform.hasDefaultSequence()) {
sessionPlatform.setDefaultSequence(projectPlatform.getDefaultSequence());
}
if ((sessionPlatform.getSequences() == null) || sessionPlatform.getSequences().isEmpty()) {
if ((projectPlatform.getSequences() != null) && !projectPlatform.getSequences().isEmpty()) {
sessionPlatform.setSequences(projectPlatform.getSequences());
}
} else {
if ((projectPlatform.getSequences() != null) && !projectPlatform.getSequences().isEmpty()) {
Iterator itProjectSequences = projectPlatform.getSequences().values().iterator();
while (itProjectSequences.hasNext()) {
Sequence sequence = (Sequence)itProjectSequences.next();
if (!sessionPlatform.getSequences().containsKey(sequence.getName())) {
sessionPlatform.addSequence(sequence);
}
}
}
}
session.addDescriptors(project);
}
/**
* INTERNAL:
* Put the given session into the session manager so it can be looked up later
*/
protected void addSessionToGlobalSessionManager() {
AbstractSession oldSession = (AbstractSession)SessionManager.getManager().getSessions().get(session.getName());
if(oldSession != null) {
throw new PersistenceException(EntityManagerSetupException.attemptedRedeployWithoutClose(session.getName()));
}
SessionManager.getManager().addSession(session);
}
/**
* INTERNAL:
* Assign a CMP3Policy to each descriptor
*/
protected void assignCMP3Policy() {
// all descriptors assigned CMP3Policy
Project project = session.getProject();
for (Iterator iterator = project.getDescriptors().values().iterator(); iterator.hasNext();){
//bug:4406101 changed class cast to base class, which is used in projects generated from 904 xml
ClassDescriptor descriptor = (ClassDescriptor)iterator.next();
if(descriptor.getCMPPolicy() == null) {
descriptor.setCMPPolicy(new CMP3Policy());
}
}
}
/**
* INTERNAL:
* Sets or updates the TopLink ServerPlatform class for use with this platform.
* @returns true if the ServerPlatform has changed.
*/
protected boolean setOrUpdateServerPlatform(Map m) {
String serverPlatformClassName = (String)PropertiesHandler.getPropertyValueLogDebug(TopLinkProperties.TARGET_SERVER, m, session);
if (serverPlatformClassName == null || serverPlatformClassName.length() == 0) {
if (serverPlatform != null) {
// Change from set to none - use the default and update the session
serverPlatform = new NoServerPlatform(session);
} else {
// nothing to do - use the defaults as before.
return false;
}
} else if (serverPlatform == null || !serverPlatform.getClass().getName().equals(serverPlatformClassName)) {
// New platform - create the new instance and set it.
Class cls = findClassForProperty(serverPlatformClassName, TopLinkProperties.TARGET_SERVER);
try {
Constructor constructor = cls.getConstructor(new Class[]{oracle.toplink.essentials.internal.sessions.DatabaseSessionImpl.class});
serverPlatform = (ServerPlatform)constructor.newInstance(new Object[]{session});
} catch (Exception ex) {
if(ExternalTransactionController.class.isAssignableFrom(cls)) {
CustomServerPlatform customServerPlatform = new CustomServerPlatform(session);
customServerPlatform.setExternalTransactionControllerClass(cls);
serverPlatform = customServerPlatform;
} else {
throw EntityManagerSetupException.failedToInstantiateServerPlatform(serverPlatformClassName, TopLinkProperties.TARGET_SERVER, ex);
}
}
} else {
// nothing to do - use the same value as before
return false;
}
if (serverPlatform != null){
session.setServerPlatform(serverPlatform);
}
return true;
}
/**
* INTERNAL:
* Update loggers and settings for the singleton logger and the session logger.
*/
protected void updateLoggers(Map m){
// Logger(SessionLog type) can be specified by the logger property or ServerPlatform.getServerLog().
// The logger property has a higher priority to ServerPlatform.getServerLog().
String loggerClassName = PropertiesHandler.getPropertyValueLogDebug(TopLinkProperties.LOGGING_LOGGER, m, session);
Class sessionLogClass = null;
if (loggerClassName != null) {
sessionLogClass = findClassForProperty(loggerClassName, TopLinkProperties.LOGGING_LOGGER);
}
// Set loggers for the singleton logger and the session logger.
// sessionLog instance should be different from singletonLog because two log have different state.
SessionLog singletonLog = null, sessionLog = null;
if(sessionLogClass != null){
try {
singletonLog = (SessionLog)sessionLogClass.newInstance();
sessionLog = (SessionLog)sessionLogClass.newInstance();
} catch (Exception ex) {
throw EntityManagerSetupException.failedToInstantiateLogger(loggerClassName, TopLinkProperties.LOGGING_LOGGER, ex);
}
} else if(serverPlatform != null){
// if ServerPlatform.getServerLog() returns null, we won't set loggers
singletonLog = serverPlatform.getServerLog();
sessionLog = serverPlatform.getServerLog();
}
// Don't change default loggers if null , but reset them if null is a new value
if (singletonLog != null && sessionLog != null){
AbstractSessionLog.setLog(singletonLog);
session.setSessionLog(sessionLog);
} else if (!(AbstractSessionLog.getLog() instanceof DefaultSessionLog)) {
AbstractSessionLog.setLog(new DefaultSessionLog());
session.setSessionLog(new DefaultSessionLog());
}
}
protected static Class findClass(String className) throws ClassNotFoundException, PrivilegedActionException {
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
return (Class)AccessController.doPrivileged(new PrivilegedClassForName(className));
} else {
return oracle.toplink.essentials.internal.security.PrivilegedAccessHelper.getClassForName(className);
}
}
protected static Class findClassForProperty(String className, String propertyName) {
try {
return findClass(className);
} catch (PrivilegedActionException exception1) {
throw EntityManagerSetupException.classNotFoundForProperty(className, propertyName, exception1.getException());
} catch (ClassNotFoundException exception2) {
throw EntityManagerSetupException.classNotFoundForProperty(className, propertyName, exception2);
}
}
protected void updateDescriptorCacheSettings(Map m) {
Map typeMap = PropertiesHandler.getPrefixValuesLogDebug(TopLinkProperties.CACHE_TYPE_, m, session);
Map sizeMap = PropertiesHandler.getPrefixValuesLogDebug(TopLinkProperties.CACHE_SIZE_, m, session);
Map sharedMap = PropertiesHandler.getPrefixValuesLogDebug(TopLinkProperties.CACHE_SHARED_, m, session);
if(typeMap.isEmpty() && sizeMap.isEmpty() && sharedMap.isEmpty()) {
return;
}
boolean hasDefault = false;
String defaultTypeName = (String)typeMap.remove(TopLinkProperties.DEFAULT);
Class defaultType = null;
if(defaultTypeName != null) {
defaultType = findClassForProperty(defaultTypeName, TopLinkProperties.CACHE_TYPE_DEFAULT);
hasDefault = true;
}
String defaultSizeString = (String)sizeMap.remove(TopLinkProperties.DEFAULT);
Integer defaultSize = null;
if(defaultSizeString != null) {
defaultSize = Integer.parseInt(defaultSizeString);
hasDefault = true;
}
String defaultSharedString = (String)sharedMap.remove(TopLinkProperties.DEFAULT);
Boolean defaultShared = null;
if(defaultSharedString != null) {
defaultShared = Boolean.parseBoolean(defaultSharedString);
hasDefault = true;
}
Iterator it = session.getDescriptors().values().iterator();
while (it.hasNext() && (hasDefault || !typeMap.isEmpty() || !sizeMap.isEmpty() || !sharedMap.isEmpty())) {
ClassDescriptor descriptor = (ClassDescriptor)it.next();
if(descriptor.isAggregateDescriptor() || descriptor.isAggregateCollectionDescriptor()) {
continue;
}
String entityName = descriptor.getAlias();
String className = descriptor.getJavaClass().getName();
String name;
Class type = defaultType;
name = entityName;
String typeName = (String)typeMap.remove(name);
if(typeName == null) {
name = className;
typeName = (String)typeMap.remove(name);
}
if(typeName != null) {
type = findClassForProperty(typeName, TopLinkProperties.CACHE_TYPE_ + name);
}
if(type != null) {
descriptor.setIdentityMapClass(type);
}
Integer size = defaultSize;
name = entityName;
String sizeString = (String)sizeMap.remove(name);
if(sizeString == null) {
name = className;
sizeString = (String)sizeMap.remove(name);
}
if(sizeString != null) {
size = Integer.parseInt(sizeString);
}
if(size != null) {
descriptor.setIdentityMapSize(size.intValue());
}
Boolean shared = defaultShared;
name = entityName;
String sharedString = (String)sharedMap.remove(name);
if(sharedString == null) {
name = className;
sharedString = (String)sharedMap.remove(name);
}
if(sharedString != null) {
shared = Boolean.parseBoolean(sharedString);
}
if(shared != null) {
descriptor.setIsIsolated(!shared.booleanValue());
}
}
}
/**
* Perform any steps necessary prior to actual deployment. This includes any steps in the session
* creation that do not require the real loaded domain classes.
*
* @return A transformer (which may be null) that should be plugged into the proper
* classloader to allow classes to be transformed as they get loaded.
* @see #predeploy(javax.persistence.spi.PersistenceUnitInfo, java.util.Map)
*/
public ClassTransformer predeploy(PersistenceUnitInfo info, Map extendedProperties) {
if(state == STATE_INITIAL) {
persistenceUnitInfo = info;
}
ClassLoader privateClassLoader = persistenceUnitInfo.getNewTempClassLoader();
predeployProperties = mergeMaps(extendedProperties, persistenceUnitInfo.getProperties());
// translate old properties
// this should be done before using properties (i.e. ServerPlatform)
translateOldProperties(predeployProperties, null);
// create server session (it should be done before initializing ServerPlatform)
session = new ServerSession(new Project(new DatabaseLogin()));
// ServerSession name must be set prior to setting the loggers.
setServerSessionName(predeployProperties);
setOrUpdateServerPlatform(predeployProperties);
// Update loggers and settings for the singleton logger and the session logger.
updateLoggers(predeployProperties);
//Bug5389828. Update the logging settings for the singleton logger.
initOrUpdateLogging(true, predeployProperties, AbstractSessionLog.getLog());
initOrUpdateLogging(true, predeployProperties, session.getSessionLog());
warnOldProperties(predeployProperties, session);
session.getPlatform().setConversionManager(new EJB30ConversionManager());
if(!isValidationOnly(predeployProperties, false) && persistenceUnitInfo != null && persistenceUnitInfo.getTransactionType() == PersistenceUnitTransactionType.JTA) {
if(persistenceUnitInfo.getJtaDataSource() == null) {
throw new PersistenceException(EntityManagerSetupException.jtaPersistenceUnitInfoMissingJtaDataSource(persistenceUnitInfo.getPersistenceUnitName()));
}
}
// this flag is used to disable work done as a result of the LAZY hint on OneToOne mappings
if(state == STATE_INITIAL ) {
enableLazyForOneToOne = true;
String weaving = getConfigPropertyAsString(TopLinkProperties.WEAVING);
if (weaving != null && weaving.equalsIgnoreCase("false")) {
enableLazyForOneToOne = false;
}
}
// Process the Object/relational metadata from XML and annotations.
processORMetadata(privateClassLoader, session, enableLazyForOneToOne);
// The connector will be reconstructed when the session is actually deployed
session.getProject().getLogin().setConnector(new DefaultConnector());
if (session.getIntegrityChecker().hasErrors()){
session.handleException(new IntegrityException(session.getIntegrityChecker()));
}
// The transformer is capable of altering domain classes to handle a LAZY hint for OneToOne mappings. It will only
// be returned if we we are mean to process these mappings
ClassTransformer transformer = null;
if (enableLazyForOneToOne){
// build a list of entities the persistence unit represented by this EntityManagerSetupImpl will use
Collection entities = buildEntityList(privateClassLoader);
transformer = TransformerFactory.createTransformerAndModifyProject(session, entities, privateClassLoader);
}
state = STATE_PREDEPLOYED;
return transformer;
}
/**
* Check the provided map for an object with the given key. If that object is not available, check the
* System properties. If it is not available from either location, return the default value.
* @param propertyKey
* @param defaultValue
* @return
*/
public String getConfigPropertyAsString(String propertyKey, String defaultValue){
return getConfigPropertyAsStringLogDebug(propertyKey, predeployProperties, defaultValue, session);
}
public String getConfigPropertyAsString(String propertyKey){
return getConfigPropertyAsStringLogDebug(propertyKey, predeployProperties, session);
}
/**
* Return the name of the session this SetupImpl is building. The session name is only known at deploy
* time and if this method is called prior to that, this method will return null.
* @return
*/
public String getDeployedSessionName(){
return session != null ? session.getName() : null;
}
public PersistenceUnitInfo getPersistenceUnitInfo(){
return persistenceUnitInfo;
}
public boolean isValidationOnly(Map m) {
return isValidationOnly(m, true);
}
protected boolean isValidationOnly(Map m, boolean shouldMergeMap) {
if(shouldMergeMap) {
m = mergeWithExistingMap(m);
}
String validationOnlyString = getConfigPropertyAsStringLogDebug(TOPLINK_VALIDATION_ONLY_PROPERTY, m, session);
if(validationOnlyString != null) {
return Boolean.parseBoolean(validationOnlyString);
} else {
return false;
}
}
public boolean shouldGetSessionOnCreateFactory(Map m) {
m = mergeWithExistingMap(m);
return isValidationOnly(m, false);
}
protected Map mergeWithExistingMap(Map m) {
if(predeployProperties != null) {
return mergeMaps(m, predeployProperties);
} else if(persistenceUnitInfo != null) {
return mergeMaps(m, persistenceUnitInfo.getProperties());
} else {
return m;
}
}
public boolean isInContainerMode(){
return isInContainerMode;
}
/**
* Override the default login creation method.
* If persistenceInfo is available, use the information from it to setup the login
* and possibly to set readConnectionPool.
* @param m
*/
protected void updateLogins(Map m){
DatasourceLogin login = session.getLogin();
// Note: This call does not checked the stored persistenceUnitInfo or extended properties because
// the map passed into this method should represent the full set of properties we expect to process
String user = getConfigPropertyAsStringLogDebug(TopLinkProperties.JDBC_USER, m, session);
String password = getConfigPropertyAsStringLogDebug(TopLinkProperties.JDBC_PASSWORD, m, session);
if(user != null) {
login.setUserName(user);
}
if(password != null) {
login.setPassword(securableObjectHolder.getSecurableObject().decryptPassword(password));
}
String toplinkPlatform = (String)PropertiesHandler.getPropertyValueLogDebug(TopLinkProperties.TARGET_DATABASE, m, session);
if (toplinkPlatform != null) {
login.setPlatformClassName(toplinkPlatform);
}
if (isValidationOnly(m, false) && persistenceUnitInfo.getTransactionType() == PersistenceUnitTransactionType.JTA && persistenceUnitInfo.getJtaDataSource() == null){
updateLoginDefaultConnector(login, m);
return;
}
login.setUsesExternalTransactionController(persistenceUnitInfo.getTransactionType() == PersistenceUnitTransactionType.JTA);
javax.sql.DataSource mainDatasource = null;
javax.sql.DataSource readDatasource = null;
if(login.shouldUseExternalTransactionController()) {
// JtaDataSource is guaranteed to be non null - otherwise exception would've been thrown earlier
mainDatasource = persistenceUnitInfo.getJtaDataSource();
// only define readDatasource if there is jta mainDatasource
readDatasource = persistenceUnitInfo.getNonJtaDataSource();
} else {
// JtaDataSource will be ignored because transactionType is RESOURCE_LOCAL
if(persistenceUnitInfo.getJtaDataSource() != null) {
session.log(SessionLog.WARNING, SessionLog.TRANSACTION, "resource_local_persistence_init_info_ignores_jta_data_source", persistenceUnitInfo.getPersistenceUnitName());
}
if(persistenceUnitInfo.getNonJtaDataSource() != null) {
mainDatasource = persistenceUnitInfo.getNonJtaDataSource();
} else {
updateLoginDefaultConnector(login, m);
return;
}
}
// mainDatasource is guaranteed to be non null
if(!(login.getConnector() instanceof JNDIConnector)) {
JNDIConnector jndiConnector;
if (mainDatasource instanceof DataSourceImpl) {
//Bug5209363 Pass in the datasource name instead of the dummy datasource
jndiConnector = new JNDIConnector(((DataSourceImpl)mainDatasource).getName());
} else {
jndiConnector = new JNDIConnector(mainDatasource);
}
login.setConnector(jndiConnector);
login.setUsesExternalConnectionPooling(true);
}
// set readLogin
if(readDatasource != null) {
DatasourceLogin readLogin = (DatasourceLogin)login.clone();
readLogin.dontUseExternalTransactionController();
JNDIConnector jndiConnector;
if (readDatasource instanceof DataSourceImpl) {
//Bug5209363 Pass in the datasource name instead of the dummy datasource
jndiConnector = new JNDIConnector(((DataSourceImpl)readDatasource).getName());
} else {
jndiConnector = new JNDIConnector(readDatasource);
}
readLogin.setConnector(jndiConnector);
session.setReadConnectionPool(readLogin);
}
}
/**
* In cases where there is no data source, we will use properties to configure the login for
* our session. This method gets those properties and sets them on the login.
* @param login
* @param m
*/
protected void updateLoginDefaultConnector(DatasourceLogin login, Map m){
if((login.getConnector() instanceof DefaultConnector)) {
DatabaseLogin dbLogin = (DatabaseLogin)login;
// Note: This call does not checked the stored persistenceUnitInfo or extended properties because
// the map passed into this method should represent the full set of properties we expect to process
String jdbcDriver = getConfigPropertyAsStringLogDebug(TopLinkProperties.JDBC_DRIVER, m, session);
String connectionString = getConfigPropertyAsStringLogDebug(TopLinkProperties.JDBC_URL, m, session);
if(connectionString != null) {
dbLogin.setConnectionString(connectionString);
}
if(jdbcDriver != null) {
dbLogin.setDriverClassName(jdbcDriver);
}
}
}
protected void updatePools(Map m) {
// Sizes are irrelevant for external connection pool
if(!session.getDefaultConnectionPool().getLogin().shouldUseExternalConnectionPooling()) {
String strWriteMin = getConfigPropertyAsStringLogDebug(TopLinkProperties.JDBC_WRITE_CONNECTIONS_MIN, m, session);
if(strWriteMin != null) {
session.getDefaultConnectionPool().setMinNumberOfConnections(Integer.parseInt(strWriteMin));
}
String strWriteMax = getConfigPropertyAsStringLogDebug(TopLinkProperties.JDBC_WRITE_CONNECTIONS_MAX, m, session);
if(strWriteMax != null) {
session.getDefaultConnectionPool().setMaxNumberOfConnections(Integer.parseInt(strWriteMax));
}
}
// Sizes and shared option are irrelevant for external connection pool
if(!session.getReadConnectionPool().getLogin().shouldUseExternalConnectionPooling()) {
String strReadMin = getConfigPropertyAsStringLogDebug(TopLinkProperties.JDBC_READ_CONNECTIONS_MIN, m, session);
if(strReadMin != null) {
session.getReadConnectionPool().setMinNumberOfConnections(Integer.parseInt(strReadMin));
}
String strReadMax = getConfigPropertyAsStringLogDebug(TopLinkProperties.JDBC_READ_CONNECTIONS_MAX, m, session);
if(strReadMax != null) {
session.getReadConnectionPool().setMaxNumberOfConnections(Integer.parseInt(strReadMax));
}
String strShouldUseShared = getConfigPropertyAsStringLogDebug(TopLinkProperties.JDBC_READ_CONNECTIONS_SHARED, m,session);
if(strShouldUseShared != null) {
boolean shouldUseShared = Boolean.parseBoolean(strShouldUseShared);
boolean sessionUsesShared = session.getReadConnectionPool() instanceof ReadConnectionPool;
if(shouldUseShared != sessionUsesShared) {
Login readLogin = session.getReadConnectionPool().getLogin();
int nReadMin = session.getReadConnectionPool().getMinNumberOfConnections();
int nReadMax = session.getReadConnectionPool().getMaxNumberOfConnections();
if(shouldUseShared) {
session.useReadConnectionPool(nReadMin, nReadMax);
} else {
session.useExclusiveReadConnectionPool(nReadMin, nReadMax);
}
// keep original readLogin
session.getReadConnectionPool().setLogin(readLogin);
}
}
}
}
/**
* Normally when a property is missing nothing should be applied to the session.
* However there are several session attributes that defaulted in EJB3 to the values
* different from TopLink defaults (for instance, in TopLink defaults binding to false,
* EJB3 - to true).
* This function applies defaults for such properties and registers the session.
* All other session-related properties are applied in updateServerSession.
* Note that updateServerSession may be called several times on the same session
* (before login), but initServerSession is called just once - before the first call
* to updateServerSession.
* @param m
*/
protected void initServerSession(Map m) {
assignCMP3Policy();
// Register session that has been created earlier.
addSessionToGlobalSessionManager();
// shouldBindAllParameters is true by default - set it if no property provided
if (EntityManagerFactoryProvider.getConfigPropertyAsString(TopLinkProperties.JDBC_BIND_PARAMETERS, m) == null) {
// session.log(SessionLog.FINEST, SessionLog.PROPERTIES, "property_value_default", new Object[]{TopLinkProperties.JDBC_BIND_PARAMETERS, "true"});
session.getPlatform().setShouldBindAllParameters(true);
}
// set default descriptor cache size - set it to all descriptors if CACHE_SIZE_DEFAULT not provided
if (PropertiesHandler.getPrefixedPropertyValue(TopLinkProperties.CACHE_SIZE_, TopLinkProperties.DEFAULT, m) == null) {
// int defaultCacheSize = Integer.parseInt(PropertiesHandler.getDefaultPropertyValueLogDebug(TopLinkProperties.CACHE_SIZE_, session));
int defaultCacheSize = Integer.parseInt(PropertiesHandler.getDefaultPropertyValue(TopLinkProperties.CACHE_SIZE_));
Iterator descriptorsIterator = session.getDescriptors().values().iterator();
while (descriptorsIterator.hasNext()) {
((ClassDescriptor)descriptorsIterator.next()).setIdentityMapSize(defaultCacheSize);
}
}
}
/**
* Set ServerSession name but do not register the session.
* The session registration should be done in sync
* with increment of the deployment counter, as otherwise the
* undeploy will not behave correctly in case of a more
* than one predeploy request for the same session name.
* @param m the combined properties map.
*/
protected void setServerSessionName(Map m) {
// use default session name if none is provided
String name = EntityManagerFactoryProvider.getConfigPropertyAsString(TopLinkProperties.SESSION_NAME, m);
if(name == null) {
if (persistenceUnitInfo.getPersistenceUnitRootUrl() != null){
name = persistenceUnitInfo.getPersistenceUnitRootUrl().toString() + "-" + persistenceUnitInfo.getPersistenceUnitName();
} else {
name = persistenceUnitInfo.getPersistenceUnitName();
}
// session.log(SessionLog.FINEST, SessionLog.PROPERTIES, "property_value_default", new Object[]{TopLinkProperties.SESSION_NAME, name});
}
session.setName(name);
}
/**
* Make any changes to our ServerSession that can be made after it is created.
* @param m
*/
protected void updateServerSession(Map m) {
if (session == null || session.isConnected()) {
return;
}
// Session name and ServerPlatform could've changed which will affect the loggers.
boolean serverPlatformChanged = setOrUpdateServerPlatform(m);
boolean sessionNameChanged = updateSessionName(m);
if (serverPlatformChanged) {
// Update loggers and settings for the singleton logger and the session logger.
updateLoggers(predeployProperties);
} else if (sessionNameChanged) {
// In JavaLog this will result in logger name changes,
// but won't affect DefaultSessionLog.
session.getSessionLog().setSession(session);
}
initOrUpdateLogging(false, m, AbstractSessionLog.getLog());
initOrUpdateLogging(false, m, session.getSessionLog());
String shouldBindString = getConfigPropertyAsStringLogDebug(TopLinkProperties.JDBC_BIND_PARAMETERS, m, session);
if (shouldBindString != null) {
session.getPlatform().setShouldBindAllParameters(Boolean.parseBoolean(shouldBindString));
}
updateLogins(m);
if(!session.getLogin().shouldUseExternalTransactionController()) {
session.getServerPlatform().disableJTA();
}
updatePools(m);
updateDescriptorCacheSettings(m);
// Customizers should be processed last
processDescriptorCustomizers(m);
processSessionCustomizer(m);
}
/**
* This sets the isInContainerMode flag.
* "true" indicates container case, "false" - SE.
* @param isInContainerMode
*/
public void setIsInContainerMode(boolean isInContainerMode) {
this.isInContainerMode = isInContainerMode;
}
protected void processSessionCustomizer(Map m) {
String sessionCustomizerClassName = getConfigPropertyAsStringLogDebug(TopLinkProperties.SESSION_CUSTOMIZER, m, session);
if(sessionCustomizerClassName == null) {
return;
}
Class sessionCustomizerClass = findClassForProperty(sessionCustomizerClassName, TopLinkProperties.SESSION_CUSTOMIZER);
SessionCustomizer sessionCustomizer;
try {
sessionCustomizer = (SessionCustomizer)sessionCustomizerClass.newInstance();
sessionCustomizer.customize(session);
} catch (Exception ex) {
throw EntityManagerSetupException.failedWhileProcessingProperty(TopLinkProperties.SESSION_CUSTOMIZER, sessionCustomizerClassName, ex);
}
}
protected void initOrUpdateLogging(boolean init, Map m, SessionLog log) {
String logLevelString = PropertiesHandler.getPropertyValueLogDebug(TopLinkProperties.LOGGING_LEVEL, m, session);
if(logLevelString != null) {
log.setLevel(AbstractSessionLog.translateStringToLoggingLevel(logLevelString));
}
String tsString = getConfigPropertyAsStringLogDebug(TopLinkProperties.LOGGING_TIMESTAMP, m, session);
if (tsString != null) {
log.setShouldPrintDate(Boolean.parseBoolean(tsString));
}
String threadString = getConfigPropertyAsStringLogDebug(TopLinkProperties.LOGGING_THREAD, m, session);
if (threadString != null) {
log.setShouldPrintThread(Boolean.parseBoolean(threadString));
}
String sessionString = getConfigPropertyAsStringLogDebug(TopLinkProperties.LOGGING_SESSION, m, session);
if (sessionString != null) {
log.setShouldPrintSession(Boolean.parseBoolean(sessionString));
}
String exString = getConfigPropertyAsStringLogDebug(TopLinkProperties.LOGGING_EXCEPTIONS, m, session);
if (exString != null) {
log.setShouldLogExceptionStackTrace(Boolean.parseBoolean(exString));
}
}
/**
* Updates server session name if changed.
* @return true if the name has changed.
*/
protected boolean updateSessionName(Map m) {
String newName = getConfigPropertyAsStringLogDebug(TopLinkProperties.SESSION_NAME, m, session);
if(newName == null || newName.equals(session.getName())) {
return false;
}
removeSessionFromGlobalSessionManager();
session.setName(newName);
addSessionToGlobalSessionManager();
return true;
}
protected void processDescriptorCustomizers(Map m) {
Map customizerMap = PropertiesHandler.getPrefixValuesLogDebug(TopLinkProperties.DESCRIPTOR_CUSTOMIZER_, m, session);
if(customizerMap.isEmpty()) {
return;
}
Iterator it = customizerMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
String name = (String)entry.getKey();
ClassDescriptor descriptor = session.getDescriptorForAlias(name);
if(descriptor == null) {
try {
Class javaClass = findClass(name);
descriptor = session.getDescriptor(javaClass);
} catch (Exception ex) {
// Ignore exception
}
}
if(descriptor != null) {
String customizerClassName = (String)entry.getValue();
Class customizerClass = findClassForProperty(customizerClassName, TopLinkProperties.DESCRIPTOR_CUSTOMIZER_ + name);
try {
DescriptorCustomizer customizer = (DescriptorCustomizer)customizerClass.newInstance();
customizer.customize(descriptor);
} catch (Exception ex) {
throw EntityManagerSetupException.failedWhileProcessingProperty(TopLinkProperties.DESCRIPTOR_CUSTOMIZER_ + name, customizerClassName, ex);
}
}
}
}
private void processORMetadata(
ClassLoader privateClassLoader, AbstractSession session,
boolean enableLazyForOneToOne){
processor = new MetadataProcessor(persistenceUnitInfo, session, privateClassLoader, enableLazyForOneToOne);
// DO NOT CHANGE the order of invocation of various methods.
// build the list of mapping files and read them. Need to do this before
// we start processing entities as the list of entity classes
// depend on metadata read from mapping files.
boolean throwExceptionOnFail = "true".equalsIgnoreCase(
getConfigPropertyAsString(TOPLINK_ORM_THROW_EXCEPTIONS, "true"));
processor.readMappingFiles(throwExceptionOnFail);
processor.buildEntityList();
// process persistence unit metadata/defaults defined in
// ORM XML instance documents in the persistence unit
processor.processPersistenceUnitMetadata();
processor.processMappingFiles();
processor.processAnnotations();
}
public boolean isPredeployed() {
return state == STATE_PREDEPLOYED;
}
public boolean isDeployed() {
return state == STATE_DEPLOYED;
}
public boolean isUndeployed() {
return state == STATE_UNDEPLOYED;
}
protected void cleanUpSessionManager() {
deploymentCount--;
if(deploymentCount > 0) {
return;
}
state = STATE_UNDEPLOYED;
removeSessionFromGlobalSessionManager();
}
/**
* Undeploy may be called several times, but only the call that decreases
* deploymentCount to 0 disconnects the session and removes it from the session manager.
* Note that the session is an attribute of this class,
* and could be deployed again (after been undeployed to deploymentCount 0 and disconnected).
*/
public synchronized void undeploy() {
if(state != STATE_DEPLOYED) {
return;
}
session.log(SessionLog.FINEST, SessionLog.PROPERTIES, "undeploy_begin", new Object[]{getPersistenceUnitInfo().getPersistenceUnitName(), state, deploymentCount});
try {
cleanUpSessionManager();
} finally {
session.log(SessionLog.FINEST, SessionLog.PROPERTIES, "undeploy_end", new Object[]{getPersistenceUnitInfo().getPersistenceUnitName(), state, deploymentCount});
if(state == STATE_UNDEPLOYED) {
session = null;
}
}
}
}