KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > internal > ejb > cmp3 > JavaSECMPInitializer


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
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
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 in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21 // Copyright (c) 1998, 2006, Oracle. All rights reserved.
22
package oracle.toplink.essentials.internal.ejb.cmp3;
23
24 import java.util.*;
25 import java.net.URL JavaDoc;
26 import java.net.URLClassLoader JavaDoc;
27 import java.lang.instrument.*;
28 import java.security.ProtectionDomain JavaDoc;
29
30 import oracle.toplink.essentials.ejb.cmp3.persistence.SEPersistenceUnitInfo;
31
32 import oracle.toplink.essentials.logging.AbstractSessionLog;
33 import oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerSetupImpl;
34 import oracle.toplink.essentials.ejb.cmp3.persistence.PersistenceUnitProcessor;
35 import oracle.toplink.essentials.exceptions.*;
36 import oracle.toplink.essentials.logging.SessionLog;
37 import oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider;
38 import oracle.toplink.essentials.PersistenceProvider;
39
40 import javax.persistence.spi.ClassTransformer;
41 import oracle.toplink.essentials.config.TopLinkProperties;
42
43 /**
44  * INTERNAL:
45  *
46  * JavaSECMPInitializer is used to bootstrap the deployment of EntityBeans in EJB 3.0
47  * when deployed in a non-managed setting
48  *
49  * It is called internally by our Provider
50  *
51  * @see oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider
52  */

