View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software 
12   * distributed under the License is distributed on an "AS IS" BASIS, 
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
14   * See the License for the specific language governing permissions and 
15   * limitations under the License.
16   */
17  
18  /*
19   * JDOHelper.java
20   *
21   */
22   
23  package javax.jdo;
24  
25  import org.xml.sax.SAXException;
26  import org.xml.sax.SAXParseException;
27  import org.xml.sax.ErrorHandler;
28  import org.w3c.dom.Document;
29  import org.w3c.dom.Element;
30  import org.w3c.dom.NodeList;
31  import org.w3c.dom.Node;
32  import org.w3c.dom.NamedNodeMap;
33  
34  import javax.jdo.spi.I18NHelper;
35  import javax.jdo.spi.JDOImplHelper;
36  import javax.jdo.spi.JDOImplHelper.StateInterrogationBooleanReturn;
37  import javax.jdo.spi.JDOImplHelper.StateInterrogationObjectReturn;
38  import javax.jdo.spi.PersistenceCapable;
39  import javax.jdo.spi.StateInterrogation;
40  import javax.naming.Context;
41  import javax.naming.InitialContext;
42  import javax.naming.NamingException;
43  import javax.rmi.PortableRemoteObject;
44  import javax.xml.parsers.DocumentBuilder;
45  import javax.xml.parsers.DocumentBuilderFactory;
46  import javax.xml.parsers.FactoryConfigurationError;
47  import javax.xml.parsers.ParserConfigurationException;
48  import java.lang.reflect.InvocationTargetException;
49  import java.lang.reflect.Method;
50  import java.net.URL;
51  import java.security.AccessController;
52  import java.security.PrivilegedAction;
53  import java.security.PrivilegedActionException;
54  import java.security.PrivilegedExceptionAction;
55  import java.util.Map;
56  import java.util.HashMap;
57  import java.util.Collections;
58  import java.util.Collection;
59  import java.util.Iterator;
60  import java.util.List;
61  import java.util.ArrayList;
62  import java.util.Properties;
63  import java.util.Enumeration;
64  import java.io.IOException;
65  import java.io.InputStream;
66  import java.io.BufferedReader;
67  import java.io.InputStreamReader;
68  import java.io.File;
69  import java.io.FileInputStream;
70  import java.io.FileNotFoundException;
71  
72  
73  /***
74   * This class can be used by a JDO-aware application to call the JDO behavior
75   * of <code>PersistenceCapable</code> instances without declaring them to be
76   * <code>PersistenceCapable</code>.
77   * <P>It is also used to acquire a <code>PersistenceManagerFactory</code> via 
78   * various methods.
79   * <P>This helper class defines static methods that allow a JDO-aware
80   * application to examine the runtime state of instances.  For example,
81   * an application can discover whether the instance is persistent, 
82   * transactional, dirty, new, deleted, or detached; and to get its associated
83   * <code>PersistenceManager</code> if it has one.
84   * 
85   * @version 2.1
86   */
87  public class JDOHelper implements Constants {
88  
89      /***
90       * A mapping from jdoconfig.xsd element attributes to PMF properties.
91       */
92      static final Map ATTRIBUTE_PROPERTY_XREF
93          = createAttributePropertyXref();
94  
95      /*** The Internationalization message helper.
96       */
97      private final static I18NHelper msg = 
98          I18NHelper.getInstance ("javax.jdo.Bundle"); //NOI18N
99  
100     /***
101      * Creates a map from jdoconfig.xsd element attributes to PMF properties.
102      * @return An unmodifiable Map of jdoconfig.xsd element attributes to PMF
103      * properties.
104      */
105     static Map createAttributePropertyXref() {
106         Map xref = new HashMap();
107 
108         xref.put(
109             PMF_ATTRIBUTE_CLASS,
110             PROPERTY_PERSISTENCE_MANAGER_FACTORY_CLASS);
111         xref.put(
112             PMF_ATTRIBUTE_CONNECTION_DRIVER_NAME,
113             PROPERTY_CONNECTION_DRIVER_NAME);
114         xref.put(
115             PMF_ATTRIBUTE_CONNECTION_FACTORY_NAME,
116             PROPERTY_CONNECTION_FACTORY_NAME);
117         xref.put(
118             PMF_ATTRIBUTE_CONNECTION_FACTORY2_NAME,
119             PROPERTY_CONNECTION_FACTORY2_NAME);
120         xref.put(
121             PMF_ATTRIBUTE_CONNECTION_PASSWORD,
122             PROPERTY_CONNECTION_PASSWORD);
123         xref.put(
124             PMF_ATTRIBUTE_CONNECTION_URL,
125             PROPERTY_CONNECTION_URL);
126         xref.put(
127             PMF_ATTRIBUTE_CONNECTION_USER_NAME,
128             PROPERTY_CONNECTION_USER_NAME);
129         xref.put(
130             PMF_ATTRIBUTE_IGNORE_CACHE,
131             PROPERTY_IGNORE_CACHE);
132         xref.put(
133             PMF_ATTRIBUTE_MAPPING,
134             PROPERTY_MAPPING);
135         xref.put(
136             PMF_ATTRIBUTE_MULTITHREADED,
137             PROPERTY_MULTITHREADED);
138         xref.put(
139             PMF_ATTRIBUTE_NONTRANSACTIONAL_READ,
140             PROPERTY_NONTRANSACTIONAL_READ);
141         xref.put(
142             PMF_ATTRIBUTE_NONTRANSACTIONAL_WRITE,
143             PROPERTY_NONTRANSACTIONAL_WRITE);
144         xref.put(
145             PMF_ATTRIBUTE_OPTIMISTIC,
146             PROPERTY_OPTIMISTIC);
147         xref.put(
148             PMF_ATTRIBUTE_PERSISTENCE_UNIT_NAME,
149             PROPERTY_PERSISTENCE_UNIT_NAME);
150         xref.put(
151             PMF_ATTRIBUTE_NAME,
152             PROPERTY_NAME);
153         xref.put(
154             PMF_ATTRIBUTE_RESTORE_VALUES,
155             PROPERTY_RESTORE_VALUES);
156         xref.put(
157             PMF_ATTRIBUTE_RETAIN_VALUES,
158             PROPERTY_RETAIN_VALUES);
159         xref.put(
160             PMF_ATTRIBUTE_DETACH_ALL_ON_COMMIT,
161             PROPERTY_DETACH_ALL_ON_COMMIT);
162         xref.put(
163             PMF_ATTRIBUTE_SERVER_TIME_ZONE_ID,
164             PROPERTY_SERVER_TIME_ZONE_ID);
165 
166         return Collections.unmodifiableMap(xref);
167     }
168 
169     /*** The JDOImplHelper instance used for handling non-binary-compatible
170      *  implementations.
171      */
172     private static JDOImplHelper implHelper = (JDOImplHelper)
173         AccessController.doPrivileged(
174             new PrivilegedAction () {
175                 public Object run () {
176                     return JDOImplHelper.getInstance();
177                 }
178             }
179         );
180 
181     /*** The singleton instance of JDOHelper.
182      * @since 2.1
183      */
184     private static JDOHelper instance = new JDOHelper();
185 
186     /***
187      * Return the singleton instance of JDOHelper. This instance is 
188      * thread-safe.
189      * @since 2.1
190      * @return the thread-safe singleton JDOHelper
191      */
192     public static JDOHelper getInstance() {
193         return instance;
194     }
195 
196     /*** Some applications might prefer to use instance
197      * methods instead of static methods.
198      * @since 2.1
199      */
200     public JDOHelper() {}
201 
202     /*** The stateless instance used for handling non-binary-compatible
203     *  implementations of getPersistenceManager.
204     */
205     static StateInterrogationObjectReturn getPersistenceManager =
206         new StateInterrogationObjectReturn() {
207             public Object get(Object pc, StateInterrogation si) {
208                 return si.getPersistenceManager(pc);
209             }
210         };
211 
212    /*** The stateless instance used for handling non-binary-compatible
213     *  implementations of getObjectId.
214     */
215     static StateInterrogationObjectReturn getObjectId =
216         new StateInterrogationObjectReturn() {
217             public Object get(Object pc, StateInterrogation si) {
218                 return si.getObjectId(pc);
219             }
220         };
221 
222    /*** The stateless instance used for handling non-binary-compatible
223     *  implementations of getTransactionalObjectId.
224     */
225     static StateInterrogationObjectReturn getTransactionalObjectId =
226         new StateInterrogationObjectReturn() {
227             public Object get(Object pc, StateInterrogation si) {
228                 return si.getTransactionalObjectId(pc);
229             }
230         };
231 
232    /*** The stateless instance used for handling non-binary-compatible
233     *  implementations of getVersion.
234     */
235     static StateInterrogationObjectReturn getVersion =
236         new StateInterrogationObjectReturn() {
237             public Object get(Object pc, StateInterrogation si) {
238                 return si.getVersion(pc);
239             }
240         };
241 
242    /*** The stateless instance used for handling non-binary-compatible
243     *  implementations of isPersistent.
244     */
245     static StateInterrogationBooleanReturn isPersistent =
246         new StateInterrogationBooleanReturn() {
247             public Boolean is(Object pc, StateInterrogation si) {
248                 return si.isPersistent(pc);
249             }
250         };
251 
252    /*** The stateless instance used for handling non-binary-compatible
253     *  implementations of isTransactional.
254     */
255     static StateInterrogationBooleanReturn isTransactional =
256         new StateInterrogationBooleanReturn() {
257             public Boolean is(Object pc, StateInterrogation si) {
258                 return si.isTransactional(pc);
259             }
260         };
261 
262    /*** The stateless instance used for handling non-binary-compatible
263     *  implementations of isDirty.
264     */
265     static StateInterrogationBooleanReturn isDirty =
266         new StateInterrogationBooleanReturn() {
267             public Boolean is(Object pc, StateInterrogation si) {
268                 return si.isDirty(pc);
269             }
270         };
271 
272    /*** The stateless instance used for handling non-binary-compatible
273     *  implementations of isNew.
274     */
275     static StateInterrogationBooleanReturn isNew =
276         new StateInterrogationBooleanReturn() {
277             public Boolean is(Object pc, StateInterrogation si) {
278                 return si.isNew(pc);
279             }
280         };
281 
282    /*** The stateless instance used for handling non-binary-compatible
283     *  implementations of isDeleted.
284     */
285     static StateInterrogationBooleanReturn isDeleted =
286         new StateInterrogationBooleanReturn() {
287             public Boolean is(Object pc, StateInterrogation si) {
288                 return si.isDeleted(pc);
289             }
290         };
291 
292    /*** The stateless instance used for handling non-binary-compatible
293     *  implementations of isDetached.
294     */
295     static StateInterrogationBooleanReturn isDetached =
296         new StateInterrogationBooleanReturn() {
297             public Boolean is(Object pc, StateInterrogation si) {
298                 return si.isDetached(pc);
299             }
300         };
301 
302     /*** Return the associated <code>PersistenceManager</code> if there is one.
303      * Transactional and persistent instances return the associated
304      * <code>PersistenceManager</code>.  
305      *
306      * <P>Transient non-transactional instances and instances of classes 
307      * that do not implement <code>PersistenceCapable</code> return 
308      * <code>null</code>.
309      * @see PersistenceCapable#jdoGetPersistenceManager()
310      * @param pc the <code>PersistenceCapable</code> instance.
311      * @return the <code>PersistenceManager</code> associated with the parameter
312      * instance.
313      */
314      public static PersistenceManager getPersistenceManager(Object pc) {
315         if (pc instanceof PersistenceCapable) {
316             return ((PersistenceCapable)pc).jdoGetPersistenceManager();
317         } else {
318             return (PersistenceManager)
319                 implHelper.nonBinaryCompatibleGet(pc, getPersistenceManager);
320         }
321       }
322     
323     /*** Explicitly mark the parameter instance and field dirty.
324      * Normally, <code>PersistenceCapable</code> classes are able to detect 
325      * changes made to their fields.  However, if a reference to an array is 
326      * given to a method outside the class, and the array is modified, then the
327      * persistent instance is not aware of the change.  This API allows the
328      * application to notify the instance that a change was made to a field.
329      *
330      * <P>Transient instances and instances of classes 
331      * that do not implement <code>PersistenceCapable</code> ignore this method.
332      * @see PersistenceCapable#jdoMakeDirty(String fieldName)
333      * @param pc the <code>PersistenceCapable</code> instance.
334      * @param fieldName the name of the field to be marked dirty.
335      */
336     public static void makeDirty(Object pc, String fieldName) {
337         if (pc instanceof PersistenceCapable) {
338             ((PersistenceCapable)pc).jdoMakeDirty(fieldName);
339         } else {
340              implHelper.nonBinaryCompatibleMakeDirty(pc, fieldName);
341         }
342     }
343     
344     /*** Return a copy of the JDO identity associated with the parameter 
345      * instance.
346      *
347      * <P>Persistent instances of <code>PersistenceCapable</code> classes have a
348      * JDO identity managed by the <code>PersistenceManager</code>.  This method
349      * returns a copy of the ObjectId that represents the JDO identity.  
350      * 
351      * <P>Transient instances and instances of classes that do not implement 
352      * <code>PersistenceCapable</code> return <code>null</code>.
353      *
354      * <P>The ObjectId may be serialized
355      * and later restored, and used with a <code>PersistenceManager</code> from 
356      * the same JDO implementation to locate a persistent instance with the same
357      * data store identity.
358      *
359      * <P>If the JDO identity is managed by the application, then the ObjectId 
360      * may be used with a <code>PersistenceManager</code> from any JDO 
361      * implementation that supports the <code>PersistenceCapable</code> class.
362      *
363      * <P>If the JDO identity is not managed by the application or the data 
364      * store, then the ObjectId returned is only valid within the current 
365      * transaction.
366      *<P>
367      * @see PersistenceManager#getObjectId(Object pc)
368      * @see PersistenceCapable#jdoGetObjectId()
369      * @see PersistenceManager#getObjectById(Object oid, boolean validate)
370      * @param pc the PersistenceCapable instance.
371      * @return a copy of the ObjectId of the parameter instance as of the 
372      * beginning of the transaction.
373      */
374     public static Object getObjectId(Object pc) {
375       if (pc instanceof PersistenceCapable) {
376           return ((PersistenceCapable)pc).jdoGetObjectId();
377         } else {
378             return implHelper.nonBinaryCompatibleGet(pc, getObjectId);
379         }
380     }
381 
382     /*** Get object ids for a collection of instances. For each instance
383      * in the parameter, the getObjectId method is called. This method
384      * returns one identity instance for each element 
385      * in the parameter. The order of iteration of the returned
386      * Collection exactly matches the order of iteration of the
387      * parameter Collection.
388      * @param pcs the persistence-capable instances
389      * @return the object ids of the parameters
390      * @see #getObjectId(Object pc)
391      * @see #getObjectIds(Object[] pcs)
392      * @since 2.0
393      */
394     public static Collection getObjectIds(Collection pcs) {
395         ArrayList result = new ArrayList();
396         for (Iterator it = pcs.iterator(); it.hasNext();) {
397             result.add(getObjectId(it.next()));
398         }
399         return result;
400     }
401 
402     /*** Get object ids for an array of instances. For each instance
403      * in the parameter, the getObjectId method is called. This method
404      * returns one identity instance for each element 
405      * in the parameter. The order of instances of the returned
406      * array exactly matches the order of instances of the
407      * parameter array.
408      * @param pcs the persistence-capable instances
409      * @return the object ids of the parameters
410      * @see #getObjectId(Object pc)
411      * @see #getObjectIds(Collection pcs)
412      * @since 2.0
413      */
414     public static Object[] getObjectIds(Object[] pcs) {
415         Object[] result = new Object[pcs.length];
416         for (int i = 0; i < pcs.length; ++i) {
417             result[i] = getObjectId(pcs[i]);
418         }
419         return result;
420     }
421 
422     /*** Return a copy of the JDO identity associated with the parameter 
423      * instance.
424      *
425      * @see PersistenceCapable#jdoGetTransactionalObjectId()
426      * @see PersistenceManager#getObjectById(Object oid, boolean validate)
427      * @param pc the <code>PersistenceCapable</code> instance.
428      * @return a copy of the ObjectId of the parameter instance as modified in 
429      * this transaction.
430      */
431     public static Object getTransactionalObjectId(Object pc) {
432       if (pc instanceof PersistenceCapable) {
433           return ((PersistenceCapable)pc).jdoGetTransactionalObjectId();
434         } else {
435             return implHelper.nonBinaryCompatibleGet(
436                 pc, getTransactionalObjectId);
437         }
438     }
439     
440     /***
441      * Return the version of the instance.
442      * @since 2.0
443      * @param pc the instance
444      * @return the version of the instance
445      */
446     public static Object getVersion (Object pc) {
447       if (pc instanceof PersistenceCapable) {
448           return ((PersistenceCapable)pc).jdoGetVersion();
449         } else {
450             return implHelper.nonBinaryCompatibleGet(pc, getVersion);
451         }
452     }
453     /*** Tests whether the parameter instance is dirty.
454      *
455      * Instances that have been modified, deleted, or newly 
456      * made persistent in the current transaction return <code>true</code>.
457      *
458      *<P>Transient instances and instances of classes that do not implement 
459      * <code>PersistenceCapable</code> return <code>false</code>.
460      *<P>
461      * @see javax.jdo.spi.StateManager#makeDirty(PersistenceCapable pc, 
462      * String fieldName)
463      * @see PersistenceCapable#jdoIsDirty()
464      * @param pc the <code>PersistenceCapable</code> instance.
465      * @return <code>true</code> if the parameter instance has been modified in 
466      * the current transaction.
467      */
468     public static boolean isDirty(Object pc) {
469       if (pc instanceof PersistenceCapable) {
470           return ((PersistenceCapable)pc).jdoIsDirty();
471         } else {
472             return implHelper.nonBinaryCompatibleIs(pc, isDirty);
473         }
474     }
475 
476     /*** Tests whether the parameter instance is transactional.
477      *
478      * Instances whose state is associated with the current transaction 
479      * return true. 
480      *
481      *<P>Transient instances and instances of classes that do not implement 
482      * <code>PersistenceCapable</code> return <code>false</code>.
483      * @see PersistenceCapable#jdoIsTransactional()
484      * @param pc the <code>PersistenceCapable</code> instance.
485      * @return <code>true</code> if the parameter instance is transactional.
486      */
487     public static boolean isTransactional(Object pc) {
488       if (pc instanceof PersistenceCapable) {
489           return ((PersistenceCapable)pc).jdoIsTransactional();
490         } else {
491             return implHelper.nonBinaryCompatibleIs(pc, isTransactional);
492         }
493     }
494 
495     /*** Tests whether the parameter instance is persistent.
496      *
497      * Instances that represent persistent objects in the data store 
498      * return <code>true</code>. 
499      *
500      *<P>Transient instances and instances of classes that do not implement 
501      * <code>PersistenceCapable</code> return <code>false</code>.
502      *<P>
503      * @see PersistenceManager#makePersistent(Object pc)
504      * @see PersistenceCapable#jdoIsPersistent()
505      * @param pc the <code>PersistenceCapable</code> instance.
506      * @return <code>true</code> if the parameter instance is persistent.
507      */
508     public static boolean isPersistent(Object pc) {
509       if (pc instanceof PersistenceCapable) {
510           return ((PersistenceCapable)pc).jdoIsPersistent();
511         } else {
512             return implHelper.nonBinaryCompatibleIs(pc, isPersistent);
513         }
514     }
515 
516     /*** Tests whether the parameter instance has been newly made persistent.
517      *
518      * Instances that have been made persistent in the current transaction 
519      * return <code>true</code>.
520      *
521      *<P>Transient instances and instances of classes that do not implement 
522      * <code>PersistenceCapable</code> return <code>false</code>.
523      *<P>
524      * @see PersistenceManager#makePersistent(Object pc)
525      * @see PersistenceCapable#jdoIsNew()
526      * @param pc the <code>PersistenceCapable</code> instance.
527      * @return <code>true</code> if the parameter instance was made persistent
528      * in the current transaction.
529      */
530     public static boolean isNew(Object pc) {
531       if (pc instanceof PersistenceCapable) {
532           return ((PersistenceCapable)pc).jdoIsNew();
533         } else {
534             return implHelper.nonBinaryCompatibleIs(pc, isNew);
535         }
536     }
537 
538     /*** Tests whether the parameter instance has been deleted.
539      *
540      * Instances that have been deleted in the current transaction return 
541      * <code>true</code>.
542      *
543      *<P>Transient instances and instances of classes that do not implement 
544      * <code>PersistenceCapable</code> return <code>false</code>.
545      *<P>
546      * @see PersistenceManager#deletePersistent(Object pc)
547      * @see PersistenceCapable#jdoIsDeleted()
548      * @param pc the <code>PersistenceCapable</code> instance.
549      * @return <code>true</code> if the parameter instance was deleted
550      * in the current transaction.
551      */
552     public static boolean isDeleted(Object pc) {
553       if (pc instanceof PersistenceCapable) {
554           return ((PersistenceCapable)pc).jdoIsDeleted();
555         } else {
556             return implHelper.nonBinaryCompatibleIs(pc, isDeleted);
557         }
558     }
559     
560     /***
561      * Tests whether the parameter instance has been detached.
562      * 
563      * Instances that have been detached return true.
564      * 
565      * <P>Transient instances return false.
566      * <P>
567      * @see PersistenceCapable#jdoIsDetached()
568      * @return <code>true</code> if this instance is detached.
569      * @since 2.0
570      * @param pc the instance
571      */
572     public static boolean isDetached(Object pc) {
573       if (pc instanceof PersistenceCapable) {
574           return ((PersistenceCapable)pc).jdoIsDetached();
575         } else {
576             return implHelper.nonBinaryCompatibleIs(pc, isDetached);
577         }
578     }
579 
580     /*** Accessor for the state of the passed object.
581      * @param pc The object
582      * @return The object state
583      * @since 2.1
584      */
585     public static ObjectState getObjectState(Object pc) {
586         if (pc == null) {
587             return null;
588         }
589 
590         if (isDetached(pc)) {
591             if (isDirty(pc)) {
592                 // Detached Dirty
593                 return ObjectState.DETACHED_DIRTY;
594             }
595             else {
596                 // Detached Not Dirty
597                 return ObjectState.DETACHED_CLEAN;
598             }
599         }
600         else {
601             if (isPersistent(pc)) {
602                 if (isTransactional(pc)) {
603                     if (isDirty(pc)) {
604                         if (isNew(pc)) {
605                             if (isDeleted(pc)) {
606                                 // Persistent Transactional Dirty New Deleted
607                                 return ObjectState.PERSISTENT_NEW_DELETED;
608                             } else {
609                                 // Persistent Transactional Dirty New Not Deleted
610                                 return ObjectState.PERSISTENT_NEW;
611                             }
612                         } else {
613                             if (isDeleted(pc)) {
614                                 // Persistent Transactional Dirty Not New Deleted
615                                 return ObjectState.PERSISTENT_DELETED;
616                             } else {
617                                 // Persistent Transactional Dirty Not New Not Deleted
618                                 return ObjectState.PERSISTENT_DIRTY;
619                             }
620                         }
621                     } else {
622                         // Persistent Transactional Not Dirty
623                         return ObjectState.PERSISTENT_CLEAN;
624                     }
625                 }
626                 else {
627                     if (isDirty(pc)) {
628                     // Persistent Nontransactional Dirty
629                         return ObjectState.PERSISTENT_NONTRANSACTIONAL_DIRTY;
630                     }
631                     else {
632                     // Persistent Nontransactional Not Dirty
633                         return ObjectState.HOLLOW_PERSISTENT_NONTRANSACTIONAL;
634                     }
635                 }
636             }
637             else {
638                 if (isTransactional(pc)) {
639                     if (isDirty(pc)) {
640                         // Not Persistent Transactional Dirty
641                         return ObjectState.TRANSIENT_DIRTY;                        
642                     } else {
643                         // Not Persistent Transactional Not Dirty
644                         return ObjectState.TRANSIENT_CLEAN;
645                     }
646                 }
647                 else {
648                     // Not Persistent Not Transactional
649                     return ObjectState.TRANSIENT;
650                 }
651             }
652         }
653     }
654 
655     /*** Get the anonymous <code>PersistenceManagerFactory</code> configured via
656      * the standard configuration file resource "META-INF/jdoconfig.xml", using
657      * the current thread's context class loader
658      * to locate the configuration file resource(s).
659      * @return the anonymous <code>PersistenceManagerFactory</code>.
660      * @since 2.1
661      * @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader)
662      */
663     public static PersistenceManagerFactory getPersistenceManagerFactory() {
664         ClassLoader cl = getContextClassLoader();
665         return getPersistenceManagerFactory(
666                 null, ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME, cl, cl);
667     }
668 
669     /*** Get the anonymous <code>PersistenceManagerFactory</code> configured via
670      * the standard configuration file resource "META-INF/jdoconfig.xml", using
671      * the given class loader.
672      * @return the anonymous <code>PersistenceManagerFactory</code>.
673      * @param pmfClassLoader the ClassLoader used to load resources and classes
674      * @since 2.1
675      * @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader)
676      */
677     public static PersistenceManagerFactory getPersistenceManagerFactory(
678             ClassLoader pmfClassLoader) {
679         return getPersistenceManagerFactory(
680                 null,
681                 ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME,
682                 pmfClassLoader, pmfClassLoader);
683     }
684 
685     /*** Get a <code>PersistenceManagerFactory</code> based on a <code>Properties</code>
686      * instance, using the current thread's context class loader to locate the
687      * <code>PersistenceManagerFactory</code> class.
688      * @return the <code>PersistenceManagerFactory</code>.
689      * @param props a <code>Properties</code> instance with properties of the
690      * <code>PersistenceManagerFactory</code>.
691      * @see #getPersistenceManagerFactory(java.util.Map,ClassLoader)
692      */
693     public static PersistenceManagerFactory getPersistenceManagerFactory
694             (Map props) {
695         return getPersistenceManagerFactory(
696                 null, props, getContextClassLoader());
697     }
698 
699 
700     /*** Get a <code>PersistenceManagerFactory</code> based on a 
701      * <code>Map</code> and a class loader.
702      * This method delegates to the getPersistenceManagerFactory
703      * method that takes a Map of overrides and a Map of properties,
704      * passing null as the overrides parameter.
705      * @see #getPersistenceManagerFactory(java.util.Map, java.util.Map, ClassLoader)
706      * @return the <code>PersistenceManagerFactory</code>.
707      * @param props a <code>Map</code> with properties of the 
708      * <code>PersistenceManagerFactory</code>.
709      * @param pmfClassLoader the class loader used to load the
710      * <code>PersistenceManagerFactory</code> class
711      * @since 1.0
712      */
713     public static PersistenceManagerFactory getPersistenceManagerFactory
714             (Map props, ClassLoader pmfClassLoader) {
715         return getPersistenceManagerFactory(
716                 null, props, pmfClassLoader);
717     }
718 
719     /***
720      * Get a <code>PersistenceManagerFactory</code> based on a 
721      * <code>Map</code> of overrides, a <code>Map</code> of 
722      * properties, and a class loader.
723      * The following are standard key names:
724      * <BR><code>"javax.jdo.PersistenceManagerFactoryClass"
725      * <BR>"javax.jdo.option.Optimistic",
726      * <BR>"javax.jdo.option.RetainValues",
727      * <BR>"javax.jdo.option.RestoreValues",
728      * <BR>"javax.jdo.option.IgnoreCache",
729      * <BR>"javax.jdo.option.NontransactionalRead",
730      * <BR>"javax.jdo.option.NontransactionalWrite",
731      * <BR>"javax.jdo.option.Multithreaded",
732      * <BR>"javax.jdo.option.ConnectionUserName",
733      * <BR>"javax.jdo.option.ConnectionPassword",
734      * <BR>"javax.jdo.option.ConnectionURL",
735      * <BR>"javax.jdo.option.ConnectionFactoryName",
736      * <BR>"javax.jdo.option.ConnectionFactory2Name",
737      * <BR>"javax.jdo.option.Mapping",
738      * <BR>"javax.jdo.mapping.Catalog",
739      * <BR>"javax.jdo.mapping.Schema",
740      * <BR>"javax.jdo.option.PersistenceUnitName",
741      * <BR>"javax.jdo.option.DetachAllOnCommit",
742      * <BR>"javax.jdo.option.CopyOnAttach",
743      * <BR>"javax.jdo.option.ReadOnly",
744      * <BR>"javax.jdo.option.TransactionIsolationLevel",
745      * <BR>"javax.jdo.option.TransactionType",
746      * <BR>"javax.jdo.option.ServerTimeZoneID",
747      * <BR>"javax.jdo.option.Name".
748      * </code>
749      * and properties of the form
750      * <BR><code>javax.jdo.option.InstanceLifecycleListener.{listenerClass}[=[{pcClasses}]]</code>
751      * where <code>{listenerClass}</code> is the fully qualified name of a
752      * class that implements
753      * {@link javax.jdo.listener.InstanceLifecycleListener}, and
754      * <code>{pcClasses}</code> is an optional comma- or whitespace-delimited
755      * list of persistence-capable classes to be observed; the absence of a
756      * value for a property of this form means that instances of all
757      * persistence-capable classes will be observed by an instance of the given
758      * listener class.
759      * <P>JDO implementations
760      * are permitted to define key values of their own.  Any key values not
761      * recognized by the implementation must be ignored.  Key values that are
762      * recognized but not supported by an implementation must result in a
763      * <code>JDOFatalUserException</code> thrown by the method.
764      * <P>The returned <code>PersistenceManagerFactory</code> is not 
765      * configurable (the <code>set<I>XXX</I></code> methods will throw an 
766      * exception).
767      * <P>JDO implementations might manage a map of instantiated
768      * <code>PersistenceManagerFactory</code> instances based on specified 
769      * property key values, and return a previously instantiated 
770      * <code>PersistenceManagerFactory</code> instance.  In this case, the 
771      * properties of the returned instance must exactly match the requested 
772      * properties.
773      * @return the <code>PersistenceManagerFactory</code>.
774      * @param props a <code>Properties</code> instance with properties of the 
775      * <code>PersistenceManagerFactory</code>.
776      * @param pmfClassLoader the class loader to use to load the
777      * <code>PersistenceManagerFactory</code> class
778      * @throws JDOFatalUserException if
779      * <ul><li>the pmfClassLoader passed is invalid; or 
780      * </li><li>a valid class name cannot be obtained from
781      * either <code>props</code> or system resources 
782      * (an entry in META-INF/services/javax.jdo.PersistenceManagerFactory); or
783      * </li><li>all implementations throw an exception.
784      * </li></ul>
785      * @since 2.1
786      */
787     protected static PersistenceManagerFactory getPersistenceManagerFactory
788             (Map overrides, Map props, ClassLoader pmfClassLoader) {
789         List exceptions = new ArrayList();
790         if (pmfClassLoader == null)
791             throw new JDOFatalUserException (msg.msg (
792                 "EXC_GetPMFNullLoader")); //NOI18N
793 
794 	    // first try to get the class name from the properties object.
795         String pmfClassName = (String) props.get (
796                 PROPERTY_PERSISTENCE_MANAGER_FACTORY_CLASS);
797 
798         if (!isNullOrBlank(pmfClassName)) {
799 	    // a valid name was returned from the properties.
800             return invokeGetPersistenceManagerFactoryOnImplementation(
801                         pmfClassName, overrides, props, pmfClassLoader);
802 
803         } else {
804             /*
805              * If you have a jar file that provides the jdo implementation,
806              * a file naming the implementation goes into the file 
807              * packaged into the jar file, called
808              * META-INF/services/javax.jdo.PersistenceManagerFactory.
809              * The contents of the file is a string that is the PMF class name, 
810              * null or blank. 
811              * For each file in pmfClassLoader named
812              * META-INF/services/javax.jdo.PersistenceManagerFactory,
813              * this method will try to invoke the getPersistenceManagerFactory
814              * method of the implementation class. 
815              * Return the factory if a valid class name is extracted from 
816              * resources and the invocation returns an instance.  
817              * Otherwise add the exception thrown to 
818              * an exception list.
819              */
820             Enumeration urls = null;
821             try {
822                 urls = getResources(pmfClassLoader,
823                         SERVICE_LOOKUP_PMF_RESOURCE_NAME);
824             } catch (Throwable ex) {
825                 exceptions.add(ex);
826             }
827 
828             if (urls != null){
829                 while (urls.hasMoreElements()) {
830 
831                     try {
832                         pmfClassName = getClassNameFromURL(
833                                 (URL) urls.nextElement());
834 
835                         // return the implementation that is valid.
836                         PersistenceManagerFactory pmf = 
837                             invokeGetPersistenceManagerFactoryOnImplementation(
838                                 pmfClassName, overrides, props, pmfClassLoader);
839                         return pmf;
840 
841                     } catch (Throwable ex) {
842 
843                         // remember exceptions from failed pmf invocations
844                         exceptions.add(ex);
845 
846                     }
847                 }
848             }
849         }
850 
851         // no PMF class name in props and no services.  
852 
853         throw new JDOFatalUserException(msg.msg(
854                 "EXC_GetPMFNoPMFClassNamePropertyOrPUNameProperty"),
855                 (Throwable[])
856                     exceptions.toArray(new Throwable[exceptions.size()]));
857     }
858 
859     /*** Get a class name from a URL. The URL is from getResources with 
860      * e.g. META-INF/services/javax.jdo.PersistenceManagerFactory as the
861      * parameter. Parse the file, removing blank lines, comment lines,
862      * and comments.
863      * @param url the URL of the services file
864      * @return the name of the class contained in the file
865      * @throws java.io.IOException
866      * @since 2.1
867      */
868 
869     protected static String getClassNameFromURL (URL url) 
870             throws IOException {
871         InputStream is = openStream(url);
872         BufferedReader reader = new BufferedReader(new InputStreamReader(is));
873         String line = null;
874         try {
875             while ((line = reader.readLine()) != null) {
876                 line = line.trim();
877                 if (line.length() == 0 || line.startsWith("#")) {
878                     continue;
879                 }
880                 // else assume first line of text is the PMF class name
881                 String[] tokens = line.split("//s");
882                 String pmfClassName = tokens[0];
883                 int indexOfComment = pmfClassName.indexOf("#");
884                 if (indexOfComment == -1) {
885                     return pmfClassName;
886                 }
887                 // else pmfClassName has a comment at the end of it -- remove
888                 return pmfClassName.substring(0, indexOfComment);
889             }
890             return null;
891         } finally {
892             try {
893                 reader.close();
894             }
895             catch (IOException x) {
896                 // gulp
897             }
898         }
899     }
900 
901     /***
902      * Returns a named {@link PersistenceManagerFactory} or persistence
903      * unit.
904      *
905      * @since 2.1
906      * @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader)
907      */
908     public static PersistenceManagerFactory getPersistenceManagerFactory
909         (String name) {
910         ClassLoader cl = getContextClassLoader();
911         return getPersistenceManagerFactory(null, name, cl, cl);
912     }
913 
914     /***
915      * Returns a named {@link PersistenceManagerFactory} or persistence
916      * unit.
917      *
918      * @since 1.0
919      * @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader)
920      */
921     public static PersistenceManagerFactory getPersistenceManagerFactory
922         (String name, ClassLoader loader) {
923         
924         return getPersistenceManagerFactory(null, name, loader, loader);
925     }
926 
927     /***
928      * Returns a named {@link PersistenceManagerFactory} or persistence
929      * unit.
930      *
931      * @since 2.0
932      * @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader)
933      */
934     public static PersistenceManagerFactory getPersistenceManagerFactory
935         (String name, ClassLoader resourceLoader, ClassLoader pmfLoader) {
936 
937         return getPersistenceManagerFactory(
938                 null, name, resourceLoader, pmfLoader);
939     }
940 
941     /***
942      * Returns a named {@link PersistenceManagerFactory} or persistence
943      * unit.
944      *
945      * @since 2.1
946      * @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader)
947      */
948     public static PersistenceManagerFactory getPersistenceManagerFactory
949             (Map overrides, String name) {
950 
951         ClassLoader cl = getContextClassLoader();
952         return getPersistenceManagerFactory(overrides, name, cl, cl);
953     }
954 
955     /***
956      * Returns a named {@link PersistenceManagerFactory} or persistence
957      * unit.
958      *
959      * @since 2.1
960      * @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader)
961      */
962     public static PersistenceManagerFactory getPersistenceManagerFactory
963             (Map overrides, String name, ClassLoader resourceLoader) {
964 
965         return getPersistenceManagerFactory(
966                 overrides, name, resourceLoader, resourceLoader);
967     }
968     
969 
970     /***
971      * Returns a {@link PersistenceManagerFactory} configured based
972      * on the properties stored in the resource at
973      * <code>name</code>, or, if not found, returns a
974      * {@link PersistenceManagerFactory} with the given
975      * name or, if not found, returns a
976      * <code>javax.persistence.EntityManagerFactory</code> cast to a
977      * {@link PersistenceManagerFactory}.  If the name given is null or consists
978      * only of whitespace, it is interpreted as
979      * {@link Constants#ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME}.
980      * The following are standard key names:
981      * <BR><code>"javax.jdo.PersistenceManagerFactoryClass"
982      * <BR>"javax.jdo.option.Optimistic",
983      * <BR>"javax.jdo.option.RetainValues",
984      * <BR>"javax.jdo.option.RestoreValues",
985      * <BR>"javax.jdo.option.IgnoreCache",
986      * <BR>"javax.jdo.option.NontransactionalRead",
987      * <BR>"javax.jdo.option.NontransactionalWrite",
988      * <BR>"javax.jdo.option.Multithreaded",
989      * <BR>"javax.jdo.option.ConnectionUserName",
990      * <BR>"javax.jdo.option.ConnectionPassword",
991      * <BR>"javax.jdo.option.ConnectionURL",
992      * <BR>"javax.jdo.option.ConnectionFactoryName",
993      * <BR>"javax.jdo.option.ConnectionFactory2Name",
994      * <BR>"javax.jdo.option.Mapping",
995      * <BR>"javax.jdo.mapping.Catalog",
996      * <BR>"javax.jdo.mapping.Schema",
997      * <BR>"javax.jdo.option.PersistenceUnitName".
998      * <BR>"javax.jdo.option.DetachAllOnCommit".
999      * <BR>"javax.jdo.option.CopyOnAttach".
1000      * <BR>"javax.jdo.option.TransactionType".
1001      * <BR>"javax.jdo.option.ServerTimeZoneID".
1002      * <BR>"javax.jdo.option.Name".
1003      * </code>
1004      * and properties of the form
1005      * <BR><code>javax.jdo.option.InstanceLifecycleListener.{listenerClass}[=[{pcClasses}]]</code>
1006      * where <code>{listenerClass}</code> is the fully qualified name of a
1007      * class that implements
1008      * {@link javax.jdo.listener.InstanceLifecycleListener}, and
1009      * <code>{pcClasses}</code> is an optional comma- or whitespace-delimited
1010      * list of persistence-capable classes to be observed; the absence of a
1011      * value for a property of this form means that instances of all
1012      * persistence-capable classes will be observed by an instance of the given
1013      * listener class.
1014      * <P>JDO implementations
1015      * are permitted to define key values of their own.  Any key values not
1016      * recognized by the implementation must be ignored.  Key values that are
1017      * recognized but not supported by an implementation must result in a
1018      * <code>JDOFatalUserException</code> thrown by the method.
1019      * <P>The returned <code>PersistenceManagerFactory</code> is not 
1020      * configurable (the <code>set<I>XXX</I></code> methods will throw an 
1021      * exception).
1022      * 
1023      * This method loads the properties found at <code>name</code>, if any, via
1024      * <code>resourceLoader</code>, and creates a {@link
1025      * PersistenceManagerFactory} with <code>pmfLoader</code>. Any
1026      * exceptions thrown during resource loading will
1027      * be wrapped in a {@link JDOFatalUserException}.
1028      * If multiple PMFs with the requested name are found, a
1029      * {@link JDOFatalUserException} is thrown.
1030      * @since 2.1
1031      * @param overrides a Map containing properties that override properties
1032      * defined in any resources loaded according to the "name" parameter
1033      * @param name interpreted as the name of the resource containing the PMF
1034      * properties, the name of the PMF, or the persistence unit name, in that
1035      * order; if name is null, blank or whitespace, it is interpreted as
1036      * indicating the anonymous {@link PersistenceManagerFactory}.
1037      * @param resourceLoader the class loader to use to load properties file
1038      * resources; must be non-null if <code>name</code> is non-null or blank
1039      * @param pmfLoader the class loader to use to load the 
1040      * {@link PersistenceManagerFactory} or
1041      * <code>javax.persistence.EntityManagerFactory</code> classes
1042      * @return the {@link PersistenceManagerFactory} with properties in the
1043      * given resource, with the given name, or with the given persitence unit
1044      * name
1045      * @see Constants#ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME
1046      */
1047     public static PersistenceManagerFactory getPersistenceManagerFactory(
1048             Map overrides,
1049             String name,
1050             ClassLoader resourceLoader,
1051             ClassLoader pmfLoader) {
1052         if (pmfLoader == null)
1053             throw new JDOFatalUserException (msg.msg (
1054                 "EXC_GetPMFNullPMFLoader")); //NOI18N
1055         if (resourceLoader == null) {
1056             throw new JDOFatalUserException(msg.msg(
1057                 "EXC_GetPMFNullPropsLoader")); //NOI18N
1058         }
1059 
1060         Map props = null;
1061         // trim spaces from name and ensure non-null
1062         name = (name == null?ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME:name.trim());
1063         if (!ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME.equals(name)) {
1064             props = loadPropertiesFromResource(resourceLoader, name);
1065         }
1066 
1067         if (props != null) {
1068             // add the SPI property to inform the implementation that
1069             // the PMF was configured by the given resource name
1070             // and not via named PMF for proper deserialization
1071             props.put(PROPERTY_SPI_RESOURCE_NAME, name);
1072             props.remove(PROPERTY_NAME);
1073             return getPersistenceManagerFactory(overrides, props, pmfLoader);
1074         }
1075         // props were null; try getting from jdoconfig.xml
1076         props = getPropertiesFromJdoconfig(name, pmfLoader);
1077         if (props != null) {
1078             // inform the impl that the config came from a jdoconfig.xml
1079             // element with the given name
1080             props.put(PROPERTY_NAME, name);
1081             props.remove(PROPERTY_SPI_RESOURCE_NAME);
1082             // we have loaded a Properties, delegate to implementation
1083             return getPersistenceManagerFactory(overrides, props, pmfLoader);
1084         }
1085         // no properties found; last try to see if name is a JPA PU name
1086         if (!ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME.equals(name)) {
1087             props = new Properties();
1088             props.put(PROPERTY_PERSISTENCE_UNIT_NAME, name);
1089             return getPersistenceManagerFactory(overrides, props, pmfLoader);
1090         }
1091         
1092         // no PMF found; give up
1093         throw new JDOFatalUserException (msg.msg (
1094             "EXC_NoPMFConfigurableViaPropertiesOrXML", name)); //NOI18N
1095     }
1096 
1097     /*** Invoke the getPersistenceManagerFactory method on the implementation.
1098      * If the overrides parameter to this method is not null, the static method 
1099      * with Map overrides, Map properties parameters will be invoked.
1100      * If the overrides parameter to this method is null,  the static method 
1101      * with Map properties parameter will be invoked.
1102      * @param pmfClassName the name of the implementation factory class
1103      * @param overrides a Map of overrides
1104      * @param properties a Map of properties
1105      * @param cl the class loader to use to load the implementation class
1106      * @return the PersistenceManagerFactory
1107      */
1108     protected static PersistenceManagerFactory
1109         invokeGetPersistenceManagerFactoryOnImplementation(
1110             String pmfClassName, Map overrides, Map properties, ClassLoader cl) {
1111         if (overrides != null) {
1112             // overrides is not null; use getPersistenceManagerFactory(Map overrides, Map props)
1113             try {
1114                 Class implClass = forName(pmfClassName, true, cl);
1115                 Method m = getMethod(implClass,
1116                         "getPersistenceManagerFactory", //NOI18N
1117                         new Class[]{Map.class, Map.class});
1118                 PersistenceManagerFactory pmf = 
1119                     (PersistenceManagerFactory) invoke(m,
1120                         null, new Object[]{overrides, properties});
1121                 if (pmf == null) {
1122                         throw new JDOFatalInternalException(msg.msg (
1123                             "EXC_GetPMFNullPMF", pmfClassName)); //NOI18N
1124                     }
1125                 return pmf;
1126 
1127             } catch (ClassNotFoundException e) {
1128                 throw new JDOFatalUserException(msg.msg(
1129                         "EXC_GetPMFClassNotFound", pmfClassName), e); //NOI18N
1130             } catch (NoSuchMethodException e) {
1131                 throw new JDOFatalInternalException(msg.msg(
1132                         "EXC_GetPMFNoSuchMethod2", pmfClassName), e); //NOI18N
1133             } catch (NullPointerException e) {
1134                 throw new JDOFatalInternalException (msg.msg(
1135                     "EXC_GetPMFNullPointerException", pmfClassName), e); //NOI18N
1136             } catch (IllegalAccessException e) {
1137                 throw new JDOFatalUserException(msg.msg(
1138                         "EXC_GetPMFIllegalAccess", pmfClassName), e); //NOI18N
1139             } catch (ClassCastException e) {
1140                 throw new JDOFatalInternalException (msg.msg(
1141                     "EXC_GetPMFClassCastException", pmfClassName), e); //NOI18N
1142             } catch (InvocationTargetException ite) {
1143                 Throwable nested = ite.getTargetException();
1144                 if (nested instanceof JDOException) {
1145                     throw (JDOException)nested;
1146                 } else throw new JDOFatalInternalException (msg.msg(
1147                     "EXC_GetPMFUnexpectedException"), ite); //NOI18N
1148             }
1149         } else {
1150             // overrides is null; use getPersistenceManagerFactory(Map props)
1151             try {
1152                 Class implClass = forName(pmfClassName, true, cl);
1153                 Method m = getMethod(implClass,
1154                         "getPersistenceManagerFactory", //NOI18N
1155                         new Class[]{Map.class});
1156                 PersistenceManagerFactory pmf = 
1157                     (PersistenceManagerFactory) invoke(m,
1158                         null, new Object[]{properties});
1159                 if (pmf == null) {
1160                         throw new JDOFatalInternalException(msg.msg (
1161                             "EXC_GetPMFNullPMF", pmfClassName)); //NOI18N
1162                     }
1163                 return pmf;
1164             } catch (ClassNotFoundException e) {
1165                 throw new JDOFatalUserException(msg.msg(
1166                         "EXC_GetPMFClassNotFound", pmfClassName), e); //NOI18N
1167             } catch (NoSuchMethodException e) {
1168                 throw new JDOFatalInternalException(msg.msg(
1169                         "EXC_GetPMFNoSuchMethod", pmfClassName), e); //NOI18N
1170             } catch (NullPointerException e) {
1171                 throw new JDOFatalInternalException (msg.msg(
1172                     "EXC_GetPMFNullPointerException", pmfClassName), e); //NOI18N
1173             } catch (IllegalAccessException e) {
1174                 throw new JDOFatalUserException(msg.msg(
1175                         "EXC_GetPMFIllegalAccess", pmfClassName), e); //NOI18N
1176             } catch (ClassCastException e) {
1177                 throw new JDOFatalInternalException (msg.msg(
1178                     "EXC_GetPMFClassCastException", pmfClassName), e); //NOI18N
1179             } catch (InvocationTargetException ite) {
1180                 Throwable nested = ite.getTargetException();
1181                 if (nested instanceof JDOException) {
1182                     throw (JDOException)nested;
1183                 } else throw new JDOFatalInternalException (msg.msg(
1184                     "EXC_GetPMFUnexpectedException"), ite); //NOI18N
1185             }
1186         }
1187     }
1188 
1189     /*** Load a Properties instance by name from the class loader.
1190      * 
1191      * @param resourceLoader the class loader from which to load the properties
1192      * @param name the name of the resource
1193      * @return a Properties instance or null if no resource is found
1194      */
1195     protected static Map loadPropertiesFromResource(
1196             ClassLoader resourceLoader, String name) {
1197         InputStream in = null;
1198         Properties props = null;
1199         // try to load resources from properties file
1200         try {
1201             in = getResourceAsStream(resourceLoader, name);
1202             if (in != null) {
1203                 // then some kind of resource was found by the given name;
1204                 // assume that it's a properties file
1205                 props = new Properties();
1206                 ((Properties) props).load(in);
1207             }
1208         } catch (IOException ioe) {
1209             throw new JDOFatalUserException(msg.msg(
1210                 "EXC_GetPMFIOExceptionRsrc", name), ioe); //NOI18N
1211         } finally {
1212             if (in != null) {
1213                 try {
1214                     in.close();
1215                 } catch (IOException ioe) {
1216                 }
1217             }
1218         }
1219         return props;
1220     }
1221 
1222     /***
1223      * @see #getNamedPMFProperties(String,ClassLoader,String)
1224      * @since 2.1
1225      */
1226     protected static Map getPropertiesFromJdoconfig(
1227             String name,
1228             ClassLoader resourceLoader) {
1229         return getNamedPMFProperties(
1230             name, resourceLoader, JDOCONFIG_RESOURCE_NAME);
1231     }
1232 
1233     /***
1234      * Find and return the named {@link PersistenceManagerFactory}'s properties,
1235      * or null if not found.
1236      * If multiple named PMF property sets with
1237      * the given name are found (including anonymous ones), throw
1238      * {@link JDOFatalUserException}.
1239      * This method is here only to facilitate testing; the parameter
1240      * "jdoconfigResourceName" in public usage should always have the value
1241      * given in the constant {@link Constants#JDOCONFIG_RESOURCE_NAME}.
1242      *
1243      * @param name The persistence unit name; null is disallowed.
1244      * @param resourceLoader The ClassLoader used to load the standard JDO
1245      * configuration file.
1246      * @param jdoconfigResourceName The name of the configuration file to read.
1247      * In public usage, this should always be the value of
1248      * {@link Constants#JDOCONFIG_RESOURCE_NAME}.
1249      * @return The named <code>PersistenceManagerFactory</code> properties if
1250      * found, null if not.
1251      * @since 2.1
1252      * @throws JDOFatalUserException if multiple named PMF property sets are
1253      * found with the given name, or any other exception is encountered.
1254      */
1255     protected static Map getNamedPMFProperties(
1256             String name,
1257             ClassLoader resourceLoader,
1258             String jdoconfigResourceName) {
1259         // key is PU name, value is Map of PU properties
1260         Map/*<String,Map>*/ propertiesByNameInAllConfigs
1261                 = new HashMap/*<String,Map>*/();
1262         try {
1263             URL firstFoundConfigURL = null;
1264 
1265             // get all JDO configurations
1266             Enumeration resources =
1267                 getResources(resourceLoader, jdoconfigResourceName);
1268 
1269             if (resources.hasMoreElements()) {
1270                 ArrayList processedResources = new ArrayList();
1271 
1272                 // get ready to parse XML
1273                 DocumentBuilderFactory factory = getDocumentBuilderFactory();
1274                 do {
1275                     URL currentConfigURL = (URL) resources.nextElement();
1276                     if (processedResources.contains(currentConfigURL)) {
1277                         continue;
1278                     }
1279                     else {
1280                         processedResources.add(currentConfigURL);
1281                     }
1282                     
1283                     Map/*<String,Map>*/ propertiesByNameInCurrentConfig =
1284                         readNamedPMFProperties(
1285                             currentConfigURL,
1286                             name,
1287                             factory);
1288 
1289                     // try to detect duplicate requested PU
1290                     if (propertiesByNameInCurrentConfig.containsKey(name)) {
1291                         // possible dup -- check for it
1292                         if (firstFoundConfigURL == null) {
1293                             firstFoundConfigURL = currentConfigURL;
1294                         }
1295                         
1296                         if (propertiesByNameInAllConfigs.containsKey(name))
1297                             throw new JDOFatalUserException (msg.msg(
1298                                 "EXC_DuplicateRequestedNamedPMFFoundInDifferentConfigs",
1299                                 "".equals(name)
1300                                         ? "(anonymous)"
1301                                         : name,
1302                                 firstFoundConfigURL.toExternalForm(),
1303                                 currentConfigURL.toExternalForm())); //NOI18N
1304                     }
1305                     // no dups -- add found PUs to all PUs and keep going
1306                     propertiesByNameInAllConfigs
1307                         .putAll(propertiesByNameInCurrentConfig);
1308                 } while (resources.hasMoreElements());
1309             }
1310         }
1311         catch (FactoryConfigurationError e) {
1312             throw new JDOFatalUserException(
1313                 msg.msg("ERR_NoDocumentBuilderFactory"), e);
1314         }
1315         catch (IOException ioe) {
1316             throw new JDOFatalUserException (msg.msg (
1317                 "EXC_GetPMFIOExceptionRsrc", name), ioe); //NOI18N
1318         }
1319 
1320         // done with reading all config resources;
1321         // return what we found, which may very well be null
1322         return (Map) propertiesByNameInAllConfigs.get(name);
1323     }
1324 
1325 
1326     protected static DocumentBuilderFactory getDocumentBuilderFactory() {
1327         DocumentBuilderFactory factory =
1328                 implHelper.getRegisteredDocumentBuilderFactory();
1329         if (factory == null) {
1330             factory = getDefaultDocumentBuilderFactory();
1331         }
1332         return factory;
1333     }
1334     
1335     protected static DocumentBuilderFactory getDefaultDocumentBuilderFactory() {
1336         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
1337         factory.setIgnoringComments(true);
1338         factory.setNamespaceAware(true);
1339         factory.setValidating(false);
1340         factory.setIgnoringElementContentWhitespace(true);
1341         factory.setExpandEntityReferences(true);
1342 
1343         return factory;
1344     }
1345 
1346     protected static ErrorHandler getErrorHandler() {
1347         ErrorHandler handler = implHelper.getRegisteredErrorHandler();
1348         if (handler == null) {
1349             handler = getDefaultErrorHandler();
1350         }
1351         return handler;
1352     }
1353     
1354     protected static ErrorHandler getDefaultErrorHandler() {
1355         return new ErrorHandler() {
1356                 public void error(SAXParseException exception)
1357                         throws SAXException {
1358                     throw exception;
1359                 }
1360 
1361                 public void fatalError(SAXParseException exception)
1362                         throws SAXException {
1363                     throw exception;
1364                 }
1365 
1366                 public void warning(SAXParseException exception)
1367                         throws SAXException {
1368                     // gulp:  ignore warnings
1369                 }
1370             };
1371     }
1372 
1373 
1374     /*** Reads JDO configuration file, creates a Map for each
1375      * persistence-manager-factory, then returns the map.
1376      * @param url URL of a JDO configuration file compliant with
1377      * javax/jdo/jdoconfig.xsd.
1378      * @param requestedPMFName The name of the requested
1379      * persistence unit (allows for fail-fast).
1380      * @param factory The <code>DocumentBuilderFactory</code> to use for XML
1381      * parsing.
1382      * @return a Map<String,Map> holding persistence unit configurations; for
1383      * the anonymous persistence unit, the
1384      * value of the String key is the empty string, "".
1385      */
1386     protected static Map/*<String,Map>*/ readNamedPMFProperties(
1387             URL url,
1388             String requestedPMFName,
1389             DocumentBuilderFactory factory) {
1390         requestedPMFName = requestedPMFName == null
1391             ? ""
1392             : requestedPMFName.trim();
1393 
1394         Map propertiesByName = new HashMap();
1395         InputStream in = null;
1396         try {
1397             DocumentBuilder builder = factory.newDocumentBuilder();
1398             builder.setErrorHandler(getErrorHandler());
1399 
1400             in = openStream(url);
1401             Document doc = builder.parse(in);
1402 
1403             Element root = doc.getDocumentElement();
1404             if (root == null) {
1405                 throw new JDOFatalUserException(
1406                     msg.msg("EXC_InvalidJDOConfigNoRoot", url.toExternalForm())
1407                 );
1408             }
1409 
1410             NodeList pmfs = root.getElementsByTagName(
1411                 ELEMENT_PERSISTENCE_MANAGER_FACTORY);
1412 
1413             for(int i = 0; i < pmfs.getLength(); i++) {
1414                 Node pmfElement = pmfs.item(i);
1415 
1416                 Properties pmfPropertiesFromAttributes
1417                     = readPropertiesFromPMFElementAttributes(pmfElement);
1418 
1419                 Properties pmfPropertiesFromElements
1420                     = readPropertiesFromPMFSubelements(pmfElement, url);
1421 
1422                 // for informative error handling, get name (or names) now
1423                 String pmfNameFromAtts =
1424                     pmfPropertiesFromAttributes.getProperty(PROPERTY_NAME);
1425                 String pmfNameFromElem =
1426                     pmfPropertiesFromElements.getProperty(PROPERTY_NAME);
1427 
1428                 String pmfName = null;
1429                 if (isNullOrBlank(pmfNameFromAtts)) {
1430                     // no PMF name attribute given
1431                     if (!isNullOrBlank(pmfNameFromElem)) {
1432                         // PMF name element was given
1433                         pmfName = pmfNameFromElem;
1434                     }
1435                     else  {
1436                         // PMF name not given at all, means the "anonymous" PMF
1437                         pmfName = ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME;
1438                     }
1439                 }
1440                 else {
1441                     // PMF name given in an attribute
1442                     if (!isNullOrBlank(pmfNameFromElem)) {
1443                         // exception -- PMF name given as both att & elem
1444                         throw new JDOFatalUserException(
1445                             msg.msg(
1446                                 "EXC_DuplicatePMFNamePropertyFoundWithinConfig",
1447                                 pmfNameFromAtts,
1448                                 pmfNameFromElem,
1449                                 url.toExternalForm()));
1450                     }
1451                     pmfName = pmfNameFromAtts;
1452                 }
1453                 pmfName = pmfName == null ? "" : pmfName.trim();
1454 
1455                 // check for duplicate properties among atts & elems
1456                 if (requestedPMFName.equals(pmfName)) {
1457                     Iterator it =
1458                         pmfPropertiesFromAttributes.keySet().iterator();
1459                     while (it.hasNext()) {
1460                         String property = (String) it.next();
1461                         if (pmfPropertiesFromElements.contains(property)) {
1462                             throw new JDOFatalUserException(
1463                                 msg.msg(
1464                                     "EXC_DuplicatePropertyFound",
1465                                     property,
1466                                     pmfName,
1467                                     url.toExternalForm()));
1468                         }
1469                     }
1470                 }
1471                 
1472                 // at this point, we're guaranteed not to have duplicate
1473                 // properties -- merge them
1474                 Properties pmfProps = new Properties();
1475                 pmfProps.putAll(pmfPropertiesFromAttributes);
1476                 pmfProps.putAll(pmfPropertiesFromElements);
1477 
1478                 // check for duplicate requested PMF name
1479                 if (pmfName.equals(requestedPMFName)
1480                     && propertiesByName.containsKey(pmfName)) {
1481 
1482                     throw new JDOFatalUserException(msg.msg(
1483                             "EXC_DuplicateRequestedNamedPMFFoundInSameConfig",
1484                         pmfName,
1485                         url.toExternalForm()));
1486                 }
1487                 propertiesByName.put(pmfName, pmfProps);
1488             }
1489             return propertiesByName;
1490         }
1491         catch (IOException ioe) {
1492             throw new JDOFatalUserException(
1493                 msg.msg("EXC_GetPMFIOExceptionRsrc", url.toString()),
1494                 ioe); //NOI18N
1495         }
1496         catch (ParserConfigurationException e) {
1497             throw new JDOFatalInternalException(
1498                 msg.msg("EXC_ParserConfigException"),
1499                 e);
1500         }
1501         catch (SAXParseException e) {
1502             throw new JDOFatalUserException(
1503                 msg.msg(
1504                     "EXC_SAXParseException",
1505                     url.toExternalForm(),
1506                     new Integer(e.getLineNumber()),
1507                     new Integer(e.getColumnNumber())),
1508                 e);
1509         }
1510         catch (SAXException e) {
1511             throw new JDOFatalUserException(
1512                 msg.msg("EXC_SAXException", url.toExternalForm()),
1513                 e);
1514         }
1515         catch (JDOException e) {
1516             throw e;
1517         }
1518         catch (RuntimeException e) {
1519             throw new JDOFatalUserException(
1520                 msg.msg("EXC_SAXException", url.toExternalForm()),
1521                 e);
1522         }
1523         finally {
1524             if (in != null) {
1525                 try {
1526                     in.close();
1527                 }
1528                 catch (IOException ioe) { /* gulp */ }
1529             }
1530         }
1531     }
1532 
1533     protected static Properties readPropertiesFromPMFElementAttributes(
1534         Node pmfElement) {
1535         Properties p = new Properties();
1536         NamedNodeMap attributes = pmfElement.getAttributes();
1537         if (attributes == null) {
1538             return p;
1539         }
1540 
1541         for(int i = 0; i < attributes.getLength(); i++) {
1542             Node att = attributes.item(i);
1543             String attName = att.getNodeName();
1544             String attValue = att.getNodeValue().trim();
1545 
1546             String jdoPropertyName =
1547                 (String) ATTRIBUTE_PROPERTY_XREF.get(attName);
1548 
1549             p.put(
1550                 jdoPropertyName != null
1551                     ? jdoPropertyName
1552                     : attName,
1553                 attValue);
1554         }
1555 
1556         return p;
1557     }
1558 
1559     protected static Properties readPropertiesFromPMFSubelements(
1560         Node pmfElement, URL url) {
1561         Properties p = new Properties();
1562         NodeList elements = pmfElement.getChildNodes();
1563         if (elements == null) {
1564             return p;
1565         }
1566         for(int i = 0; i < elements.getLength(); i++) {
1567             Node element = elements.item(i);
1568             if (element.getNodeType() != Node.ELEMENT_NODE) {
1569                 continue;
1570             }
1571             
1572             String elementName = element.getNodeName();
1573             NamedNodeMap attributes = element.getAttributes();
1574             if (ELEMENT_PROPERTY.equalsIgnoreCase(elementName)) {
1575                 // <property name="..." value="..."/>
1576 
1577                 // get the "name" attribute's value (required)
1578                 Node nameAtt = attributes.getNamedItem(PROPERTY_ATTRIBUTE_NAME);
1579                 if (nameAtt == null) {
1580                     throw new JDOFatalUserException(
1581                         msg.msg("EXC_PropertyElementHasNoNameAttribute", url));
1582                 }
1583                 String name = nameAtt.getNodeValue().trim();
1584                 if ("".equals(name)) {
1585                     throw new JDOFatalUserException(
1586                         msg.msg(
1587                             "EXC_PropertyElementNameAttributeHasNoValue",
1588                             name,
1589                             url));
1590                 }
1591                 // The next call allows users to use either the
1592                 // <persistence-manager-factory> attribute names or the
1593                 // "javax.jdo" property names in <property> element "name"
1594                 // attributes.  Handy-dandy.
1595                 String jdoPropertyName =
1596                     (String) ATTRIBUTE_PROPERTY_XREF.get(name);
1597                 
1598                 String propertyName = jdoPropertyName != null
1599                         ? jdoPropertyName
1600                         : name;
1601 
1602                 if (p.containsKey(propertyName)) {
1603                     throw new JDOFatalUserException(
1604                         msg.msg(
1605                             "EXC_DuplicatePropertyNameGivenInPropertyElement",
1606                             propertyName,
1607                             url));
1608                 }
1609 
1610                 // get the "value" attribute's value (optional)
1611                 Node valueAtt = attributes.getNamedItem(
1612                     PROPERTY_ATTRIBUTE_VALUE);
1613                 String value = valueAtt == null
1614                     ? null
1615                     : valueAtt.getNodeValue().trim();
1616 
1617                 p.put(propertyName, value);
1618             }
1619             else if (ELEMENT_INSTANCE_LIFECYCLE_LISTENER.equals(elementName)) {
1620                 // <instance-lifecycle-listener listener="..." classes="..."/>
1621 
1622                 // get the "listener" attribute's value
1623                 Node listenerAtt = attributes.getNamedItem(
1624                     INSTANCE_LIFECYCLE_LISTENER_ATTRIBUTE_LISTENER);
1625                 if (listenerAtt == null) {
1626                     throw new JDOFatalUserException(
1627                         msg.msg(
1628                             "EXC_MissingListenerAttribute",
1629                             url));
1630                 }
1631                 String listener = listenerAtt.getNodeValue().trim();
1632                 if ("".equals(listener)) {
1633                     throw new JDOFatalUserException(
1634                         msg.msg(
1635                             "EXC_MissingListenerAttributeValue",
1636                             url));
1637                 }
1638 
1639                 // listener properties are of the form
1640                 // "javax.jdo.option.InstanceLifecycleListener." + listener
1641                 listener =
1642                     PROPERTY_PREFIX_INSTANCE_LIFECYCLE_LISTENER + listener;
1643 
1644                 // get the "classes" attribute's value (optional)
1645                 Node classesAtt = attributes.getNamedItem(
1646                     INSTANCE_LIFECYCLE_LISTENER_ATTRIBUTE_CLASSES);
1647                 String value = classesAtt == null
1648                     ? ""
1649                     : classesAtt.getNodeValue().trim();
1650 
1651                 p.put(listener,  value);
1652             }
1653         }
1654         return p;
1655     }
1656 
1657     protected static boolean isNullOrBlank(String s) {
1658         return s == null || "".equals(s.trim());
1659     }
1660     
1661     /***
1662      * Returns a {@link PersistenceManagerFactory} configured based
1663      * on the properties stored in the file at
1664      * <code>propsFile</code>. This method is equivalent to
1665      * invoking {@link
1666      * #getPersistenceManagerFactory(File,ClassLoader)} with
1667      * <code>Thread.currentThread().getContextClassLoader()</code> as
1668      * the <code>loader</code> argument.
1669      * @since 2.0
1670      * @param propsFile the file containing the Properties
1671      * @return the PersistenceManagerFactory
1672      */
1673     public static PersistenceManagerFactory getPersistenceManagerFactory
1674             (File propsFile) {
1675         return getPersistenceManagerFactory(
1676                 propsFile, getContextClassLoader());
1677     }
1678 
1679     /***
1680      * Returns a {@link PersistenceManagerFactory} configured based
1681      * on the properties stored in the file at
1682      * <code>propsFile</code>. Creates a {@link
1683      * PersistenceManagerFactory} with <code>loader</code>. Any
1684      * <code>IOException</code>s or
1685      * <code>FileNotFoundException</code>s thrown during resource
1686      * loading will be wrapped in a {@link JDOFatalUserException}.
1687      * @since 2.0
1688      * @param propsFile the file containing the Properties
1689      * @param loader the class loader to use to load the 
1690      * <code>PersistenceManagerFactory</code> class
1691      * @return the PersistenceManagerFactory
1692      */
1693     public static PersistenceManagerFactory getPersistenceManagerFactory
1694             (File propsFile, ClassLoader loader) {
1695         if (propsFile == null)
1696             throw new JDOFatalUserException (msg.msg (
1697                 "EXC_GetPMFNullFile")); //NOI18N
1698 
1699         Properties props = new Properties();
1700         InputStream in = null;
1701         try {
1702             in = new FileInputStream(propsFile);
1703             return getPersistenceManagerFactory(in, loader);
1704         } catch (FileNotFoundException fnfe) {
1705             throw new JDOFatalUserException (msg.msg (
1706                 "EXC_GetPMFNoFile", propsFile), fnfe); //NOI18N
1707         } finally {
1708             if (in != null)
1709                 try { 
1710                     in.close (); 
1711                 } catch (IOException ioe) { }
1712         }
1713     }
1714 
1715     /***
1716      * Returns a {@link PersistenceManagerFactory} at the JNDI
1717      * location specified by <code>jndiLocation</code> in the context
1718      * <code>context</code>. If <code>context</code> is
1719      * <code>null</code>, <code>new InitialContext()</code> will be
1720      * used. This method is equivalent to invoking {@link
1721      * #getPersistenceManagerFactory(String,Context,ClassLoader)}
1722      * with <code>Thread.currentThread().getContextClassLoader()</code> as
1723      * the <code>loader</code> argument.
1724      * @since 2.0
1725      * @param jndiLocation the JNDI location containing the 
1726      * PersistenceManagerFactory
1727      * @param context the context in which to find the named
1728      * PersistenceManagerFactory
1729      * @return the PersistenceManagerFactory
1730      */
1731     public static PersistenceManagerFactory getPersistenceManagerFactory
1732             (String jndiLocation, Context context) {
1733         return getPersistenceManagerFactory (jndiLocation, context,
1734             getContextClassLoader());
1735     }
1736 
1737 
1738     /***
1739      * Returns a {@link PersistenceManagerFactory} at the JNDI
1740      * location specified by <code>jndiLocation</code> in the context
1741      * <code>context</code>. If <code>context</code> is
1742      * <code>null</code>, <code>new InitialContext()</code> will be
1743      * used. Creates a {@link PersistenceManagerFactory} with
1744      * <code>loader</code>. Any <code>NamingException</code>s thrown
1745      * will be wrapped in a {@link JDOFatalUserException}.
1746      * @since 2.0
1747      * @param jndiLocation the JNDI location containing the 
1748      * PersistenceManagerFactory
1749      * @param context the context in which to find the named 
1750      * PersistenceManagerFactory
1751      * @param loader the class loader to use to load the 
1752      * <code>PersistenceManagerFactory</code> class
1753      * @return the PersistenceManagerFactory
1754      */
1755     public static PersistenceManagerFactory getPersistenceManagerFactory
1756             (String jndiLocation, Context context, ClassLoader loader) {
1757         if (jndiLocation == null)
1758             throw new JDOFatalUserException (msg.msg (
1759                 "EXC_GetPMFNullJndiLoc")); //NOI18N
1760         if (loader == null)
1761             throw new JDOFatalUserException (msg.msg (
1762                 "EXC_GetPMFNullLoader")); //NOI18N
1763         try {
1764             if (context == null)
1765                 context = new InitialContext ();
1766 
1767             Object o = context.lookup (jndiLocation);
1768             return (PersistenceManagerFactory) PortableRemoteObject.narrow
1769                 (o, PersistenceManagerFactory.class);
1770         } catch (NamingException ne) {
1771             throw new JDOFatalUserException (msg.msg (
1772                 "EXC_GetPMFNamingException", jndiLocation, loader), ne); //NOI18N
1773         }
1774     }
1775     
1776     /***
1777      * Returns a {@link PersistenceManagerFactory} configured based
1778      * on the Properties stored in the input stream at
1779      * <code>stream</code>. This method is equivalent to
1780      * invoking {@link
1781      * #getPersistenceManagerFactory(InputStream,ClassLoader)} with
1782      * <code>Thread.currentThread().getContextClassLoader()</code> as
1783      * the <code>loader</code> argument.
1784      * @since 2.0
1785      * @param stream the stream containing the Properties
1786      * @return the PersistenceManagerFactory
1787      */
1788     public static PersistenceManagerFactory getPersistenceManagerFactory
1789             (InputStream stream) {
1790         return getPersistenceManagerFactory(
1791                 stream, getContextClassLoader());
1792     }
1793 
1794     /***
1795      * Returns a {@link PersistenceManagerFactory} configured based
1796      * on the Properties stored in the input stream at
1797      * <code>stream</code>. Creates a {@link
1798      * PersistenceManagerFactory} with <code>loader</code>. Any
1799      * <code>IOException</code>s thrown during resource
1800      * loading will be wrapped in a {@link JDOFatalUserException}.
1801      * @since 2.0
1802      * @param stream the stream containing the Properties
1803      * @param loader the class loader to use to load the 
1804      * <code>PersistenceManagerFactory</code> class
1805      * @return the PersistenceManagerFactory
1806      */
1807     public static PersistenceManagerFactory getPersistenceManagerFactory
1808             (InputStream stream, ClassLoader loader) {
1809         if (stream == null)
1810             throw new JDOFatalUserException (msg.msg (
1811                 "EXC_GetPMFNullStream")); //NOI18N
1812 
1813         Properties props = new Properties ();
1814         try {
1815             props.load (stream);
1816         } catch (IOException ioe) {
1817             throw new JDOFatalUserException
1818                 (msg.msg ("EXC_GetPMFIOExceptionStream"), ioe); //NOI18N
1819         }
1820         return getPersistenceManagerFactory (props, loader);
1821     }
1822 
1823     /*** Get the context class loader associated with the current thread. 
1824      * This is done in a doPrivileged block because it is a secure method.
1825      * @return the current thread's context class loader.
1826      * @since 2.0
1827      */
1828     private static ClassLoader getContextClassLoader() {
1829         return (ClassLoader)AccessController.doPrivileged(
1830             new PrivilegedAction () {
1831                 public Object run () {
1832                     return Thread.currentThread().getContextClassLoader();
1833                 }
1834             }
1835         );
1836     }
1837 
1838     /*** Get the named resource as a stream from the resource loader.
1839      * Perform this operation in a doPrivileged block.
1840      */
1841     private static InputStream getResourceAsStream(
1842             final ClassLoader resourceLoader, final String name) {
1843         return (InputStream)AccessController.doPrivileged(
1844             new PrivilegedAction() {
1845                 public Object run() {
1846                     return resourceLoader.getResourceAsStream(name);
1847                 }
1848             }
1849         );
1850     }
1851 
1852 
1853     /*** Get the named Method from the named class. 
1854      * Perform this operation in a doPrivileged block.
1855      * 
1856      * @param implClass the class
1857      * @param methodName the name of the method
1858      * @param parameterTypes the parameter types of the method
1859      * @return the Method instance
1860      */
1861     private static Method getMethod(
1862             final Class implClass, 
1863             final String methodName, 
1864             final Class[] parameterTypes) 
1865                 throws NoSuchMethodException {
1866         try {
1867             return (Method) AccessController.doPrivileged(
1868                 new PrivilegedExceptionAction() {
1869                     public Object run() throws NoSuchMethodException {
1870                         return implClass.getMethod(methodName, parameterTypes);
1871                     }
1872                 }
1873             );
1874         } catch (PrivilegedActionException ex) {
1875             throw (NoSuchMethodException)ex.getException();
1876         }
1877     }
1878 
1879     /*** Invoke the method.
1880      * Perform this operation in a doPrivileged block.
1881      */
1882     private static Object invoke(final Method method,
1883             final Object instance, final Object[] parameters) 
1884                 throws IllegalAccessException, InvocationTargetException {
1885         try {
1886             return (Object) AccessController.doPrivileged(
1887                 new PrivilegedExceptionAction() {
1888                     public Object run() 
1889                         throws IllegalAccessException, 
1890                             InvocationTargetException {
1891                         return method.invoke (instance, parameters);
1892                     }
1893                 }
1894             );
1895         } catch (PrivilegedActionException ex) {
1896             Exception cause = (Exception)ex.getException();
1897             if (cause instanceof IllegalAccessException)
1898                 throw (IllegalAccessException)cause;
1899             else //if (cause instanceof InvocationTargetException)
1900                 throw (InvocationTargetException)cause;
1901         }
1902     }
1903 
1904     /*** Get resources of the resource loader. 
1905      * Perform this operation in a doPrivileged block.
1906      * @param resourceLoader
1907      * @param resourceName
1908      * @return the resources
1909      */
1910     protected static Enumeration getResources(
1911             final ClassLoader resourceLoader, 
1912             final String resourceName) 
1913                 throws IOException {
1914         try {
1915             return (Enumeration) AccessController.doPrivileged(
1916                 new PrivilegedExceptionAction() {
1917                     public Object run() throws IOException {
1918                         return resourceLoader.getResources(resourceName);
1919                     }
1920                 }
1921             );
1922         } catch (PrivilegedActionException ex) {
1923             throw (IOException)ex.getException();
1924         }
1925     }
1926 
1927     /*** Get the named class.
1928      * Perform this operation in a doPrivileged block.
1929      * 
1930      * @param name the name of the class
1931      * @param init whether to initialize the class
1932      * @param loader which class loader to use
1933      * @return the class
1934      */
1935     private static Class forName(
1936             final String name, 
1937             final boolean init, 
1938             final ClassLoader loader) 
1939                 throws ClassNotFoundException {
1940         try {
1941             return (Class) AccessController.doPrivileged(
1942                 new PrivilegedExceptionAction() {
1943                     public Object run() throws ClassNotFoundException {
1944                         return Class.forName(name, init, loader);
1945                     }
1946                 }
1947             );
1948         } catch (PrivilegedActionException ex) {
1949             throw (ClassNotFoundException)ex.getException();
1950         }
1951     }
1952 
1953     /*** Open an input stream on the url.
1954      * Perform this operation in a doPrivileged block.
1955      * 
1956      * @param url
1957      * @return the input stream
1958      */
1959     private static InputStream openStream(final URL url) 
1960             throws IOException {
1961         try {
1962             return (InputStream) AccessController.doPrivileged(
1963                 new PrivilegedExceptionAction() {
1964                     public Object run() throws IOException {
1965                         return url.openStream();
1966                     }
1967                 }
1968             );
1969         } catch (PrivilegedActionException ex) {
1970             throw (IOException)ex.getException();
1971         }
1972     }
1973 
1974 }