KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jdo > spi > persistence > support > ejb > ejbc > PersistenceProcessor


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 package com.sun.jdo.spi.persistence.support.ejb.ejbc;
25
26 import com.sun.enterprise.connectors.ConnectorRuntime;
27 import com.sun.enterprise.deployment.Application;
28 import com.sun.enterprise.deployment.EjbBundleDescriptor;
29 import com.sun.enterprise.deployment.PersistenceUnitsDescriptor;
30 import com.sun.enterprise.deployment.PersistenceUnitDescriptor;
31 import com.sun.enterprise.deployment.WebBundleDescriptor;
32 import com.sun.enterprise.deployment.backend.DeploymentEventInfo;
33 import com.sun.enterprise.deployment.backend.DeploymentStatus;
34 import com.sun.enterprise.deployment.io.DescriptorConstants;
35 import com.sun.enterprise.loader.InstrumentableClassLoader;
36 import com.sun.enterprise.server.PersistenceUnitInfoImpl;
37 import com.sun.enterprise.server.Constants;
38
39 import com.sun.jdo.spi.persistence.support.sqlstore.ejb.EJBHelper;
40 import com.sun.jdo.spi.persistence.utility.database.DatabaseConstants;
41 import com.sun.jdo.spi.persistence.utility.I18NHelper;
42
43 import java.io.File JavaDoc;
44 import java.io.IOException JavaDoc;
45 import java.util.ArrayList JavaDoc;
46 import java.util.Collection JavaDoc;
47 import java.util.Iterator JavaDoc;
48 import java.util.List JavaDoc;
49 import java.util.logging.Level JavaDoc;
50
51 import javax.naming.NamingException JavaDoc;
52 import javax.persistence.EntityManagerFactory;
53 import javax.persistence.spi.PersistenceUnitInfo;
54 import javax.persistence.spi.PersistenceProvider;
55 import java.sql.Connection JavaDoc;
56 import javax.sql.DataSource JavaDoc;
57 import java.sql.Statement JavaDoc;
58 import java.sql.SQLException JavaDoc;
59
60 import oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider;
61
62 /**
63  * For each persistence unit descriptors that is defined for
64  * an application create the ddl scripts. Additionally if the
65  * user has requested the tables to be created or dropped from
66  * the database complete that action too.
67  * @author pramodg
68  */