53 public class JavaSECMPInitializer {
54
55     // Used when byte code enhancing
56
public static Instrumentation globalInstrumentation;
57
58     // The internal loader is used by applications that do weaving to pre load classes
59
// When this flag is set to false, we will not be able to weave.
60
protected boolean shouldCreateInternalLoader = true;
61
62     // The JavaSECMPInitializer - a singleton
63
protected static JavaSECMPInitializer javaSECMPInitializer;
64
65     // We create an EntityManagerSetupImpl for each persistence unit the following
66
// two variables maintain a dictionary of both the EntityManagerSetupImpls and
67
// their associated PersistenceUnitInfo objects
68
protected HashMap<String JavaDoc, EntityManagerSetupImpl> emSetupImpls = null;
69     protected HashMap<String JavaDoc, SEPersistenceUnitInfo> emSetupPersistenceUnitInfos = null;
70
71     protected ClassLoader JavaDoc sessionClassLoader = null;
72
73     /**
74      * INTERNAL:
75      * Get the singleton entityContainer.
76      * @return EnityContainer
77      */

78     public static JavaSECMPInitializer getJavaSECMPInitializer(Map properties) {
79         if (javaSECMPInitializer == null) {
80            initializeFromMain(properties);
81         }
82         return javaSECMPInitializer;
83     }
84
85   /**
86    * Return whether initialization has occured without actually triggering
87    * initialization
88    */

89     public static boolean isSingletonInitialized(){
90         return javaSECMPInitializer != null;
91     }
92
93   /**
94    * Look in the System properties for a logging level property and return a integer
95    * that can be used to set the logging level in TopLink
96    * @return
97    */

98     public static int getTopLinkLoggingLevel(){
99         String JavaDoc logLevel = System.getProperty(TopLinkProperties.LOGGING_LEVEL);
100         return AbstractSessionLog.translateStringToLoggingLevel(logLevel);
101     }
102
103     /**
104      * INTERNAL:
105      * User should not instantiate JavaSECMPInitializer.
106      */

107     protected JavaSECMPInitializer() {
108         super();
109         emSetupImpls = new HashMap<String JavaDoc, EntityManagerSetupImpl>();
110         emSetupPersistenceUnitInfos = new HashMap<String JavaDoc, SEPersistenceUnitInfo>();
111     }
112
113     /**
114      * INTERNAL
115      * predeploy (with deploy) is one of the two steps required in deployment of entities
116      * This method will prepare to call predeploy, call it and finally register the
117      * transformer returned to be used for weaving.
118      */

119     protected boolean callPredeploy(SEPersistenceUnitInfo persistenceUnitInfo, Map m) {
120         // we will only attempt to deploy when TopLink is specified as the provider or the provider is unspecified
121
String JavaDoc providerClassName = persistenceUnitInfo.getPersistenceProviderClassName();
122         if (providerClassName == null || providerClassName.equals("") || providerClassName.equals(EntityManagerFactoryProvider.class.getName()) || providerClassName.equals(PersistenceProvider.class.getName())){
123             Set tempLoaderSet = PersistenceUnitProcessor.buildClassSet(persistenceUnitInfo);
124             // Create the temp loader that will not cache classes for entities in our persistence unit
125
ClassLoader JavaDoc tempLoader = createTempLoader(tempLoaderSet);
126             persistenceUnitInfo.setNewTempClassLoader(tempLoader);
127
128             EntityManagerSetupImpl emSetupImpl = new EntityManagerSetupImpl();
129             emSetupImpls.put(persistenceUnitInfo.getPersistenceUnitName(), emSetupImpl);
130             emSetupPersistenceUnitInfos.put(persistenceUnitInfo.getPersistenceUnitName(), persistenceUnitInfo);
131            
132             // Make the callback
133
AbstractSessionLog.getLog().log(SessionLog.FINER, "cmp_init_invoke_predeploy", persistenceUnitInfo.getPersistenceUnitName());
134
135             Map mergedProperties = EntityManagerFactoryProvider.mergeMaps(m, persistenceUnitInfo.getProperties());
136             //Bug#4452468 When globalInstrumentation is null, there is no weaving
137
if (globalInstrumentation == null && EntityManagerFactoryProvider.getConfigPropertyAsString(TopLinkProperties.WEAVING, mergedProperties, null) == null) {
138                 if (m == null) {
139                     m = new HashMap();
140                 }
141                 m.put(TopLinkProperties.WEAVING, "false");
142             }
143     
144             // A call to predeploy will partially build the session we will use
145
final ClassTransformer transformer = emSetupImpl.predeploy(persistenceUnitInfo, m);
146     
147             // If we got a transformer then register it
148
if ((transformer != null) && (globalInstrumentation != null)) {
149                 AbstractSessionLog.getLog().log(SessionLog.FINER, "cmp_init_register_transformer", persistenceUnitInfo.getPersistenceUnitName());
150                 globalInstrumentation.addTransformer(new ClassFileTransformer(){
151                     // adapt ClassTransformer to ClassFileTransformer interface
152
public byte[] transform(
153                             ClassLoader JavaDoc loader, String JavaDoc className,
154                             Class JavaDoc<?> classBeingRedefined,
155                             ProtectionDomain JavaDoc protectionDomain,
156                             byte[] classfileBuffer) throws IllegalClassFormatException {
157                         return transformer.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
158                     }
159                 });
160             } else if (transformer == null) {
161                 AbstractSessionLog.getLog().log(SessionLog.FINER, "cmp_init_transformer_is_null");
162             } else if (globalInstrumentation == null) {
163                 AbstractSessionLog.getLog().log(SessionLog.FINER, "cmp_init_globalInstrumentation_is_null");
164             }
165             persistenceUnitInfo.setClassLoader(getMainLoader());
166             return true;
167         }
168         return false;
169     }
170     
171     /**
172  * Create a temporary class loader that can be used to inspect classes and then
173  * thrown away. This allows classes to be introspected prior to loading them
174  * with application's main class loader enabling weaving.
175  */

176     protected ClassLoader JavaDoc createTempLoader(Collection col) {
177         return createTempLoader(col, true);
178     }
179
180     protected ClassLoader JavaDoc createTempLoader(Collection col, boolean shouldOverrideLoadClassForCollectionMembers) {
181         if (!shouldCreateInternalLoader) {
182             return Thread.currentThread().getContextClassLoader();
183         }
184
185         ClassLoader JavaDoc currentLoader = Thread.currentThread().getContextClassLoader();
186         if (!(currentLoader instanceof URLClassLoader JavaDoc)) {
187             //we can't create a TempEntityLoader so just use the current one
188
//shouldn't be a problem (and should only occur) in JavaSE
189
return currentLoader;
190         }
191         URL JavaDoc[] urlPath = ((URLClassLoader JavaDoc)currentLoader).getURLs();
192         ClassLoader JavaDoc tempLoader = new TempEntityLoader(urlPath, currentLoader, col, shouldOverrideLoadClassForCollectionMembers);
193
194         AbstractSessionLog.getLog().log(SessionLog.FINER, "cmp_init_tempLoader_created", tempLoader);
195         AbstractSessionLog.getLog().log(SessionLog.FINER, "cmp_init_shouldOverrideLoadClassForCollectionMembers", new Boolean JavaDoc(shouldOverrideLoadClassForCollectionMembers));
196
197         return tempLoader;
198     }
199     
200   /**
201    * Return the setup class for a given entity manager name
202    * @param emName
203    */

204     public EntityManagerSetupImpl getEntityManagerSetupImpl(String JavaDoc emName){
205         if (emName == null){
206             return (EntityManagerSetupImpl)emSetupImpls.get("");
207         }
208         return (EntityManagerSetupImpl)emSetupImpls.get(emName);
209     }
210
211     public static ClassLoader JavaDoc getMainLoader() {
212         return Thread.currentThread().getContextClassLoader();
213     }
214
215   /**
216    * Initialize one persistence unit.
217    * Initialization is a two phase process. First the predeploy process builds the metadata
218    * and creates any required transformers.
219    * Second the deploy process creates a TopLink session based on that metadata.
220    */

221     protected void initPersistenceUnits(URL JavaDoc url, Map m) {
222         Iterator<SEPersistenceUnitInfo> persistenceUnits = PersistenceUnitProcessor.getPersistenceUnits(url, sessionClassLoader).iterator();
223         while (persistenceUnits.hasNext()){
224             SEPersistenceUnitInfo persistenceUnitInfo = persistenceUnits.next();
225             callPredeploy(persistenceUnitInfo, m);
226         }
227     }
228
229     /**
230      * INTERNAL
231      * This method initializes the container. Essentially, it will try to load the
232      * class that contains the list of entities and reflectively call the method that
233      * contains that list. It will then initialize the container with that list.
234      * If succeeded return true, false otherwise.
235      */

236     public void initialize(Map m) {
237         sessionClassLoader = getMainLoader();
238         for (URL JavaDoc url: PersistenceUnitProcessor.findPersistenceArchives()){
239             AbstractSessionLog.getLog().log(SessionLog.FINER, "cmp_init_initialize", url);
240             initPersistenceUnits(url, m);
241         }
242     }
243
244     /**
245      * INTERNAL:
246      * Should be called only by the agent. (when weaving classes)
247      * If succeeded return true, false otherwise.
248      */

249     protected static void initializeFromAgent(Instrumentation instrumentation) throws Exception JavaDoc {
250         AbstractSessionLog.getLog().setLevel(JavaSECMPInitializer.getTopLinkLoggingLevel());
251
252         // Squirrel away the instrumentation for later
253
globalInstrumentation = instrumentation;
254         // Create JavaSECMPInitializer singleton
255
javaSECMPInitializer = new JavaSECMPInitializer();
256         // Initialize it
257
javaSECMPInitializer.initialize(new HashMap());
258     }
259
260     /**
261      * Initialize the static entityContainer from a main method. The entityContainer
262      * can also be initialized from a premain method. with slightly different behavior
263      * @param cls the class of the JavaSECMPInitializer. We will instantiate it reflectively
264      * @param m a map containing the set of properties to intantiate with.
265      */

266     public static void initializeFromMain(Map m) {
267         if (javaSECMPInitializer != null) {
268             return;
269         }
270
271         javaSECMPInitializer = new JavaSECMPInitializer();
272         AbstractSessionLog.getLog().setLevel(JavaSECMPInitializer.getTopLinkLoggingLevel());
273
274         AbstractSessionLog.getLog().log(SessionLog.FINER, "cmp_init_initialize_from_main");
275
276         // Initialize it
277
javaSECMPInitializer.initialize(m);
278     }
279
280     /**
281      * INTERNAL:
282      * Create a list of java.lang.Class that contains the classes of all the entities
283      * that we will be deploying
284      */

285     protected Set loadEntityClasses(Collection entityNames, ClassLoader JavaDoc classLoader) {
286         Set entityClasses = new HashSet();
287
288         // Load the classes using the loader passed in
289
AbstractSessionLog.getLog().log(SessionLog.FINER, "cmp_loading_entities_using_loader", classLoader);
290         for (Iterator iter = entityNames.iterator(); iter.hasNext();) {
291             String JavaDoc entityClassName = (String JavaDoc)iter.next();
292             try {
293                 entityClasses.add(classLoader.loadClass(entityClassName));
294             } catch (ClassNotFoundException JavaDoc cnfEx) {
295                 throw ValidationException.entityClassNotFound(entityClassName, classLoader, cnfEx);
296             }
297         }
298         return entityClasses;
299     }
300
301     /*********************************/
302     /***** Temporary Classloader *****/
303     /*********************************/
304     /** This class loader is provided at initialization time to allow us to temporarily load
305      * domain classes so we can examine them for annotations. After they are loaded we will throw this
306      * class loader away. Transformers can then be registered on the real class loader to allow
307      * weaving to occur.
308      *
309      * It selectively loads classes based on the list of classnames it is instantiated with. Classes
310      * not on that list are allowed to be loaded by the parent.
311      */

312     public class TempEntityLoader extends URLClassLoader JavaDoc {
313         Collection classNames;
314         boolean shouldOverrideLoadClassForCollectionMembers;
315         
316         //added to resolved gf #589 - without this, the orm.xml url would be returned twice
317
public Enumeration<URL JavaDoc> getResources(String JavaDoc name) throws java.io.IOException JavaDoc {
318             return this.getParent().getResources(name);
319         }
320
321         public TempEntityLoader(URL JavaDoc[] urls, ClassLoader JavaDoc parent, Collection classNames, boolean shouldOverrideLoadClassForCollectionMembers) {
322             super(urls, parent);
323             this.classNames = classNames;
324             this.shouldOverrideLoadClassForCollectionMembers = shouldOverrideLoadClassForCollectionMembers;
325         }
326
327         public TempEntityLoader(URL JavaDoc[] urls, ClassLoader JavaDoc parent, Collection classNames) {
328             this(urls, parent, classNames, true);
329         }
330
331         // Indicates if the classLoad should be overridden for the passed className.
332
// Returns true in case the class should NOT be loaded by parent classLoader.
333
protected boolean shouldOverrideLoadClass(String JavaDoc name) {
334             if (shouldOverrideLoadClassForCollectionMembers) {
335                 // Override classLoad if the name is in collection
336
return (classNames != null) && classNames.contains(name);
337             } else {
338                 // Directly opposite: Override classLoad if the name is NOT in collection.
339
// Forced to check for java. and javax. packages here, because even if the class
340
// has been loaded by parent loader we would load it again
341
// (see comment in loadClass)
342
return !name.startsWith("java.") && !name.startsWith("javax.") && ((classNames == null) || !classNames.contains(name));
343             }
344         }
345
346         protected synchronized Class JavaDoc loadClass(String JavaDoc name, boolean resolve) throws ClassNotFoundException JavaDoc {
347             if (shouldOverrideLoadClass(name)) {
348                 // First, check if the class has already been loaded.
349
// Note that the check only for classes loaded by this loader,
350
// it doesn't return true if the class has been loaded by parent loader
351
// (forced to live with that because findLoadedClass method defined as final protected:
352
// neither can override it nor call it on the parent loader)
353
Class JavaDoc c = findLoadedClass(name);
354                 if (c == null) {
355                     c = findClass(name);
356                 }
357                 if (resolve) {
358                     resolveClass(c);
359                 }
360                 return c;
361             } else {
362                 return super.loadClass(name, resolve);
363             }
364         }
365     }
366
367 }
368
Popular Tags