PersistenceProcessorpublic class PersistenceProcessor extends BaseProcessor For each persistence unit descriptors that is defined for
an application create the ddl scripts. Additionally if the
user has requested the tables to be created or dropped from
the database complete that action too.
These are the principles and expectations of the implementation.
We don't want TopLink code to execute the DDLs, it should only
generate them. So, we always set the *generation-mode* to *script*
in the PUInfo object before passing it to createContainerEMF().
As a result TopLink never creates the actual tables, nor does it drop
them. The DDLs are executed by our code based on user preference which
considers inputs from persistence.xml and CLI. We set the TopLink
property to DROP_AND_CREATE in that map because we want it to always
generate both create- and dropDDL.jdbc files. |
Fields Summary |
---|
private static final String | TOPLINK_PERSISTENCE_PROVIDER_CLASS_NAME_OLD | private static final String | TOPLINK_PERSISTENCE_PROVIDER_CLASS_NAME_NEW | private PersistenceUnitInfo | piThe object that would be used by the
toplink code when creating a container. |
Methods Summary |
---|
private void | addPropertiesToPU(com.sun.enterprise.deployment.PersistenceUnitDescriptor puDescriptor)Since the ddl files are actually created
by the toplink code, we ensure that the
correct properties are put in the persistence
unit info object.
addPropertyToDescriptor(puDescriptor,
TopLinkProperties.TARGET_SERVER,
"oracle.toplink.essentials.platform.server.sunas.SunAS9ServerPlatform"); // NOI18N
addPropertyToDescriptor(puDescriptor,
EntityManagerFactoryProvider.APP_LOCATION,
appGeneratedLocation);
addPropertyToDescriptor(puDescriptor,
EntityManagerFactoryProvider.CREATE_JDBC_DDL_FILE,
createJdbcFileName);
addPropertyToDescriptor(puDescriptor,
EntityManagerFactoryProvider.DROP_JDBC_DDL_FILE,
dropJdbcFileName);
| private void | addPropertyToDescriptor(com.sun.enterprise.deployment.PersistenceUnitDescriptor descriptor, java.lang.String propertyName, java.lang.String propertyValue)Utility method that is used to actually set the property into the persistence unit descriptor.
String oldPropertyValue = descriptor.getProperties().getProperty(propertyName);
if(null == oldPropertyValue) {
descriptor.addProperty(propertyName, propertyValue);
}
| private void | constructJdbcFileNames(com.sun.enterprise.deployment.PersistenceUnitDescriptor parBundle)Construct the name of the create and
drop jdbc ddl files that would be
created. These name would be either
obtained from the persistence.xml file
(if the user has defined them) or we would
create default filenames
createJdbcFileName =
getPersistencePropVal(parBundle,
EntityManagerFactoryProvider.CREATE_JDBC_DDL_FILE, null);
dropJdbcFileName =
getPersistencePropVal(parBundle,
EntityManagerFactoryProvider.DROP_JDBC_DDL_FILE, null);
if((null != createJdbcFileName) && (null != dropJdbcFileName)) {
return;
}
String filePrefix =
EJBHelper.getDDLNamePrefix(parBundle.getParent().getParent());
if(null == createJdbcFileName) {
createJdbcFileName = filePrefix + NAME_SEPARATOR + parBundle.getName() +
CREATE_DDL_JDBC_FILE_SUFFIX;
}
if(null == dropJdbcFileName) {
dropJdbcFileName = filePrefix + NAME_SEPARATOR + parBundle.getName() +
DROP_DDL_JDBC_FILE_SUFFIX;
}
| private void | createTablesInDB(boolean createTables, com.sun.enterprise.deployment.PersistenceUnitDescriptor bundle, java.lang.String ddlMode)Currently java2db feature is supported for toplink persistence provider
only, as toplink is the default persistence provider for glassfish.
If the provider is toplink, call into toplink code to generate the ddl files.
Once the jdbc files have been created, use the create jdbc ddl file and
execute it against the database to have the required objects created.
if(createTables) {
pi = loadPersistenceUnitBundle(bundle,
createJdbcFileName, dropJdbcFileName);
// if pi is null it means that the user has defined a persistence
// provider that is not supported. We should also skip DDL execution
// if the user chose only to create the files.
if ((null != pi) && isDDLExecution(ddlMode)) {
File createFile = getDDLFile(bundle, createJdbcFileName, true);
if(createFile.exists()) {
executeDDLStatement(createFile, pi.getNonJtaDataSource());
} else {
logI18NWarnMessage(
"ejb.BaseProcessor.cannotcreatetables", //NOI18N
appRegisteredName, createFile.getName(), null);
}
}
}
| private void | dropTablesFromDB(boolean dropTables, com.sun.enterprise.deployment.PersistenceUnitDescriptor bundle)We need to get the datasource information if
that has been defined in the persistence.xml.
Did not want to duplicate code here. So we
create a persistence unit info object and get
the nonJTADatasource from that object
Then if the drop file is present, drop the tables
from the database.
If the user has specified a persistence provider other than the default
toplink one, then java2db feature will not be a supported feature. In such
cases the drop file would not be present.
if(dropTables) {
File dropFile = getDDLFile(bundle, dropJdbcFileName, false);
if (dropFile.exists()) {
PersistenceUnitInfo pi = new Java2DBPersistenceUnitInfoImpl(
bundle,
appDeployedLocation,
null);
executeDDLStatement(dropFile, pi.getNonJtaDataSource());
} else if (isSupportedPersistenceProvider(bundle)){
logI18NWarnMessage(
"ejb.BaseProcessor.cannotdroptables", //NOI18N
appRegisteredName, dropFile.getName(), null);
}
}
| private boolean | executeDDLStatement(java.io.File fileName, javax.sql.DataSource nonJtaDataSource)Get the ddl files eventually executed
against the database. This method deals
with both create and drop ddl files.
boolean result = false;
Connection conn = null;
Statement sql = null;
try {
try {
conn = nonJtaDataSource.getConnection();
sql = conn.createStatement();
result = true;
} catch (SQLException ex) {
logI18NWarnMessage(
"ejb.BaseProcessor.cannotConnect",
appRegisteredName, null, ex);
}
if(result) {
executeDDLs(fileName, sql);
}
} catch (IOException e) {
fileIOError(application.getRegistrationName(), e);
} finally {
closeConn(conn);
}
return result;
| private java.util.Collection | getAllPersistenceUnitDescriptors(com.sun.enterprise.deployment.Application application)For a given application get all the
persistence units that are being referenced by this application.
Set<PersistenceUnitDescriptor> allPUs =
new HashSet<PersistenceUnitDescriptor>();
// step #1: PUs referenced by EJBs
for (Object o : application.getEjbBundleDescriptors()) {
EjbBundleDescriptor bundle = EjbBundleDescriptor.class.cast(o);
allPUs.addAll(bundle.findReferencedPUs());
}
// step #2: PUs referenced by Web components
for (Object o : application.getWebBundleDescriptors()) {
WebBundleDescriptor bundle = WebBundleDescriptor.class.cast(o);
allPUs.addAll(bundle.findReferencedPUs());
}
// step #3: PUs referenced by appclients
for (Object o : application.getApplicationClientDescriptors()) {
ApplicationClientDescriptor bundle =
ApplicationClientDescriptor.class.cast(o);
allPUs.addAll(bundle.findReferencedPUs());
}
return allPUs;
| protected boolean | getCreateTablesValue(java.lang.String ddlGenerate, java.lang.String ddlMode)We need to create tables only on deploy, and only
if the CLI options cliCreateTables or cliDropAndCreateTables
are not set to false. If those options are not set (UNDEFINED)
the value is taken from the ddl-generate property if defined
in persistence.xml.
boolean createTables =
create
&& (cliCreateTables.equals(Constants.TRUE)
|| (
(ddlGenerate.equals(EntityManagerFactoryProvider.CREATE_ONLY)
|| ddlGenerate.equals(EntityManagerFactoryProvider.DROP_AND_CREATE))
&& !ddlMode.equals(EntityManagerFactoryProvider.NONE))
&& cliCreateTables.equals(Constants.UNDEFINED));
return createTables;
| private java.io.File | getDDLFile(com.sun.enterprise.deployment.PersistenceUnitDescriptor bundle, java.lang.String fileName, boolean create)Create and read the ddl file constructing the proper disk location.
// Application location might be already set to the
// generated directory but that would happen only if the
// deploy happened in the same VM as a redeploy or an undeploy.
String appLocation = getPersistencePropVal(bundle,
EntityManagerFactoryProvider.APP_LOCATION,
appGeneratedLocation);
// Delegate the rest to the superclass.
return getDDLFile(appLocation + File.separator + fileName, create);
| protected boolean | getDropTablesValue(java.lang.String ddlGenerate, java.lang.String ddlMode)We need to drop tables on deploy and redeploy, if the
corresponding CLI options cliDropAndCreateTables
(for redeploy) or cliDropTables (for undeploy) are not
set to false.
If the corresponding option is not set (UNDEFINED)
the value is taken from the ddl-generate property
if defined in persistence.xml.
boolean dropTables =
!create
&& (cliDropAndCreateTables.equals(Constants.TRUE)
|| cliDropTables.equals(Constants.TRUE)
|| ((ddlGenerate.equals(EntityManagerFactoryProvider.DROP_AND_CREATE)
&& (ddlMode.equals(EntityManagerFactoryProvider.DDL_DATABASE_GENERATION)
|| ddlMode.equals(EntityManagerFactoryProvider.DDL_BOTH_GENERATION))
&& cliDropAndCreateTables.equals(Constants.UNDEFINED)
&& cliDropTables.equals(Constants.UNDEFINED))));
return dropTables;
| private java.lang.String | getPersistencePropVal(com.sun.enterprise.deployment.PersistenceUnitDescriptor parBundle, java.lang.String propertyName, java.lang.String defaultValue)Given a persistence unit descriptor
return the value of a property if the
user has specified it.
If the user has not defined this property
return the default value.
String propertyValue;
if(null == defaultValue)
propertyValue = parBundle.getProperties().getProperty(propertyName);
else
propertyValue = parBundle.getProperties().
getProperty(propertyName, defaultValue);
return propertyValue;
| private java.lang.String | getProviderClassName(com.sun.enterprise.deployment.PersistenceUnitDescriptor persistenceUnitDescriptor)Return provider class name as specified in the persistence.xml
or the default provider as known to the system.
return PersistenceUnitInfoImpl.getPersistenceProviderClassNameForPuDesc(
persistenceUnitDescriptor);
| private boolean | isDDLExecution(java.lang.String ddlMode)Check if we should skip DDL execution which can be the case if the
user chose only to create the files.
boolean rs = true;
if (cliCreateTables.equals(Constants.UNDEFINED)) {
rs = !ddlMode.equals(EntityManagerFactoryProvider.DDL_SQL_SCRIPT_GENERATION);
}
return rs;
| private boolean | isSupportedPersistenceProvider(com.sun.enterprise.deployment.PersistenceUnitDescriptor persistenceUnitDescriptor)The java2db feature is currently implemented only for toplink (the default
persistence povider in glassfish). Hence we check for the name of the
persistence provider class name. It it is not toplink, stop processing.
String providerClassName = getProviderClassName(persistenceUnitDescriptor);
return providerClassName.equals(TOPLINK_PERSISTENCE_PROVIDER_CLASS_NAME_OLD) ||
providerClassName.equals(TOPLINK_PERSISTENCE_PROVIDER_CLASS_NAME_NEW);
| private javax.persistence.spi.PersistenceUnitInfo | loadPersistenceUnitBundle(com.sun.enterprise.deployment.PersistenceUnitDescriptor persistenceUnitDescriptor, java.lang.String createJdbcFileName, java.lang.String dropJdbcFileName)Since the actual jdbc files are generated
by the toplink code, we need to create
a persistence unit info object and then
call into the toplink code.
logger.entering("loadPersistenceUnitBundle", "load",
new Object[]{persistenceUnitDescriptor});
if (! isSupportedPersistenceProvider(persistenceUnitDescriptor)) {
// Persistence provider is not supported, hence exit from java2db code
if (cliCreateTables.equals(Constants.TRUE) ||
cliDropAndCreateTables.equals(Constants.TRUE)) {
logI18NWarnMessage(
"ejb.PersistenceProcessor.nondefaultprovider",
getProviderClassName(persistenceUnitDescriptor),
persistenceUnitDescriptor.getName(), null);
}
return null;
}
PersistenceProvider provider;
addPropertiesToPU(persistenceUnitDescriptor);
// We should not override some properties, but pass them as a Map instead.
Map<String, String> overrides = new HashMap<String, String>();
overrides.put(
EntityManagerFactoryProvider.DDL_GENERATION,
EntityManagerFactoryProvider.DROP_AND_CREATE);
// Turn off enhancement during Java2DB. For details,
// refer to https://glassfish.dev.java.net/issues/show_bug.cgi?id=1646
overrides.put(TopLinkProperties.WEAVING, "FALSE"); // NOI18N
// As part of the deployment cycle we set the DDL_GENERATION_MODE. This
// would ensure that the toplink code would create the required jdbc files,
// but won't execute DDLs themselves.
// As part of the normal application load we would set this property to a
// value of "NONE".
overrides.put(EntityManagerFactoryProvider.DDL_GENERATION_MODE,
EntityManagerFactoryProvider.DDL_SQL_SCRIPT_GENERATION);
final InstrumentableClassLoader cl =
InstrumentableClassLoader.class.cast(
persistenceUnitDescriptor.getClassLoader());
PersistenceUnitInfo pi = new Java2DBPersistenceUnitInfoImpl(
persistenceUnitDescriptor,
appDeployedLocation,
cl);
if(debug)
logger.fine("PersistenceInfo for PU is :\n" + pi);
provider = new EntityManagerFactoryProvider();
EntityManagerFactory emf = null;
try {
emf = provider.createContainerEntityManagerFactory(pi, overrides);
emf.createEntityManager();
if(debug)
logger.fine("PersistenceProcessor", "loadPersistenceUnitBundle",
"emf = {0}", emf);
} finally {
if(emf != null) {
emf.close();
}
}
return pi;
| private void | processAppBundle(com.sun.enterprise.deployment.PersistenceUnitDescriptor bundle)This method does all the work of checking
and processing each persistence unit
descriptor.
String ddlGenerate = getPersistencePropVal(bundle,
EntityManagerFactoryProvider.DDL_GENERATION,
EntityManagerFactoryProvider.NONE);
String ddlMode = getPersistencePropVal(bundle,
EntityManagerFactoryProvider.DDL_GENERATION_MODE,
EntityManagerFactoryProvider.DDL_BOTH_GENERATION);
boolean createTables =
getCreateTablesValue(ddlGenerate, ddlMode);
boolean dropTables =
getDropTablesValue(ddlGenerate, ddlMode);
if (debug) {
logger.fine("ejb.PersistenceProcessor.createanddroptables", //NOI18N
new Object[] {new Boolean(createTables), new Boolean(dropTables)});
}
if (!createTables && !dropTables) {
// Nothing to do.
return;
}
constructJdbcFileNames(bundle);
if (debug) {
logger.fine("ejb.PersistenceProcessor.createanddropfilenames", createJdbcFileName, dropJdbcFileName); //NOI18N
}
// These calls will be a no-op if it's not a corresponding event.
dropTablesFromDB(dropTables, bundle);
createTablesInDB(createTables, bundle, ddlMode);
| protected void | processApplication()The entry point into this class. Process
any persistence unit descriptors if
found for this application.
Collection<PersistenceUnitDescriptor> pus =
getAllPersistenceUnitDescriptors(application);
if (pus.size() == 0) {
return;
}
// At this point of time we are sure that we would need to create
// the sql/jdbc files required to create or drop objects from the
// database. Hence setup the required directories from the info object.
setApplicationLocation();
setGeneratedLocation();
for (PersistenceUnitDescriptor pu : pus) {
processAppBundle(pu);
}
|
|