69 public class PersistenceProcessor
70         extends BaseProcessor {
71
72     // Defining the persistence provider class names here that we would use to
73
// check if java2db is supported.
74
private static final String JavaDoc TOPLINK_PERSISTENCE_PROVIDER_CLASS_NAME_OLD =
75         "oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider"; // NOI18N
76
private static final String JavaDoc TOPLINK_PERSISTENCE_PROVIDER_CLASS_NAME_NEW =
77         "oracle.toplink.essentials.PersistenceProvider"; // NOI18N
78

79     /**
80      * The object that would be used by the
81      * toplink code when creating a container.
82      */

83     private PersistenceUnitInfo pi;
84    
85     /**
86      * Creates a new instance of PersistenceProcessor
87      * @param info the deployment info object.
88      * @param deploy true if this is a deploy event.
89      * @param redeploy true if this application is being redeployed.
90      * @param cliCreateTables the cli string related to creating tables
91      * at deployment time.
92      * @param cliDropAndCreateTables the cli string that indicates that
93      * old tables have to be dropped and new tables created.
94      * @param cliDropTables the cli string to indicate that the tables
95      * have to dropped at undeploy time.
96      */

97     public PersistenceProcessor(
98             DeploymentEventInfo info, boolean deploy, boolean redeploy,
99             String JavaDoc cliCreateTables, String JavaDoc cliDropAndCreateTables, String JavaDoc cliDropTables) {
100         super(info, deploy, redeploy, cliCreateTables,
101             cliDropAndCreateTables, cliDropTables);
102     }
103  
104     /**
105      * The entry point into this class. Process
106      * any persistence unit descriptors if
107      * found for this application.
108      */

109     protected void processApplication() {
110         Collection JavaDoc<PersistenceUnitsDescriptor> bundleCollection =
111                 getAllPersistenceUnitDescriptors(application);
112         
113         if ( bundleCollection.size() == 0) {
114             return;
115         }
116
117         // At this point of time we are sure that we would need to create
118
// the sql/jdbc files required to create or drop objects from the
119
// database. Hence setup the required directories from the info object.
120
setApplicationLocation();
121         setGeneratedLocation();
122
123         for (PersistenceUnitsDescriptor pus : bundleCollection) {
124             for (PersistenceUnitDescriptor bundle : pus.getPersistenceUnitDescriptors()) {
125                 processAppBundle(bundle);
126             }
127         }
128     }
129     
130     /**
131      * For a given application get all the
132      * persistence descriptors that have been
133      * defined.
134      * @param application the application that is being
135      * deployed/redeployed/undeployed.
136      * @return a collection of persistenceunitsdescriptors.
137      */

138     private Collection JavaDoc<PersistenceUnitsDescriptor>
139             getAllPersistenceUnitDescriptors(Application application) {
140         List JavaDoc<PersistenceUnitsDescriptor> allPUs =
141                 new ArrayList JavaDoc<PersistenceUnitsDescriptor>(
142                     application.getPersistenceUnitsDescriptors());
143         
144         // step #2: load ejb-jar level PUs
145
for (Object JavaDoc o : application.getEjbBundleDescriptors()) {
146             EjbBundleDescriptor bundle = EjbBundleDescriptor.class.cast(o);
147             allPUs.addAll(bundle.getPersistenceUnitsDescriptors());
148         }
149
150         // step #3: load war level PUs
151
for (Object JavaDoc o : application.getWebBundleDescriptors()) {
152             WebBundleDescriptor bundle = WebBundleDescriptor.class.cast(o);
153             allPUs.addAll(bundle.getPersistenceUnitsDescriptors());
154         }
155         
156         return allPUs;
157     }
158     
159     /**
160      * This method does all the work of checking
161      * and processing each persistence unit
162      * descriptor.
163      * @param bundle the persistence unit descriptor that is being worked on.
164      */

165     private void processAppBundle(PersistenceUnitDescriptor bundle) {
166        String JavaDoc ddlGenerate = getPersistencePropVal(bundle,
167                 EntityManagerFactoryProvider.DDL_GENERATION,
168                 EntityManagerFactoryProvider.NONE);
169         boolean createTables =
170                 getCreateTablesValue(bundle, ddlGenerate);
171         boolean dropTables =
172                 getDropTablesValue(bundle, ddlGenerate);
173
174         if (debug) {
175             logger.fine("ejb.PersistenceProcessor.createanddroptables", //NOI18N
176
new Object JavaDoc[] {new Boolean JavaDoc(createTables), new Boolean JavaDoc(dropTables)});
177         }
178
179         if (!createTables && !dropTables) {
180             // Nothing to do.
181
return;
182         }
183
184         constructJdbcFileNames(bundle);
185         if (debug) {
186             logger.fine("ejb.PersistenceProcessor.createanddropfilenames", createJdbcFileName, dropJdbcFileName); //NOI18N
187
}
188         
189         dropTablesFromDB(dropTables, bundle);
190         createTablesInDB(createTables, bundle);
191     }
192     
193     /**
194      * We need to create tables only on deploy, and only
195      * if the CLI options cliCreateTables or cliDropAndCreateTables
196      * are not set to false. If those options are not set (UNDEFINED)
197      * the value is taken from the ddl-generate property if defined
198      * in persistence.xml.
199      * @param bundle the persistence unit descriptor that is being worked on.
200      * @param ddlGenerate the string value specified by the user.
201      * @return true if tables have to created.
202      */

203     protected boolean getCreateTablesValue(
204             PersistenceUnitDescriptor bundle, String JavaDoc ddlGenerate) {
205         boolean createTables =
206             deploy
207                 && (cliCreateTables.equals(Constants.TRUE)
208                     || (ddlGenerate.equals(EntityManagerFactoryProvider.CREATE_ONLY)
209                     || ddlGenerate.equals(EntityManagerFactoryProvider.DROP_AND_CREATE)
210                         && cliCreateTables.equals(Constants.UNDEFINED)));
211         
212         return createTables;
213     }
214     
215     /**
216      * We need to drop tables on deploy and redeploy, if the
217      * corresponding CLI options cliDropAndCreateTables
218      * (for redeploy) or cliDropTables (for undeploy) are not
219      * set to false.
220      * If the corresponding option is not set (UNDEFINED)
221      * the value is taken from the ddl-generate property
222      * if defined in persistence.xml.
223      * @param bundle the persistence unit descriptor that is being worked on.
224      * @param ddlGenerate the string value specified by the user.
225      * @return true if the tables have to be dropped.
226      */

227     protected boolean getDropTablesValue(
228             PersistenceUnitDescriptor bundle, String JavaDoc ddlGenerate) {
229         boolean dropTables =
230             (redeploy
231                 && (cliDropAndCreateTables.equals(Constants.TRUE)
232                     || (ddlGenerate.equals(EntityManagerFactoryProvider.DROP_AND_CREATE)
233                         && cliDropAndCreateTables.equals(Constants.UNDEFINED))))
234             || (!deploy
235                 && (cliDropTables.equals(Constants.TRUE)
236                     || (ddlGenerate.equals(EntityManagerFactoryProvider.DROP_AND_CREATE)
237                         && cliDropTables.equals(Constants.UNDEFINED))));
238           
239         return dropTables;
240     }
241  
242     /**
243      * Construct the name of the create and
244      * drop jdbc ddl files that would be
245      * created. These name would be either
246      * obtained from the persistence.xml file
247      * (if the user has defined them) or we would
248      * create default filenames
249      * @param parBundle the persistence unit descriptor that is being worked on.
250      */

251     private void constructJdbcFileNames(PersistenceUnitDescriptor parBundle) {
252         createJdbcFileName =
253                 getPersistencePropVal(parBundle,
254                 EntityManagerFactoryProvider.CREATE_JDBC_DDL_FILE, null);
255         dropJdbcFileName =
256                 getPersistencePropVal(parBundle,
257                 EntityManagerFactoryProvider.DROP_JDBC_DDL_FILE, null);
258
259         if((null != createJdbcFileName) && (null != dropJdbcFileName)) {
260             return;
261         }
262         
263         String JavaDoc filePrefix =
264                     EJBHelper.getDDLNamePrefix(parBundle.getParent().getParent());
265
266         if(null == createJdbcFileName) {
267             createJdbcFileName = filePrefix + NAME_SEPARATOR + parBundle.getName() +
268                 CREATE_DDL_JDBC_FILE_SUFFIX;
269         }
270         if(null == dropJdbcFileName) {
271             dropJdbcFileName = filePrefix + NAME_SEPARATOR + parBundle.getName() +
272                 DROP_DDL_JDBC_FILE_SUFFIX;
273         }
274     }
275     
276     /**
277      * We need to get the datasource information if
278      * that has been defined in the persistence.xml.
279      * Did not want to duplicate code here. So we
280      * create a persistence unit info object and get
281      * the nonJTADatasource from that object
282      * Then if the drop file is present, drop the tables
283      * from the database.
284      * If the user has specified a persistence provider other than the default
285      * toplink one, then java2db feature will not be a supported feature. In such
286      * cases the drop file would not be present.
287      *
288      * @param dropTables true if the table need to be dropped.
289      * @param bundle the persistence unit descriptor that is being worked on.
290      * @return true if tables were successfully dropped.
291      */

292     protected boolean dropTablesFromDB(boolean dropTables,
293             PersistenceUnitDescriptor bundle) {
294         boolean dropResult = false;
295         File JavaDoc dropFile = null;
296         
297         if(dropTables) {
298             dropFile = getDropDDLFile(dropJdbcFileName, deploy);
299             if (dropFile.exists()) {
300                 PersistenceUnitInfo pi = new PersistenceUnitInfoImpl(
301                     bundle,
302                     appDeployedLocation,
303                     null);
304                 dropResult = executeDDLStatement(dropFile,
305                     pi.getNonJtaDataSource());
306             }
307         }
308         return dropResult;
309     }
310
311     /**
312      * Currently java2db feature is supported for toplink persistence provider
313      * only, as toplink is the default persistence provider for glassfish.
314      * If the provider is toplink, call into toplink code to generate the ddl files.
315      * Once the jdbc files have been created, use the create jdbc ddl file and
316      * execute it against the database to have the required objects created.
317      * @param createTables true if tables have to be created.
318      * @param bundle the persistence unit descriptor that is being worked on
319      * @return true if tables were successfully created.
320      */

321     protected boolean createTablesInDB(boolean createTables,
322             PersistenceUnitDescriptor bundle) {
323         boolean createResult = false;
324         if(createTables) {
325             pi = loadPersistenceUnitBundle(bundle,
326                     createJdbcFileName, dropJdbcFileName);
327             
328             // if pi is null it means that the user has defined a persistence
329
// provider that is not toplink.
330
if (null == pi) {
331                 return createResult;
332             }
333
334             File JavaDoc createFile = getCreateDDLFile(
335                         appGeneratedLocation + createJdbcFileName);
336             if(createFile.exists()) {
337                 createResult = executeDDLStatement( createFile,
338                         pi.getNonJtaDataSource());
339             }
340             createResult = true;
341         }
342         return createResult;
343     }
344     
345
346     /**
347      * Get the ddl files eventually executed
348      * against the database. This method deals
349      * with both create and drop ddl files.
350      * @param fileName the create or drop jdbc ddl file.
351      * @param nonJtaDataSource the nonJtaDataSource
352      * that is obtained from the persistence info object that we had created.
353      * @return true if the tables were successfully
354      * created/dropped from the database.
355      */

356     private boolean executeDDLStatement(File JavaDoc fileName, DataSource JavaDoc nonJtaDataSource ) {
357         boolean result = false;
358         Connection JavaDoc conn = null;
359         Statement JavaDoc sql = null;
360         try {
361             try {
362                 conn = nonJtaDataSource.getConnection();
363                 sql = conn.createStatement();
364                 result = true;
365             } catch (SQLException JavaDoc ex) {
366                 logI18NWarnMessage(
367                      "ejb.BaseProcessor.cannotConnect",
368                     appRegisteredName, null, ex);
369             }
370             if(result) {
371                 executeDDLs(fileName, sql);
372             }
373         } catch (IOException JavaDoc e) {
374             fileIOError(application.getRegistrationName(), e);
375         } finally {
376             closeConn(conn);
377         }
378         return result;
379     }
380
381     
382     /**
383      * Since the ddl files are actually created
384      * by the toplink code, we ensure that the
385      * correct properties are put in the persistence
386      * unit info object.
387      * @param puDescriptor the persistence unit descriptor that is being worked on.
388      */

389     private void addPropertiesToPU(PersistenceUnitDescriptor puDescriptor) {
390         addPropertyToDescriptor(puDescriptor,
391                 EntityManagerFactoryProvider.APP_LOCATION,
392                 appGeneratedLocation);
393         addPropertyToDescriptor(puDescriptor,
394                 EntityManagerFactoryProvider.DDL_GENERATION,
395                 EntityManagerFactoryProvider.DROP_AND_CREATE);
396         // As part of the deployment cycle we set the DDL_GENERATION_MODE. This
397
// would ensure that the toplink code would create the required jdbc files.
398
// As part of the normal application load we would set this property to a
399
// value of "NONE".
400
addPropertyToDescriptor(puDescriptor,
401                 EntityManagerFactoryProvider.DDL_GENERATION_MODE,
402                 EntityManagerFactoryProvider.DDL_SQL_SCRIPT_GENERATION);
403         addPropertyToDescriptor(puDescriptor,
404                 EntityManagerFactoryProvider.CREATE_JDBC_DDL_FILE,
405                 createJdbcFileName);
406         addPropertyToDescriptor(puDescriptor,
407                 EntityManagerFactoryProvider.DROP_JDBC_DDL_FILE,
408                 dropJdbcFileName);
409     }
410     
411     /**
412      * Utility method that is used to actually set the property into the persistence unit descriptor.
413      * @param descriptor the persistence unit descriptor that is being worked on.
414      * @param propertyName the name of the property.
415      * @param propertyValue the value of the property.
416      */

417     private void addPropertyToDescriptor(PersistenceUnitDescriptor descriptor,
418             String JavaDoc propertyName, String JavaDoc propertyValue) {
419         String JavaDoc oldPropertyValue = descriptor.getProperties().getProperty(propertyName);
420         if(null == oldPropertyValue) {
421             descriptor.addProperty(propertyName, propertyValue);
422         }
423     }
424     
425     /**
426      * Since the actual jdbc files are generated
427      * by the toplink code, we need to create
428      * a persistence unit info object and then
429      * call into the toplink code.
430      * @param persistenceUnitDescriptor the persistence unit descriptor that is
431      * being worked on.
432      * @param createJdbcFileName the string name of the create
433      * jdbc ddl file.
434      * @param dropJdbcFileName the string name of the drop
435      * jdbc ddl file.
436      * @return the persistence unit info object that
437      * would used by toplink code.
438      */

439     private PersistenceUnitInfo loadPersistenceUnitBundle(
440             PersistenceUnitDescriptor persistenceUnitDescriptor,
441             String JavaDoc createJdbcFileName, String JavaDoc dropJdbcFileName) {
442         logger.entering("loadPersistenceUnitBundle", "load",
443                 new Object JavaDoc[]{persistenceUnitDescriptor});
444                         
445         if (! isSupportedPersistenceProvider(persistenceUnitDescriptor)) {
446             // Persistence provider is not toplink, hence exit from java2db code
447
return null;
448         }
449
450         PersistenceProvider provider;
451         addPropertiesToPU(persistenceUnitDescriptor);
452
453         final InstrumentableClassLoader cl =
454                 InstrumentableClassLoader.class.cast(
455                     persistenceUnitDescriptor.getClassLoader());
456         PersistenceUnitInfo pi = new PersistenceUnitInfoImpl(
457                 persistenceUnitDescriptor,
458                 appDeployedLocation,
459                 cl);
460  
461         if(debug)
462             logger.fine("PersistenceInfo for PU is :\n" + pi);
463         
464         provider = new EntityManagerFactoryProvider();
465         EntityManagerFactory emf = null;
466         try {
467             emf = provider.createContainerEntityManagerFactory(pi, null);
468             emf.createEntityManager();
469             if(debug)
470                 logger.fine("PersistenceProcessor", "loadPersistenceUnitBundle",
471                     "emf = {0}", emf);
472         } finally {
473             if(emf != null) {
474                 emf.close();
475             }
476         }
477         return pi;
478     }
479     
480     /**
481      * Given a persistence unit descriptor
482      * return the value of a property if the
483      * user has specified it.
484      * If the user has not defined this property
485      * return the default value.
486      * @param parBundle the persistence unit descriptor that is being worked on.
487      * @param propertyName the property name being checked.
488      * @param defaultValue the default value to be used.
489      * @return the property value.
490      */

491     private String JavaDoc getPersistencePropVal(PersistenceUnitDescriptor parBundle,
492         String JavaDoc propertyName, String JavaDoc defaultValue) {
493         String JavaDoc propertyValue;
494         if(null == defaultValue)
495             propertyValue = parBundle.getProperties().getProperty(propertyName);
496         else
497              propertyValue = parBundle.getProperties().
498                      getProperty(propertyName, defaultValue);
499
500         return propertyValue;
501     }
502         
503     /**
504      * The java2db feature is currently implemented only for toplink (the default
505      * persistence povider in glassfish). Hence we check for the name of the
506      * persistence provider class name. It it is not toplink, stop processing.
507      *
508      * @param persistenceUnitDescriptor the persistence unit descriptor that is being worked on.
509      * @return true if persistence provider is toplink.
510      */

511     private boolean isSupportedPersistenceProvider(
512             final PersistenceUnitDescriptor persistenceUnitDescriptor) {
513         String JavaDoc providerClassName =
514                 PersistenceUnitInfoImpl.getPersistenceProviderClassNameForPuDesc(persistenceUnitDescriptor);
515         boolean result = providerClassName.equals(TOPLINK_PERSISTENCE_PROVIDER_CLASS_NAME_OLD) ||
516                 providerClassName.equals(TOPLINK_PERSISTENCE_PROVIDER_CLASS_NAME_NEW);
517         if (!result) {
518             logI18NInfoMessage(
519                 "ejb.PersistenceProcessor.nondefaultprovider",
520                 TOPLINK_PERSISTENCE_PROVIDER_CLASS_NAME_OLD,
521                 providerClassName, null);
522         }
523         return result;
524     }
525     
526 }
527
Popular Tags