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.TransactionType".
744      * <BR>"javax.jdo.option.ServerTimeZoneID".
745      * <BR>"javax.jdo.option.Name".
746      * </code>
747      * and properties of the form
748      * <BR><code>javax.jdo.option.InstanceLifecycleListener.{listenerClass}[=[{pcClasses}]]</code>
749      * where <code>{listenerClass}</code> is the fully qualified name of a
750      * class that implements
751      * {@link javax.jdo.listener.InstanceLifecycleListener}, and
752      * <code>{pcClasses}</code> is an optional comma- or whitespace-delimited
753      * list of persistence-capable classes to be observed; the absence of a
754      * value for a property of this form means that instances of all
755      * persistence-capable classes will be observed by an instance of the given
756      * listener class.
757      * <P>JDO implementations
758      * are permitted to define key values of their own.  Any key values not
759      * recognized by the implementation must be ignored.  Key values that are
760      * recognized but not supported by an implementation must result in a
761      * <code>JDOFatalUserException</code> thrown by the method.
762      * <P>The returned <code>PersistenceManagerFactory</code> is not 
763      * configurable (the <code>set<I>XXX</I></code> methods will throw an 
764      * exception).
765      * <P>JDO implementations might manage a map of instantiated
766      * <code>PersistenceManagerFactory</code> instances based on specified 
767      * property key values, and return a previously instantiated 
768      * <code>PersistenceManagerFactory</code> instance.  In this case, the 
769      * properties of the returned instance must exactly match the requested 
770      * properties.
771      * @return the <code>PersistenceManagerFactory</code>.
772      * @param props a <code>Properties</code> instance with properties of the 
773      * <code>PersistenceManagerFactory</code>.
774      * @param pmfClassLoader the class loader to use to load the
775      * <code>PersistenceManagerFactory</code> class
776      * @since 2.1
777      */
778     protected static PersistenceManagerFactory getPersistenceManagerFactory
779             (Map overrides, Map props, ClassLoader pmfClassLoader) {
780         List exceptions = new ArrayList();
781         if (pmfClassLoader == null)
782             throw new JDOFatalUserException (msg.msg (
783                 "EXC_GetPMFNullLoader")); //NOI18N
784 
785         String pmfClassName = (String) props.get (
786                 PROPERTY_PERSISTENCE_MANAGER_FACTORY_CLASS);
787 
788         if (!isNullOrBlank(pmfClassName)) {
789             return invokeGetPersistenceManagerFactoryOnImplementation(
790                         pmfClassName, overrides, props, pmfClassLoader);
791 
792         } else {
793         // PMF class name null or blank -- try services
794         // for each file META-INF/services/javax.jdo.PersistenceManagerFactory
795         // try to invoke the getPersistenceManagerFactory method of the
796         // implementation class
797             try {
798                 Enumeration urls = getResources(pmfClassLoader, 
799                     SERVICE_LOOKUP_PMF_RESOURCE_NAME);
800                 while (urls.hasMoreElements()) {
801                     pmfClassName = getClassNameFromURL((URL)urls.nextElement());
802                         return invokeGetPersistenceManagerFactoryOnImplementation(
803                             pmfClassName, overrides, props, pmfClassLoader);
804                 }
805             } catch (Throwable ex) {
806                 // remember exceptions from failed pmf invocations
807                 exceptions.add(ex);
808             }
809         }
810 
811         // no PMF class name and no services
812         
813         throw new JDOFatalUserException(msg.msg(
814                 "EXC_GetPMFNoPMFClassNamePropertyOrPUNameProperty"),
815                 (Throwable[])
816                     exceptions.toArray(new Throwable[exceptions.size()]));
817     }
818 
819     /*** Get a class name from a URL. The URL is from getResources with 
820      * e.g. META-INF/services/javax.jdo.PersistenceManagerFactory as the
821      * parameter. Parse the file, removing blank lines, comment lines,
822      * and comments.
823      * @param url the URL of the services file
824      * @return the name of the class contained in the file
825      * @throws java.io.IOException
826      * @since 2.1
827      */
828 
829     protected static String getClassNameFromURL (URL url) 
830             throws IOException {
831         InputStream is = openStream(url);
832         BufferedReader reader = new BufferedReader(new InputStreamReader(is));
833         String line = null;
834         try {
835             while ((line = reader.readLine()) != null) {
836                 line = line.trim();
837                 if (line.length() == 0 || line.startsWith("#")) {
838                     continue;
839                 }
840                 // else assume first line of text is the PMF class name
841                 String[] tokens = line.split("//s");
842                 String pmfClassName = tokens[0];
843                 int indexOfComment = pmfClassName.indexOf("#");
844                 if (indexOfComment == -1) {
845                     return pmfClassName;
846                 }
847                 // else pmfClassName has a comment at the end of it -- remove
848                 return pmfClassName.substring(0, indexOfComment);
849             }
850             return null;
851         } finally {
852             try {
853                 reader.close();
854             }
855             catch (IOException x) {
856                 // gulp
857             }
858         }
859     }
860 
861     /***
862      * Returns a named {@link PersistenceManagerFactory} or persistence
863      * unit.
864      *
865      * @since 2.1
866      * @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader)
867      */
868     public static PersistenceManagerFactory getPersistenceManagerFactory
869         (String name) {
870         ClassLoader cl = getContextClassLoader();
871         return getPersistenceManagerFactory(null, name, cl, cl);
872     }
873 
874     /***
875      * Returns a named {@link PersistenceManagerFactory} or persistence
876      * unit.
877      *
878      * @since 1.0
879      * @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader)
880      */
881     public static PersistenceManagerFactory getPersistenceManagerFactory
882         (String name, ClassLoader loader) {
883         
884         return getPersistenceManagerFactory(null, name, loader, loader);
885     }
886 
887     /***
888      * Returns a named {@link PersistenceManagerFactory} or persistence
889      * unit.
890      *
891      * @since 2.0
892      * @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader)
893      */
894     public static PersistenceManagerFactory getPersistenceManagerFactory
895         (String name, ClassLoader resourceLoader, ClassLoader pmfLoader) {
896 
897         return getPersistenceManagerFactory(
898                 null, name, resourceLoader, pmfLoader);
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             (Map overrides, String name) {
910 
911         ClassLoader cl = getContextClassLoader();
912         return getPersistenceManagerFactory(overrides, name, cl, cl);
913     }
914 
915     /***
916      * Returns a named {@link PersistenceManagerFactory} or persistence
917      * unit.
918      *
919      * @since 2.1
920      * @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader)
921      */
922     public static PersistenceManagerFactory getPersistenceManagerFactory
923             (Map overrides, String name, ClassLoader resourceLoader) {
924 
925         return getPersistenceManagerFactory(
926                 overrides, name, resourceLoader, resourceLoader);
927     }
928     
929 
930     /***
931      * Returns a {@link PersistenceManagerFactory} configured based
932      * on the properties stored in the resource at
933      * <code>name</code>, or, if not found, returns a
934      * {@link PersistenceManagerFactory} with the given
935      * name or, if not found, returns a
936      * <code>javax.persistence.EntityManagerFactory</code> cast to a
937      * {@link PersistenceManagerFactory}.  If the name given is null or consists
938      * only of whitespace, it is interpreted as
939      * {@link Constants#ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME}.
940      * The following are standard key names:
941      * <BR><code>"javax.jdo.PersistenceManagerFactoryClass"
942      * <BR>"javax.jdo.option.Optimistic",
943      * <BR>"javax.jdo.option.RetainValues",
944      * <BR>"javax.jdo.option.RestoreValues",
945      * <BR>"javax.jdo.option.IgnoreCache",
946      * <BR>"javax.jdo.option.NontransactionalRead",
947      * <BR>"javax.jdo.option.NontransactionalWrite",
948      * <BR>"javax.jdo.option.Multithreaded",
949      * <BR>"javax.jdo.option.ConnectionUserName",
950      * <BR>"javax.jdo.option.ConnectionPassword",
951      * <BR>"javax.jdo.option.ConnectionURL",
952      * <BR>"javax.jdo.option.ConnectionFactoryName",
953      * <BR>"javax.jdo.option.ConnectionFactory2Name",
954      * <BR>"javax.jdo.option.Mapping",
955      * <BR>"javax.jdo.mapping.Catalog",
956      * <BR>"javax.jdo.mapping.Schema",
957      * <BR>"javax.jdo.option.PersistenceUnitName".
958      * <BR>"javax.jdo.option.DetachAllOnCommit".
959      * <BR>"javax.jdo.option.CopyOnAttach".
960      * <BR>"javax.jdo.option.TransactionType".
961      * <BR>"javax.jdo.option.ServerTimeZoneID".
962      * <BR>"javax.jdo.option.Name".
963      * </code>
964      * and properties of the form
965      * <BR><code>javax.jdo.option.InstanceLifecycleListener.{listenerClass}[=[{pcClasses}]]</code>
966      * where <code>{listenerClass}</code> is the fully qualified name of a
967      * class that implements
968      * {@link javax.jdo.listener.InstanceLifecycleListener}, and
969      * <code>{pcClasses}</code> is an optional comma- or whitespace-delimited
970      * list of persistence-capable classes to be observed; the absence of a
971      * value for a property of this form means that instances of all
972      * persistence-capable classes will be observed by an instance of the given
973      * listener class.
974      * <P>JDO implementations
975      * are permitted to define key values of their own.  Any key values not
976      * recognized by the implementation must be ignored.  Key values that are
977      * recognized but not supported by an implementation must result in a
978      * <code>JDOFatalUserException</code> thrown by the method.
979      * <P>The returned <code>PersistenceManagerFactory</code> is not 
980      * configurable (the <code>set<I>XXX</I></code> methods will throw an 
981      * exception).
982      * 
983      * This method loads the properties found at <code>name</code>, if any, via
984      * <code>resourceLoader</code>, and creates a {@link
985      * PersistenceManagerFactory} with <code>pmfLoader</code>. Any
986      * exceptions thrown during resource loading will
987      * be wrapped in a {@link JDOFatalUserException}.
988      * If multiple PMFs with the requested name are found, a
989      * {@link JDOFatalUserException} is thrown.
990      * @since 2.1
991      * @param overrides a Map containing properties that override properties
992      * defined in any resources loaded according to the "name" parameter
993      * @param name interpreted as the name of the resource containing the PMF
994      * properties, the name of the PMF, or the persistence unit name, in that
995      * order; if name is null, blank or whitespace, it is interpreted as
996      * indicating the anonymous {@link PersistenceManagerFactory}.
997      * @param resourceLoader the class loader to use to load properties file
998      * resources; must be non-null if <code>name</code> is non-null or blank
999      * @param pmfLoader the class loader to use to load the 
1000      * {@link PersistenceManagerFactory} or
1001      * <code>javax.persistence.EntityManagerFactory</code> classes
1002      * @return the {@link PersistenceManagerFactory} with properties in the
1003      * given resource, with the given name, or with the given persitence unit
1004      * name
1005      * @see Constants#ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME
1006      */
1007     public static PersistenceManagerFactory getPersistenceManagerFactory(
1008             Map overrides,
1009             String name,
1010             ClassLoader resourceLoader,
1011             ClassLoader pmfLoader) {
1012         if (pmfLoader == null)
1013             throw new JDOFatalUserException (msg.msg (
1014                 "EXC_GetPMFNullPMFLoader")); //NOI18N
1015         if (resourceLoader == null) {
1016             throw new JDOFatalUserException(msg.msg(
1017                 "EXC_GetPMFNullPropsLoader")); //NOI18N
1018         }
1019 
1020         Map props = null;
1021         // trim spaces from name and ensure non-null
1022         name = (name == null?ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME:name.trim());
1023         if (!ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME.equals(name)) {
1024             props = loadPropertiesFromResource(resourceLoader, name);
1025         }
1026 
1027         if (props != null) {
1028             // add the SPI property to inform the implementation that
1029             // the PMF was configured by the given resource name
1030             // and not via named PMF for proper deserialization
1031             props.put(PROPERTY_SPI_RESOURCE_NAME, name);
1032             props.remove(PROPERTY_NAME);
1033             return getPersistenceManagerFactory(overrides, props, pmfLoader);
1034         }
1035         // props were null; try getting from jdoconfig.xml
1036         props = getPropertiesFromJdoconfig(name, pmfLoader);
1037         if (props != null) {
1038             // inform the impl that the config came from a jdoconfig.xml
1039             // element with the given name
1040             props.put(PROPERTY_NAME, name);
1041             props.remove(PROPERTY_SPI_RESOURCE_NAME);
1042             // we have loaded a Properties, delegate to implementation
1043             return getPersistenceManagerFactory(overrides, props, pmfLoader);
1044         }
1045         // no properties found; last try to see if name is a JPA PU name
1046         if (!ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME.equals(name)) {
1047             props = new Properties();
1048             props.put(PROPERTY_PERSISTENCE_UNIT_NAME, name);
1049             return getPersistenceManagerFactory(overrides, props, pmfLoader);
1050         }
1051         
1052         // no PMF found; give up
1053         throw new JDOFatalUserException (msg.msg (
1054             "EXC_NoPMFConfigurableViaPropertiesOrXML", name)); //NOI18N
1055     }
1056 
1057     /*** Invoke the getPersistenceManagerFactory method on the implementation.
1058      * If the overrides parameter to this method is not null, the static method 
1059      * with Map overrides, Map properties parameters will be invoked.
1060      * If the overrides parameter to this method is null,  the static method 
1061      * with Map properties parameter will be invoked.
1062      * @param pmfClassName the name of the implementation factory class
1063      * @param overrides a Map of overrides
1064      * @param properties a Map of properties
1065      * @param cl the class loader to use to load the implementation class
1066      * @return the PersistenceManagerFactory
1067      */
1068     protected static PersistenceManagerFactory
1069         invokeGetPersistenceManagerFactoryOnImplementation(
1070             String pmfClassName, Map overrides, Map properties, ClassLoader cl) {
1071         if (overrides != null) {
1072             // overrides is not null; use getPersistenceManagerFactory(Map overrides, Map props)
1073             try {
1074                 Class implClass = forName(pmfClassName, true, cl);
1075                 Method m = getMethod(implClass,
1076                         "getPersistenceManagerFactory",
1077                         new Class[]{Map.class, Map.class});
1078                 return (PersistenceManagerFactory) invoke(m,
1079                         null, new Object[]{overrides, properties});
1080 
1081             } catch (ClassNotFoundException e) {
1082                 throw new JDOFatalUserException(msg.msg(
1083                         "EXC_GetPMFClassNotFound", pmfClassName), e);
1084             } catch (NoSuchMethodException e) {
1085                 throw new JDOFatalInternalException(msg.msg(
1086                         "EXC_GetPMFNoSuchMethod2", pmfClassName), e);
1087             } catch (NullPointerException e) {
1088                 throw new JDOFatalInternalException (msg.msg(
1089                     "EXC_GetPMFNullPointerException", pmfClassName), e); //NOI18N
1090             } catch (IllegalAccessException e) {
1091                 throw new JDOFatalUserException(msg.msg(
1092                         "EXC_GetPMFIllegalAccess", pmfClassName), e);
1093             } catch (ClassCastException e) {
1094                 throw new JDOFatalInternalException (msg.msg(
1095                     "EXC_GetPMFClassCastException", pmfClassName), e); //NOI18N
1096             } catch (InvocationTargetException ite) {
1097                 Throwable nested = ite.getTargetException();
1098                 if (nested instanceof JDOException) {
1099                     throw (JDOException)nested;
1100                 } else throw new JDOFatalInternalException (msg.msg(
1101                     "EXC_GetPMFUnexpectedException"), ite); //NOI18N
1102             }
1103         } else {
1104             // overrides is null; use getPersistenceManagerFactory(Map props)
1105             try {
1106                 Class implClass = forName(pmfClassName, true, cl);
1107                 Method m = getMethod(implClass,
1108                         "getPersistenceManagerFactory",
1109                         new Class[]{Map.class});
1110                 return (PersistenceManagerFactory) invoke(m,
1111                         null, new Object[]{properties});
1112             } catch (ClassNotFoundException e) {
1113                 throw new JDOFatalUserException(msg.msg(
1114                         "EXC_GetPMFClassNotFound", pmfClassName), e);
1115             } catch (NoSuchMethodException e) {
1116                 throw new JDOFatalInternalException(msg.msg(
1117                         "EXC_GetPMFNoSuchMethod2", pmfClassName), e);
1118             } catch (NullPointerException e) {
1119                 throw new JDOFatalInternalException (msg.msg(
1120                     "EXC_GetPMFNullPointerException", pmfClassName), e); //NOI18N
1121             } catch (IllegalAccessException e) {
1122                 throw new JDOFatalUserException(msg.msg(
1123                         "EXC_GetPMFIllegalAccess", pmfClassName), e);
1124             } catch (ClassCastException e) {
1125                 throw new JDOFatalInternalException (msg.msg(
1126                     "EXC_GetPMFClassCastException", pmfClassName), e); //NOI18N
1127             } catch (InvocationTargetException ite) {
1128                 Throwable nested = ite.getTargetException();
1129                 if (nested instanceof JDOException) {
1130                     throw (JDOException)nested;
1131                 } else throw new JDOFatalInternalException (msg.msg(
1132                     "EXC_GetPMFUnexpectedException"), ite); //NOI18N
1133             }
1134         }
1135     }
1136 
1137     /*** Load a Properties instance by name from the class loader.
1138      * 
1139      * @param resourceLoader the class loader from which to load the properties
1140      * @param name the name of the resource
1141      * @return a Properties instance or null if no resource is found
1142      */
1143     protected static Map loadPropertiesFromResource(
1144             ClassLoader resourceLoader, String name) {
1145         InputStream in = null;
1146         Properties props = null;
1147         // try to load resources from properties file
1148         try {
1149             in = getResourceAsStream(resourceLoader, name);
1150             if (in != null) {
1151                 // then some kind of resource was found by the given name;
1152                 // assume that it's a properties file
1153                 props = new Properties();
1154                 ((Properties) props).load(in);
1155             }
1156         } catch (IOException ioe) {
1157             throw new JDOFatalUserException(msg.msg(
1158                 "EXC_GetPMFIOExceptionRsrc", name), ioe); //NOI18N
1159         } finally {
1160             if (in != null) {
1161                 try {
1162                     in.close();
1163                 } catch (IOException ioe) {
1164                 }
1165             }
1166         }
1167         return props;
1168     }
1169 
1170     /***
1171      * @see #getNamedPMFProperties(String,ClassLoader,String)
1172      * @since 2.1
1173      */
1174     protected static Map getPropertiesFromJdoconfig(
1175             String name,
1176             ClassLoader resourceLoader) {
1177         return getNamedPMFProperties(
1178             name, resourceLoader, JDOCONFIG_RESOURCE_NAME);
1179     }
1180 
1181     /***
1182      * Find and return the named {@link PersistenceManagerFactory}'s properties,
1183      * or null if not found.
1184      * If multiple named PMF property sets with
1185      * the given name are found (including anonymous ones), throw
1186      * {@link JDOFatalUserException}.
1187      * This method is here only to facilitate testing; the parameter
1188      * "jdoconfigResourceName" in public usage should always have the value
1189      * given in the constant {@link Constants#JDOCONFIG_RESOURCE_NAME}.
1190      *
1191      * @param name The persistence unit name; null is disallowed.
1192      * @param resourceLoader The ClassLoader used to load the standard JDO
1193      * configuration file.
1194      * @param jdoconfigResourceName The name of the configuration file to read.
1195      * In public usage, this should always be the value of
1196      * {@link Constants#JDOCONFIG_RESOURCE_NAME}.
1197      * @return The named <code>PersistenceManagerFactory</code> properties if
1198      * found, null if not.
1199      * @since 2.1
1200      * @throws JDOFatalUserException if multiple named PMF property sets are
1201      * found with the given name, or any other exception is encountered.
1202      */
1203     protected static Map getNamedPMFProperties(
1204             String name,
1205             ClassLoader resourceLoader,
1206             String jdoconfigResourceName) {
1207         // key is PU name, value is Map of PU properties
1208         Map/*<String,Map>*/ propertiesByNameInAllConfigs
1209                 = new HashMap/*<String,Map>*/();
1210         try {
1211             URL firstFoundConfigURL = null;
1212 
1213             // get all JDO configurations
1214             Enumeration resources =
1215                 getResources(resourceLoader, jdoconfigResourceName);
1216 
1217             if (resources.hasMoreElements()) {
1218                 ArrayList processedResources = new ArrayList();
1219 
1220                 // get ready to parse XML
1221                 DocumentBuilderFactory factory = getDocumentBuilderFactory();
1222                 do {
1223                     URL currentConfigURL = (URL) resources.nextElement();
1224                     if (processedResources.contains(currentConfigURL)) {
1225                         continue;
1226                     }
1227                     else {
1228                         processedResources.add(currentConfigURL);
1229                     }
1230                     
1231                     Map/*<String,Map>*/ propertiesByNameInCurrentConfig =
1232                         readNamedPMFProperties(
1233                             currentConfigURL,
1234                             name,
1235                             factory);
1236 
1237                     // try to detect duplicate requested PU
1238                     if (propertiesByNameInCurrentConfig.containsKey(name)) {
1239                         // possible dup -- check for it
1240                         if (firstFoundConfigURL == null) {
1241                             firstFoundConfigURL = currentConfigURL;
1242                         }
1243                         
1244                         if (propertiesByNameInAllConfigs.containsKey(name))
1245                             throw new JDOFatalUserException (msg.msg(
1246                                 "EXC_DuplicateRequestedNamedPMFFoundInDifferentConfigs",
1247                                 "".equals(name)
1248                                         ? "(anonymous)"
1249                                         : name,
1250                                 firstFoundConfigURL.toExternalForm(),
1251                                 currentConfigURL.toExternalForm())); //NOI18N
1252                     }
1253                     // no dups -- add found PUs to all PUs and keep going
1254                     propertiesByNameInAllConfigs
1255                         .putAll(propertiesByNameInCurrentConfig);
1256                 } while (resources.hasMoreElements());
1257             }
1258         }
1259         catch (FactoryConfigurationError e) {
1260             throw new JDOFatalUserException(
1261                 msg.msg("ERR_NoDocumentBuilderFactory"), e);
1262         }
1263         catch (IOException ioe) {
1264             throw new JDOFatalUserException (msg.msg (
1265                 "EXC_GetPMFIOExceptionRsrc", name), ioe); //NOI18N
1266         }
1267 
1268         // done with reading all config resources;
1269         // return what we found, which may very well be null
1270         return (Map) propertiesByNameInAllConfigs.get(name);
1271     }
1272 
1273 
1274     protected static DocumentBuilderFactory getDocumentBuilderFactory() {
1275         DocumentBuilderFactory factory =
1276                 implHelper.getRegisteredDocumentBuilderFactory();
1277         if (factory == null) {
1278             factory = getDefaultDocumentBuilderFactory();
1279         }
1280         return factory;
1281     }
1282     
1283     protected static DocumentBuilderFactory getDefaultDocumentBuilderFactory() {
1284         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
1285         factory.setIgnoringComments(true);
1286         factory.setNamespaceAware(true);
1287         factory.setValidating(false);
1288         factory.setIgnoringElementContentWhitespace(true);
1289         factory.setExpandEntityReferences(true);
1290 
1291         return factory;
1292     }
1293 
1294     protected static ErrorHandler getErrorHandler() {
1295         ErrorHandler handler = implHelper.getRegisteredErrorHandler();
1296         if (handler == null) {
1297             handler = getDefaultErrorHandler();
1298         }
1299         return handler;
1300     }
1301     
1302     protected static ErrorHandler getDefaultErrorHandler() {
1303         return new ErrorHandler() {
1304                 public void error(SAXParseException exception)
1305                         throws SAXException {
1306                     throw exception;
1307                 }
1308 
1309                 public void fatalError(SAXParseException exception)
1310                         throws SAXException {
1311                     throw exception;
1312                 }
1313 
1314                 public void warning(SAXParseException exception)
1315                         throws SAXException {
1316                     // gulp:  ignore warnings
1317                 }
1318             };
1319     }
1320 
1321 
1322     /*** Reads JDO configuration file, creates a Map for each
1323      * persistence-manager-factory, then returns the map.
1324      * @param url URL of a JDO configuration file compliant with
1325      * javax/jdo/jdoconfig.xsd.
1326      * @param requestedPMFName The name of the requested
1327      * persistence unit (allows for fail-fast).
1328      * @param factory The <code>DocumentBuilderFactory</code> to use for XML
1329      * parsing.
1330      * @return a Map<String,Map> holding persistence unit configurations; for
1331      * the anonymous persistence unit, the
1332      * value of the String key is the empty string, "".
1333      */
1334     protected static Map/*<String,Map>*/ readNamedPMFProperties(
1335             URL url,
1336             String requestedPMFName,
1337             DocumentBuilderFactory factory) {
1338         requestedPMFName = requestedPMFName == null
1339             ? ""
1340             : requestedPMFName.trim();
1341 
1342         Map propertiesByName = new HashMap();
1343         InputStream in = null;
1344         try {
1345             DocumentBuilder builder = factory.newDocumentBuilder();
1346             builder.setErrorHandler(getErrorHandler());
1347 
1348             in = openStream(url);
1349             Document doc = builder.parse(in);
1350 
1351             Element root = doc.getDocumentElement();
1352             if (root == null) {
1353                 throw new JDOFatalUserException(
1354                     msg.msg("EXC_InvalidJDOConfigNoRoot", url.toExternalForm())
1355                 );
1356             }
1357 
1358             NodeList pmfs = root.getElementsByTagName(
1359                 ELEMENT_PERSISTENCE_MANAGER_FACTORY);
1360 
1361             for(int i = 0; i < pmfs.getLength(); i++) {
1362                 Node pmfElement = pmfs.item(i);
1363 
1364                 Properties pmfPropertiesFromAttributes
1365                     = readPropertiesFromPMFElementAttributes(pmfElement);
1366 
1367                 Properties pmfPropertiesFromElements
1368                     = readPropertiesFromPMFSubelements(pmfElement, url);
1369 
1370                 // for informative error handling, get name (or names) now
1371                 String pmfNameFromAtts =
1372                     pmfPropertiesFromAttributes.getProperty(PROPERTY_NAME);
1373                 String pmfNameFromElem =
1374                     pmfPropertiesFromElements.getProperty(PROPERTY_NAME);
1375 
1376                 String pmfName = null;
1377                 if (isNullOrBlank(pmfNameFromAtts)) {
1378                     // no PMF name attribute given
1379                     if (!isNullOrBlank(pmfNameFromElem)) {
1380                         // PMF name element was given
1381                         pmfName = pmfNameFromElem;
1382                     }
1383                     else  {
1384                         // PMF name not given at all, means the "anonymous" PMF
1385                         pmfName = ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME;
1386                     }
1387                 }
1388                 else {
1389                     // PMF name given in an attribute
1390                     if (!isNullOrBlank(pmfNameFromElem)) {
1391                         // exception -- PMF name given as both att & elem
1392                         throw new JDOFatalUserException(
1393                             msg.msg(
1394                                 "EXC_DuplicatePMFNamePropertyFoundWithinConfig",
1395                                 pmfNameFromAtts,
1396                                 pmfNameFromElem,
1397                                 url.toExternalForm()));
1398                     }
1399                     pmfName = pmfNameFromAtts;
1400                 }
1401                 pmfName = pmfName == null ? "" : pmfName.trim();
1402 
1403                 // check for duplicate properties among atts & elems
1404                 if (requestedPMFName.equals(pmfName)) {
1405                     Iterator it =
1406                         pmfPropertiesFromAttributes.keySet().iterator();
1407                     while (it.hasNext()) {
1408                         String property = (String) it.next();
1409                         if (pmfPropertiesFromElements.contains(property)) {
1410                             throw new JDOFatalUserException(
1411                                 msg.msg(
1412                                     "EXC_DuplicatePropertyFound",
1413                                     property,
1414                                     pmfName,
1415                                     url.toExternalForm()));
1416                         }
1417                     }
1418                 }
1419                 
1420                 // at this point, we're guaranteed not to have duplicate
1421                 // properties -- merge them
1422                 Properties pmfProps = new Properties();
1423                 pmfProps.putAll(pmfPropertiesFromAttributes);
1424                 pmfProps.putAll(pmfPropertiesFromElements);
1425 
1426                 // check for duplicate requested PMF name
1427                 if (pmfName.equals(requestedPMFName)
1428                     && propertiesByName.containsKey(pmfName)) {
1429 
1430                     throw new JDOFatalUserException(msg.msg(
1431                             "EXC_DuplicateRequestedNamedPMFFoundInSameConfig",
1432                         pmfName,
1433                         url.toExternalForm()));
1434                 }
1435                 propertiesByName.put(pmfName, pmfProps);
1436             }
1437             return propertiesByName;
1438         }
1439         catch (IOException ioe) {
1440             throw new JDOFatalUserException(
1441                 msg.msg("EXC_GetPMFIOExceptionRsrc", url.toString()),
1442                 ioe); //NOI18N
1443         }
1444         catch (ParserConfigurationException e) {
1445             throw new JDOFatalInternalException(
1446                 msg.msg("EXC_ParserConfigException"),
1447                 e);
1448         }
1449         catch (SAXParseException e) {
1450             throw new JDOFatalUserException(
1451                 msg.msg(
1452                     "EXC_SAXParseException",
1453                     url.toExternalForm(),
1454                     new Integer(e.getLineNumber()),
1455                     new Integer(e.getColumnNumber())),
1456                 e);
1457         }
1458         catch (SAXException e) {
1459             throw new JDOFatalUserException(
1460                 msg.msg("EXC_SAXException", url.toExternalForm()),
1461                 e);
1462         }
1463         catch (JDOException e) {
1464             throw e;
1465         }
1466         catch (RuntimeException e) {
1467             throw new JDOFatalUserException(
1468                 msg.msg("EXC_SAXException", url.toExternalForm()),
1469                 e);
1470         }
1471         finally {
1472             if (in != null) {
1473                 try {
1474                     in.close();
1475                 }
1476                 catch (IOException ioe) { /* gulp */ }
1477             }
1478         }
1479     }
1480 
1481     protected static Properties readPropertiesFromPMFElementAttributes(
1482         Node pmfElement) {
1483         Properties p = new Properties();
1484         NamedNodeMap attributes = pmfElement.getAttributes();
1485         if (attributes == null) {
1486             return p;
1487         }
1488 
1489         for(int i = 0; i < attributes.getLength(); i++) {
1490             Node att = attributes.item(i);
1491             String attName = att.getNodeName();
1492             String attValue = att.getNodeValue().trim();
1493 
1494             String jdoPropertyName =
1495                 (String) ATTRIBUTE_PROPERTY_XREF.get(attName);
1496 
1497             p.put(
1498                 jdoPropertyName != null
1499                     ? jdoPropertyName
1500                     : attName,
1501                 attValue);
1502         }
1503 
1504         return p;
1505     }
1506 
1507     protected static Properties readPropertiesFromPMFSubelements(
1508         Node pmfElement, URL url) {
1509         Properties p = new Properties();
1510         NodeList elements = pmfElement.getChildNodes();
1511         if (elements == null) {
1512             return p;
1513         }
1514         for(int i = 0; i < elements.getLength(); i++) {
1515             Node element = elements.item(i);
1516             if (element.getNodeType() != Node.ELEMENT_NODE) {
1517                 continue;
1518             }
1519             
1520             String elementName = element.getNodeName();
1521             NamedNodeMap attributes = element.getAttributes();
1522             if (ELEMENT_PROPERTY.equalsIgnoreCase(elementName)) {
1523                 // <property name="..." value="..."/>
1524 
1525                 // get the "name" attribute's value (required)
1526                 Node nameAtt = attributes.getNamedItem(PROPERTY_ATTRIBUTE_NAME);
1527                 if (nameAtt == null) {
1528                     throw new JDOFatalUserException(
1529                         msg.msg("EXC_PropertyElementHasNoNameAttribute", url));
1530                 }
1531                 String name = nameAtt.getNodeValue().trim();
1532                 if ("".equals(name)) {
1533                     throw new JDOFatalUserException(
1534                         msg.msg(
1535                             "EXC_PropertyElementNameAttributeHasNoValue",
1536                             name,
1537                             url));
1538                 }
1539                 // The next call allows users to use either the
1540                 // <persistence-manager-factory> attribute names or the
1541                 // "javax.jdo" property names in <property> element "name"
1542                 // attributes.  Handy-dandy.
1543                 String jdoPropertyName =
1544                     (String) ATTRIBUTE_PROPERTY_XREF.get(name);
1545                 
1546                 String propertyName = jdoPropertyName != null
1547                         ? jdoPropertyName
1548                         : name;
1549 
1550                 if (p.containsKey(propertyName)) {
1551                     throw new JDOFatalUserException(
1552                         msg.msg(
1553                             "EXC_DuplicatePropertyNameGivenInPropertyElement",
1554                             propertyName,
1555                             url));
1556                 }
1557 
1558                 // get the "value" attribute's value (optional)
1559                 Node valueAtt = attributes.getNamedItem(
1560                     PROPERTY_ATTRIBUTE_VALUE);
1561                 String value = valueAtt == null
1562                     ? null
1563                     : valueAtt.getNodeValue().trim();
1564 
1565                 p.put(propertyName, value);
1566             }
1567             else if (ELEMENT_INSTANCE_LIFECYCLE_LISTENER.equals(elementName)) {
1568                 // <instance-lifecycle-listener listener="..." classes="..."/>
1569 
1570                 // get the "listener" attribute's value
1571                 Node listenerAtt = attributes.getNamedItem(
1572                     INSTANCE_LIFECYCLE_LISTENER_ATTRIBUTE_LISTENER);
1573                 if (listenerAtt == null) {
1574                     throw new JDOFatalUserException(
1575                         msg.msg(
1576                             "EXC_MissingListenerAttribute",
1577                             url));
1578                 }
1579                 String listener = listenerAtt.getNodeValue().trim();
1580                 if ("".equals(listener)) {
1581                     throw new JDOFatalUserException(
1582                         msg.msg(
1583                             "EXC_MissingListenerAttributeValue",
1584                             url));
1585                 }
1586 
1587                 // listener properties are of the form
1588                 // "javax.jdo.option.InstanceLifecycleListener." + listener
1589                 listener =
1590                     PROPERTY_PREFIX_INSTANCE_LIFECYCLE_LISTENER + listener;
1591 
1592                 // get the "classes" attribute's value (optional)
1593                 Node classesAtt = attributes.getNamedItem(
1594                     INSTANCE_LIFECYCLE_LISTENER_ATTRIBUTE_CLASSES);
1595                 String value = classesAtt == null
1596                     ? ""
1597                     : classesAtt.getNodeValue().trim();
1598 
1599                 p.put(listener,  value);
1600             }
1601         }
1602         return p;
1603     }
1604 
1605     protected static boolean isNullOrBlank(String s) {
1606         return s == null || "".equals(s.trim());
1607     }
1608     
1609     /***
1610      * Returns a {@link PersistenceManagerFactory} configured based
1611      * on the properties stored in the file at
1612      * <code>propsFile</code>. This method is equivalent to
1613      * invoking {@link
1614      * #getPersistenceManagerFactory(File,ClassLoader)} with
1615      * <code>Thread.currentThread().getContextClassLoader()</code> as
1616      * the <code>loader</code> argument.
1617      * @since 2.0
1618      * @param propsFile the file containing the Properties
1619      * @return the PersistenceManagerFactory
1620      */
1621     public static PersistenceManagerFactory getPersistenceManagerFactory
1622             (File propsFile) {
1623         return getPersistenceManagerFactory(
1624                 propsFile, getContextClassLoader());
1625     }
1626 
1627     /***
1628      * Returns a {@link PersistenceManagerFactory} configured based
1629      * on the properties stored in the file at
1630      * <code>propsFile</code>. Creates a {@link
1631      * PersistenceManagerFactory} with <code>loader</code>. Any
1632      * <code>IOException</code>s or
1633      * <code>FileNotFoundException</code>s thrown during resource
1634      * loading will be wrapped in a {@link JDOFatalUserException}.
1635      * @since 2.0
1636      * @param propsFile the file containing the Properties
1637      * @param loader the class loader to use to load the 
1638      * <code>PersistenceManagerFactory</code> class
1639      * @return the PersistenceManagerFactory
1640      */
1641     public static PersistenceManagerFactory getPersistenceManagerFactory
1642             (File propsFile, ClassLoader loader) {
1643         if (propsFile == null)
1644             throw new JDOFatalUserException (msg.msg (
1645                 "EXC_GetPMFNullFile")); //NOI18N
1646 
1647         Properties props = new Properties();
1648         InputStream in = null;
1649         try {
1650             in = new FileInputStream(propsFile);
1651             return getPersistenceManagerFactory(in, loader);
1652         } catch (FileNotFoundException fnfe) {
1653             throw new JDOFatalUserException (msg.msg (
1654                 "EXC_GetPMFNoFile", propsFile), fnfe); //NOI18N
1655         } finally {
1656             if (in != null)
1657                 try { 
1658                     in.close (); 
1659                 } catch (IOException ioe) { }
1660         }
1661     }
1662 
1663     /***
1664      * Returns a {@link PersistenceManagerFactory} at the JNDI
1665      * location specified by <code>jndiLocation</code> in the context
1666      * <code>context</code>. If <code>context</code> is
1667      * <code>null</code>, <code>new InitialContext()</code> will be
1668      * used. This method is equivalent to invoking {@link
1669      * #getPersistenceManagerFactory(String,Context,ClassLoader)}
1670      * with <code>Thread.currentThread().getContextClassLoader()</code> as
1671      * the <code>loader</code> argument.
1672      * @since 2.0
1673      * @param jndiLocation the JNDI location containing the 
1674      * PersistenceManagerFactory
1675      * @param context the context in which to find the named
1676      * PersistenceManagerFactory
1677      * @return the PersistenceManagerFactory
1678      */
1679     public static PersistenceManagerFactory getPersistenceManagerFactory
1680             (String jndiLocation, Context context) {
1681         return getPersistenceManagerFactory (jndiLocation, context,
1682             getContextClassLoader());
1683     }
1684 
1685 
1686     /***
1687      * Returns a {@link PersistenceManagerFactory} at the JNDI
1688      * location specified by <code>jndiLocation</code> in the context
1689      * <code>context</code>. If <code>context</code> is
1690      * <code>null</code>, <code>new InitialContext()</code> will be
1691      * used. Creates a {@link PersistenceManagerFactory} with
1692      * <code>loader</code>. Any <code>NamingException</code>s thrown
1693      * will be wrapped in a {@link JDOFatalUserException}.
1694      * @since 2.0
1695      * @param jndiLocation the JNDI location containing the 
1696      * PersistenceManagerFactory
1697      * @param context the context in which to find the named 
1698      * PersistenceManagerFactory
1699      * @param loader the class loader to use to load the 
1700      * <code>PersistenceManagerFactory</code> class
1701      * @return the PersistenceManagerFactory
1702      */
1703     public static PersistenceManagerFactory getPersistenceManagerFactory
1704             (String jndiLocation, Context context, ClassLoader loader) {
1705         if (jndiLocation == null)
1706             throw new JDOFatalUserException (msg.msg (
1707                 "EXC_GetPMFNullJndiLoc")); //NOI18N
1708         if (loader == null)
1709             throw new JDOFatalUserException (msg.msg (
1710                 "EXC_GetPMFNullLoader")); //NOI18N
1711         try {
1712             if (context == null)
1713                 context = new InitialContext ();
1714 
1715             Object o = context.lookup (jndiLocation);
1716             return (PersistenceManagerFactory) PortableRemoteObject.narrow
1717                 (o, PersistenceManagerFactory.class);
1718         } catch (NamingException ne) {
1719             throw new JDOFatalUserException (msg.msg (
1720                 "EXC_GetPMFNamingException", jndiLocation, loader), ne); //NOI18N
1721         }
1722     }
1723     
1724     /***
1725      * Returns a {@link PersistenceManagerFactory} configured based
1726      * on the Properties stored in the input stream at
1727      * <code>stream</code>. This method is equivalent to
1728      * invoking {@link
1729      * #getPersistenceManagerFactory(InputStream,ClassLoader)} with
1730      * <code>Thread.currentThread().getContextClassLoader()</code> as
1731      * the <code>loader</code> argument.
1732      * @since 2.0
1733      * @param stream the stream containing the Properties
1734      * @return the PersistenceManagerFactory
1735      */
1736     public static PersistenceManagerFactory getPersistenceManagerFactory
1737             (InputStream stream) {
1738         return getPersistenceManagerFactory(
1739                 stream, getContextClassLoader());
1740     }
1741 
1742     /***
1743      * Returns a {@link PersistenceManagerFactory} configured based
1744      * on the Properties stored in the input stream at
1745      * <code>stream</code>. Creates a {@link
1746      * PersistenceManagerFactory} with <code>loader</code>. Any
1747      * <code>IOException</code>s thrown during resource
1748      * loading will be wrapped in a {@link JDOFatalUserException}.
1749      * @since 2.0
1750      * @param stream the stream containing the Properties
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             (InputStream stream, ClassLoader loader) {
1757         if (stream == null)
1758             throw new JDOFatalUserException (msg.msg (
1759                 "EXC_GetPMFNullStream")); //NOI18N
1760 
1761         Properties props = new Properties ();
1762         try {
1763             props.load (stream);
1764         } catch (IOException ioe) {
1765             throw new JDOFatalUserException
1766                 (msg.msg ("EXC_GetPMFIOExceptionStream"), ioe); //NOI18N
1767         }
1768         return getPersistenceManagerFactory (props, loader);
1769     }
1770 
1771     /*** Get the context class loader associated with the current thread. 
1772      * This is done in a doPrivileged block because it is a secure method.
1773      * @return the current thread's context class loader.
1774      * @since 2.0
1775      */
1776     private static ClassLoader getContextClassLoader() {
1777         return (ClassLoader)AccessController.doPrivileged(
1778             new PrivilegedAction () {
1779                 public Object run () {
1780                     return Thread.currentThread().getContextClassLoader();
1781                 }
1782             }
1783         );
1784     }
1785 
1786     /*** Get the named resource as a stream from the resource loader.
1787      * Perform this operation in a doPrivileged block.
1788      */
1789     private static InputStream getResourceAsStream(
1790             final ClassLoader resourceLoader, final String name) {
1791         return (InputStream)AccessController.doPrivileged(
1792             new PrivilegedAction() {
1793                 public Object run() {
1794                     return resourceLoader.getResourceAsStream(name);
1795                 }
1796             }
1797         );
1798     }
1799 
1800 
1801     /*** Get the named Method from the named class. 
1802      * Perform this operation in a doPrivileged block.
1803      * 
1804      * @param implClass the class
1805      * @param methodName the name of the method
1806      * @param parameterTypes the parameter types of the method
1807      * @return the Method instance
1808      */
1809     private static Method getMethod(
1810             final Class implClass, 
1811             final String methodName, 
1812             final Class[] parameterTypes) 
1813                 throws NoSuchMethodException {
1814         try {
1815             return (Method) AccessController.doPrivileged(
1816                 new PrivilegedExceptionAction() {
1817                     public Object run() throws NoSuchMethodException {
1818                         return implClass.getMethod(methodName, parameterTypes);
1819                     }
1820                 }
1821             );
1822         } catch (PrivilegedActionException ex) {
1823             throw (NoSuchMethodException)ex.getException();
1824         }
1825     }
1826 
1827     /*** Invoke the method.
1828      * Perform this operation in a doPrivileged block.
1829      */
1830     private static Object invoke(final Method method,
1831             final Object instance, final Object[] parameters) 
1832                 throws IllegalAccessException, InvocationTargetException {
1833         try {
1834             return (Object) AccessController.doPrivileged(
1835                 new PrivilegedExceptionAction() {
1836                     public Object run() 
1837                         throws IllegalAccessException, 
1838                             InvocationTargetException {
1839                         return method.invoke (instance, parameters);
1840                     }
1841                 }
1842             );
1843         } catch (PrivilegedActionException ex) {
1844             Exception cause = (Exception)ex.getException();
1845             if (cause instanceof IllegalAccessException)
1846                 throw (IllegalAccessException)cause;
1847             else //if (cause instanceof InvocationTargetException)
1848                 throw (InvocationTargetException)cause;
1849         }
1850     }
1851 
1852     /*** Get resources of the resource loader. 
1853      * Perform this operation in a doPrivileged block.
1854      * @param resourceLoader
1855      * @param resourceName
1856      * @return the resources
1857      */
1858     protected static Enumeration getResources(
1859             final ClassLoader resourceLoader, 
1860             final String resourceName) 
1861                 throws IOException {
1862         try {
1863             return (Enumeration) AccessController.doPrivileged(
1864                 new PrivilegedExceptionAction() {
1865                     public Object run() throws IOException {
1866                         return resourceLoader.getResources(resourceName);
1867                     }
1868                 }
1869             );
1870         } catch (PrivilegedActionException ex) {
1871             throw (IOException)ex.getException();
1872         }
1873     }
1874 
1875     /*** Get the named class.
1876      * Perform this operation in a doPrivileged block.
1877      * 
1878      * @param name the name of the class
1879      * @param init whether to initialize the class
1880      * @param loader which class loader to use
1881      * @return the class
1882      */
1883     private static Class forName(
1884             final String name, 
1885             final boolean init, 
1886             final ClassLoader loader) 
1887                 throws ClassNotFoundException {
1888         try {
1889             return (Class) AccessController.doPrivileged(
1890                 new PrivilegedExceptionAction() {
1891                     public Object run() throws ClassNotFoundException {
1892                         return Class.forName(name, init, loader);
1893                     }
1894                 }
1895             );
1896         } catch (PrivilegedActionException ex) {
1897             throw (ClassNotFoundException)ex.getException();
1898         }
1899     }
1900 
1901     /*** Open an input stream on the url.
1902      * Perform this operation in a doPrivileged block.
1903      * 
1904      * @param url
1905      * @return the input stream
1906      */
1907     private static InputStream openStream(final URL url) 
1908             throws IOException {
1909         try {
1910             return (InputStream) AccessController.doPrivileged(
1911                 new PrivilegedExceptionAction() {
1912                     public Object run() throws IOException {
1913                         return url.openStream();
1914                     }
1915                 }
1916             );
1917         } catch (PrivilegedActionException ex) {
1918             throw (IOException)ex.getException();
1919         }
1920     }
1921 
1922 }