FileDocCategorySizeDatePackage
PersistenceProcessor.javaAPI DocGlassfish v2 API28325Fri May 25 07:56:58 BST 2007com.sun.jdo.spi.persistence.support.ejb.ejbc

PersistenceProcessor

public 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.
author
pramodg

Fields Summary
private static final String
TOPLINK_PERSISTENCE_PROVIDER_CLASS_NAME_OLD
private static final String
TOPLINK_PERSISTENCE_PROVIDER_CLASS_NAME_NEW
private PersistenceUnitInfo
pi
The object that would be used by the toplink code when creating a container.
Constructors Summary
public PersistenceProcessor(com.sun.enterprise.deployment.backend.DeploymentEventInfo info, boolean create, String cliCreateTables, String cliDropAndCreateTables, String cliDropTables)
Creates a new instance of PersistenceProcessor

param
info the deployment info object.
param
create true if tables are to be created as part of this event.
param
cliCreateTables the cli string related to creating tables at deployment time.
param
cliDropAndCreateTables the cli string that indicates that old tables have to be dropped and new tables created.
param
cliDropTables the cli string to indicate that the tables have to dropped at undeploy time.

   
                                                                                 
     
                
                
              
        super(info, create, cliCreateTables,
            cliDropAndCreateTables, cliDropTables);
    
Methods Summary
private voidaddPropertiesToPU(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.

param
puDescriptor the persistence unit descriptor that is being worked on.

        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 voidaddPropertyToDescriptor(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.

param
descriptor the persistence unit descriptor that is being worked on.
param
propertyName the name of the property.
param
propertyValue the value of the property.

        String oldPropertyValue = descriptor.getProperties().getProperty(propertyName);
        if(null == oldPropertyValue) {
            descriptor.addProperty(propertyName, propertyValue);
        }        
    
private voidconstructJdbcFileNames(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

param
parBundle the persistence unit descriptor that is being worked on.

        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 voidcreateTablesInDB(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.

param
createTables true if tables have to be created.
param
bundle the persistence unit descriptor that is being worked on
param
ddlMode the ddl-generate property value specified by the user.

        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 voiddropTablesFromDB(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.

param
dropTables true if the table need to be dropped.
param
bundle the persistence unit descriptor that is being worked on.

        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 booleanexecuteDDLStatement(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.

param
fileName the create or drop jdbc ddl file.
param
nonJtaDataSource the nonJtaDataSource that is obtained from the persistence info object that we had created.
return
true if the tables were successfully created/dropped from the database.

        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.CollectiongetAllPersistenceUnitDescriptors(com.sun.enterprise.deployment.Application application)
For a given application get all the persistence units that are being referenced by this application.

param
application the application that is being deployed/redeployed/undeployed.
return
a collection of persistenceunitsdescriptors.

        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 booleangetCreateTablesValue(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.

param
ddlGenerate the property name specified by the user.
param
ddlMode the property value specified by the user.
return
true if tables have to created.

        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.FilegetDDLFile(com.sun.enterprise.deployment.PersistenceUnitDescriptor bundle, java.lang.String fileName, boolean create)
Create and read the ddl file constructing the proper disk location.

param
bundle the persistence unit descriptor that is being worked on.
param
fileName the name of the file.
param
create true if this event results in creating tables.
return
the jdbc ddl file.

        // 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 booleangetDropTablesValue(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.

param
ddlGenerate the property name specified by the user.
param
ddlMode the property value specified by the user.
return
true if the tables have to be dropped.

        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.StringgetPersistencePropVal(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.

param
parBundle the persistence unit descriptor that is being worked on.
param
propertyName the property name being checked.
param
defaultValue the default value to be used.
return
the property value.

        String propertyValue;
        if(null == defaultValue)
            propertyValue = parBundle.getProperties().getProperty(propertyName);
        else
             propertyValue = parBundle.getProperties().
                     getProperty(propertyName, defaultValue);

        return propertyValue;
    
private java.lang.StringgetProviderClassName(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.

param
persistenceUnitDescriptor the persistence unit descriptor.
return
provider class name as a String


        return PersistenceUnitInfoImpl.getPersistenceProviderClassNameForPuDesc(
                persistenceUnitDescriptor);
     
private booleanisDDLExecution(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.

param
ddlMode the ddl-generate property value specified by the user.
return
true if the DDL need to be executed in the database.

         boolean rs = true;
         if (cliCreateTables.equals(Constants.UNDEFINED)) {
             rs = !ddlMode.equals(EntityManagerFactoryProvider.DDL_SQL_SCRIPT_GENERATION);
         }

         return rs;
     
private booleanisSupportedPersistenceProvider(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.

param
persistenceUnitDescriptor the persistence unit descriptor that is being worked on.
return
true if persistence provider is toplink.


        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.PersistenceUnitInfoloadPersistenceUnitBundle(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.

param
persistenceUnitDescriptor the persistence unit descriptor that is being worked on.
param
createJdbcFileName the string name of the create jdbc ddl file.
param
dropJdbcFileName the string name of the drop jdbc ddl file.
return
the persistence unit info object that would used by 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 voidprocessAppBundle(com.sun.enterprise.deployment.PersistenceUnitDescriptor bundle)
This method does all the work of checking and processing each persistence unit descriptor.

param
bundle the persistence unit descriptor that is being worked on.

 
       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 voidprocessApplication()
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);
        }