View Javadoc

1   /*
2    * Copyright 2005 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at 
7    * 
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software 
11   * distributed under the License is distributed on an "AS IS" BASIS, 
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License.
15   */
16  
17  /*
18   * JDOHelper.java
19   *
20   */
21   
22  package javax.jdo;
23  
24  import java.io.File;
25  import java.io.FileInputStream;
26  import java.io.FileNotFoundException;
27  import java.io.InputStream;
28  import java.io.IOException;
29  
30  import java.lang.reflect.Method;
31  import java.lang.reflect.InvocationTargetException;
32  
33  import java.util.ArrayList;
34  import java.util.Collection;
35  import java.util.Iterator;
36  import java.util.Map;
37  import java.util.Properties;
38  
39  import java.security.AccessController;
40  import java.security.PrivilegedAction;
41  
42  import javax.jdo.spi.I18NHelper;
43  import javax.jdo.spi.JDOImplHelper;
44  import javax.jdo.spi.JDOImplHelper.StateInterrogationBooleanReturn;
45  import javax.jdo.spi.JDOImplHelper.StateInterrogationObjectReturn;
46  import javax.jdo.spi.PersistenceCapable;
47  import javax.jdo.spi.StateInterrogation;
48  
49  import javax.naming.Context;
50  import javax.naming.InitialContext;
51  import javax.naming.NamingException;
52  
53  import javax.rmi.PortableRemoteObject;
54  
55  
56  /***
57   * This class can be used by a JDO-aware application to call the JDO behavior
58   * of <code>PersistenceCapable</code> instances without declaring them to be
59   * <code>PersistenceCapable</code>.
60   * <P>It is also used to acquire a <code>PersistenceManagerFactory</code> via 
61   * various methods.
62   * <P>This helper class defines static methods that allow a JDO-aware
63   * application to examine the runtime state of instances.  For example,
64   * an application can discover whether the instance is persistent, 
65   * transactional, dirty, new, deleted, or detached; and to get its associated
66   * <code>PersistenceManager</code> if it has one.
67   * 
68   * @version 2.0
69   */
70  public class JDOHelper extends Object {
71        
72      /*** The Internationalization message helper.
73       */
74      private final static I18NHelper msg = 
75          I18NHelper.getInstance ("javax.jdo.Bundle"); //NOI18N
76  
77      /*** The JDOImplHelper instance used for handling non-binary-compatible
78       *  implementations.
79       */
80      private static JDOImplHelper implHelper = (JDOImplHelper)
81          AccessController.doPrivileged(
82              new PrivilegedAction () {
83                  public Object run () {
84                      return JDOImplHelper.getInstance();
85                  }
86              }
87          );
88  
89     /*** The stateless instance used for handling non-binary-compatible
90      *  implementations of getPersistenceManager.
91      */
92      static StateInterrogationObjectReturn getPersistenceManager =
93          new StateInterrogationObjectReturn() {
94              public Object get(Object pc, StateInterrogation si) {
95                  return si.getPersistenceManager(pc);
96              }
97          };
98  
99     /*** The stateless instance used for handling non-binary-compatible
100     *  implementations of getObjectId.
101     */
102     static StateInterrogationObjectReturn getObjectId =
103         new StateInterrogationObjectReturn() {
104             public Object get(Object pc, StateInterrogation si) {
105                 return si.getObjectId(pc);
106             }
107         };
108 
109    /*** The stateless instance used for handling non-binary-compatible
110     *  implementations of getTransactionalObjectId.
111     */
112     static StateInterrogationObjectReturn getTransactionalObjectId =
113         new StateInterrogationObjectReturn() {
114             public Object get(Object pc, StateInterrogation si) {
115                 return si.getTransactionalObjectId(pc);
116             }
117         };
118 
119    /*** The stateless instance used for handling non-binary-compatible
120     *  implementations of getVersion.
121     */
122     static StateInterrogationObjectReturn getVersion =
123         new StateInterrogationObjectReturn() {
124             public Object get(Object pc, StateInterrogation si) {
125                 return si.getVersion(pc);
126             }
127         };
128 
129    /*** The stateless instance used for handling non-binary-compatible
130     *  implementations of isPersistent.
131     */
132     static StateInterrogationBooleanReturn isPersistent =
133         new StateInterrogationBooleanReturn() {
134             public Boolean is(Object pc, StateInterrogation si) {
135                 return si.isPersistent(pc);
136             }
137         };
138 
139    /*** The stateless instance used for handling non-binary-compatible
140     *  implementations of isTransactional.
141     */
142     static StateInterrogationBooleanReturn isTransactional =
143         new StateInterrogationBooleanReturn() {
144             public Boolean is(Object pc, StateInterrogation si) {
145                 return si.isTransactional(pc);
146             }
147         };
148 
149    /*** The stateless instance used for handling non-binary-compatible
150     *  implementations of isDirty.
151     */
152     static StateInterrogationBooleanReturn isDirty =
153         new StateInterrogationBooleanReturn() {
154             public Boolean is(Object pc, StateInterrogation si) {
155                 return si.isDirty(pc);
156             }
157         };
158 
159    /*** The stateless instance used for handling non-binary-compatible
160     *  implementations of isNew.
161     */
162     static StateInterrogationBooleanReturn isNew =
163         new StateInterrogationBooleanReturn() {
164             public Boolean is(Object pc, StateInterrogation si) {
165                 return si.isNew(pc);
166             }
167         };
168 
169    /*** The stateless instance used for handling non-binary-compatible
170     *  implementations of isDeleted.
171     */
172     static StateInterrogationBooleanReturn isDeleted =
173         new StateInterrogationBooleanReturn() {
174             public Boolean is(Object pc, StateInterrogation si) {
175                 return si.isDeleted(pc);
176             }
177         };
178 
179    /*** The stateless instance used for handling non-binary-compatible
180     *  implementations of isDetached.
181     */
182     static StateInterrogationBooleanReturn isDetached =
183         new StateInterrogationBooleanReturn() {
184             public Boolean is(Object pc, StateInterrogation si) {
185                 return si.isDetached(pc);
186             }
187         };
188 
189     /*** Return the associated <code>PersistenceManager</code> if there is one.
190      * Transactional and persistent instances return the associated
191      * <code>PersistenceManager</code>.  
192      *
193      * <P>Transient non-transactional instances and instances of classes 
194      * that do not implement <code>PersistenceCapable</code> return 
195      * <code>null</code>.
196      * @see PersistenceCapable#jdoGetPersistenceManager()
197      * @param pc the <code>PersistenceCapable</code> instance.
198      * @return the <code>PersistenceManager</code> associated with the parameter
199      * instance.
200      */
201      public static PersistenceManager getPersistenceManager(Object pc) {
202         if (pc instanceof PersistenceCapable) {
203             return ((PersistenceCapable)pc).jdoGetPersistenceManager();
204         } else {
205             return (PersistenceManager)
206                 implHelper.nonBinaryCompatibleGet(pc, getPersistenceManager);
207         }
208       }
209     
210     /*** Explicitly mark the parameter instance and field dirty.
211      * Normally, <code>PersistenceCapable</code> classes are able to detect 
212      * changes made to their fields.  However, if a reference to an array is 
213      * given to a method outside the class, and the array is modified, then the
214      * persistent instance is not aware of the change.  This API allows the
215      * application to notify the instance that a change was made to a field.
216      *
217      * <P>Transient instances and instances of classes 
218      * that do not implement <code>PersistenceCapable</code> ignore this method.
219      * @see PersistenceCapable#jdoMakeDirty(String fieldName)
220      * @param pc the <code>PersistenceCapable</code> instance.
221      * @param fieldName the name of the field to be marked dirty.
222      */
223     public static void makeDirty(Object pc, String fieldName) {
224         if (pc instanceof PersistenceCapable) {
225             ((PersistenceCapable)pc).jdoMakeDirty(fieldName);
226         } else {
227              implHelper.nonBinaryCompatibleMakeDirty(pc, fieldName);
228         }
229     }
230     
231     /*** Return a copy of the JDO identity associated with the parameter 
232      * instance.
233      *
234      * <P>Persistent instances of <code>PersistenceCapable</code> classes have a
235      * JDO identity managed by the <code>PersistenceManager</code>.  This method
236      * returns a copy of the ObjectId that represents the JDO identity.  
237      * 
238      * <P>Transient instances and instances of classes that do not implement 
239      * <code>PersistenceCapable</code> return <code>null</code>.
240      *
241      * <P>The ObjectId may be serialized
242      * and later restored, and used with a <code>PersistenceManager</code> from 
243      * the same JDO implementation to locate a persistent instance with the same
244      * data store identity.
245      *
246      * <P>If the JDO identity is managed by the application, then the ObjectId 
247      * may be used with a <code>PersistenceManager</code> from any JDO 
248      * implementation that supports the <code>PersistenceCapable</code> class.
249      *
250      * <P>If the JDO identity is not managed by the application or the data 
251      * store, then the ObjectId returned is only valid within the current 
252      * transaction.
253      *<P>
254      * @see PersistenceManager#getObjectId(Object pc)
255      * @see PersistenceCapable#jdoGetObjectId()
256      * @see PersistenceManager#getObjectById(Object oid, boolean validate)
257      * @param pc the PersistenceCapable instance.
258      * @return a copy of the ObjectId of the parameter instance as of the 
259      * beginning of the transaction.
260      */
261     public static Object getObjectId(Object pc) {
262       if (pc instanceof PersistenceCapable) {
263           return ((PersistenceCapable)pc).jdoGetObjectId();
264         } else {
265             return implHelper.nonBinaryCompatibleGet(pc, getObjectId);
266         }
267     }
268 
269     /*** Get object ids for a collection of instances. For each instance
270      * in the parameter, the getObjectId method is called. This method
271      * returns one identity instance for each element 
272      * in the parameter. The order of iteration of the returned
273      * Collection exactly matches the order of iteration of the
274      * parameter Collection.
275      * @param pcs the persistence-capable instances
276      * @return the object ids of the parameters
277      * @see #getObjectId(Object pc)
278      * @see #getObjectIds(Object[] pcs)
279      * @since 2.0
280      */
281     public static Collection getObjectIds(Collection pcs) {
282         ArrayList result = new ArrayList();
283         for (Iterator it = pcs.iterator(); it.hasNext();) {
284             result.add(getObjectId(it.next()));
285         }
286         return result;
287     }
288 
289     /*** Get object ids for an array of instances. For each instance
290      * in the parameter, the getObjectId method is called. This method
291      * returns one identity instance for each element 
292      * in the parameter. The order of instances of the returned
293      * array exactly matches the order of instances of the
294      * parameter array.
295      * @param pcs the persistence-capable instances
296      * @return the object ids of the parameters
297      * @see #getObjectId(Object pc)
298      * @see #getObjectIds(Collection pcs)
299      * @since 2.0
300      */
301     public static Object[] getObjectIds(Object[] pcs) {
302         Object[] result = new Object[pcs.length];
303         for (int i = 0; i < pcs.length; ++i) {
304             result[i] = getObjectId(pcs[i]);
305         }
306         return result;
307     }
308 
309     /*** Return a copy of the JDO identity associated with the parameter 
310      * instance.
311      *
312      * @see PersistenceCapable#jdoGetTransactionalObjectId()
313      * @see PersistenceManager#getObjectById(Object oid, boolean validate)
314      * @param pc the <code>PersistenceCapable</code> instance.
315      * @return a copy of the ObjectId of the parameter instance as modified in 
316      * this transaction.
317      */
318     public static Object getTransactionalObjectId(Object pc) {
319       if (pc instanceof PersistenceCapable) {
320           return ((PersistenceCapable)pc).jdoGetTransactionalObjectId();
321         } else {
322             return implHelper.nonBinaryCompatibleGet(
323                 pc, getTransactionalObjectId);
324         }
325     }
326     
327     /***
328      * Return the version of the instance.
329      * @since 2.0
330      * @param pc the instance
331      * @return the version of the instance
332      */
333     public static Object getVersion (Object pc) {
334       if (pc instanceof PersistenceCapable) {
335           return ((PersistenceCapable)pc).jdoGetVersion();
336         } else {
337             return implHelper.nonBinaryCompatibleGet(pc, getVersion);
338         }
339     }
340     /*** Tests whether the parameter instance is dirty.
341      *
342      * Instances that have been modified, deleted, or newly 
343      * made persistent in the current transaction return <code>true</code>.
344      *
345      *<P>Transient instances and instances of classes that do not implement 
346      * <code>PersistenceCapable</code> return <code>false</code>.
347      *<P>
348      * @see javax.jdo.spi.StateManager#makeDirty(PersistenceCapable pc, 
349      * String fieldName)
350      * @see PersistenceCapable#jdoIsDirty()
351      * @param pc the <code>PersistenceCapable</code> instance.
352      * @return <code>true</code> if the parameter instance has been modified in 
353      * the current transaction.
354      */
355     public static boolean isDirty(Object pc) {
356       if (pc instanceof PersistenceCapable) {
357           return ((PersistenceCapable)pc).jdoIsDirty();
358         } else {
359             return implHelper.nonBinaryCompatibleIs(pc, isDirty);
360         }
361     }
362 
363     /*** Tests whether the parameter instance is transactional.
364      *
365      * Instances whose state is associated with the current transaction 
366      * return true. 
367      *
368      *<P>Transient instances and instances of classes that do not implement 
369      * <code>PersistenceCapable</code> return <code>false</code>.
370      * @see PersistenceCapable#jdoIsTransactional()
371      * @param pc the <code>PersistenceCapable</code> instance.
372      * @return <code>true</code> if the parameter instance is transactional.
373      */
374     public static boolean isTransactional(Object pc) {
375       if (pc instanceof PersistenceCapable) {
376           return ((PersistenceCapable)pc).jdoIsTransactional();
377         } else {
378             return implHelper.nonBinaryCompatibleIs(pc, isTransactional);
379         }
380     }
381 
382     /*** Tests whether the parameter instance is persistent.
383      *
384      * Instances that represent persistent objects in the data store 
385      * return <code>true</code>. 
386      *
387      *<P>Transient instances and instances of classes that do not implement 
388      * <code>PersistenceCapable</code> return <code>false</code>.
389      *<P>
390      * @see PersistenceManager#makePersistent(Object pc)
391      * @see PersistenceCapable#jdoIsPersistent()
392      * @param pc the <code>PersistenceCapable</code> instance.
393      * @return <code>true</code> if the parameter instance is persistent.
394      */
395     public static boolean isPersistent(Object pc) {
396       if (pc instanceof PersistenceCapable) {
397           return ((PersistenceCapable)pc).jdoIsPersistent();
398         } else {
399             return implHelper.nonBinaryCompatibleIs(pc, isPersistent);
400         }
401     }
402 
403     /*** Tests whether the parameter instance has been newly made persistent.
404      *
405      * Instances that have been made persistent in the current transaction 
406      * return <code>true</code>.
407      *
408      *<P>Transient instances and instances of classes that do not implement 
409      * <code>PersistenceCapable</code> return <code>false</code>.
410      *<P>
411      * @see PersistenceManager#makePersistent(Object pc)
412      * @see PersistenceCapable#jdoIsNew()
413      * @param pc the <code>PersistenceCapable</code> instance.
414      * @return <code>true</code> if the parameter instance was made persistent
415      * in the current transaction.
416      */
417     public static boolean isNew(Object pc) {
418       if (pc instanceof PersistenceCapable) {
419           return ((PersistenceCapable)pc).jdoIsNew();
420         } else {
421             return implHelper.nonBinaryCompatibleIs(pc, isNew);
422         }
423     }
424 
425     /*** Tests whether the parameter instance has been deleted.
426      *
427      * Instances that have been deleted in the current transaction return 
428      * <code>true</code>.
429      *
430      *<P>Transient instances and instances of classes that do not implement 
431      * <code>PersistenceCapable</code> return <code>false</code>.
432      *<P>
433      * @see PersistenceManager#deletePersistent(Object pc)
434      * @see PersistenceCapable#jdoIsDeleted()
435      * @param pc the <code>PersistenceCapable</code> instance.
436      * @return <code>true</code> if the parameter instance was deleted
437      * in the current transaction.
438      */
439     public static boolean isDeleted(Object pc) {
440       if (pc instanceof PersistenceCapable) {
441           return ((PersistenceCapable)pc).jdoIsDeleted();
442         } else {
443             return implHelper.nonBinaryCompatibleIs(pc, isDeleted);
444         }
445     }
446     
447     /***
448      * Tests whether the parameter instance has been detached.
449      * 
450      * Instances that have been detached return true.
451      * 
452      * <P>Transient instances return false.
453      * <P>
454      * @see PersistenceCapable#jdoIsDetached()
455      * @return <code>true</code> if this instance is detached.
456      * @since 2.0
457      * @param pc the instance
458      */
459     public static boolean isDetached(Object pc) {
460       if (pc instanceof PersistenceCapable) {
461           return ((PersistenceCapable)pc).jdoIsDetached();
462         } else {
463             return implHelper.nonBinaryCompatibleIs(pc, isDetached);
464         }
465     }
466     
467     /*** Get a <code>PersistenceManagerFactory</code> based on a <code>Properties</code> 
468      * instance, using the current thread's context class loader to locate the
469      * <code>PersistenceManagerFactory</code> class.
470      * @return the <code>PersistenceManagerFactory</code>.
471      * @param props a <code>Properties</code> instance with properties of the 
472      * <code>PersistenceManagerFactory</code>.
473      * @see #getPersistenceManagerFactory(Map,ClassLoader)
474      */
475     public static PersistenceManagerFactory getPersistenceManagerFactory
476             (Map props) {
477         ClassLoader cl = getContextClassLoader();
478         return getPersistenceManagerFactory (props, cl);
479     }
480     
481     /***
482      * Get a <code>PersistenceManagerFactory</code> based on a 
483      * <code>Properties</code> instance and a class loader.
484      * The following are standard key values:
485      * <BR><code>"javax.jdo.PersistenceManagerFactoryClass"
486      * <BR>"javax.jdo.option.Optimistic",
487      * <BR>"javax.jdo.option.RetainValues",
488      * <BR>"javax.jdo.option.RestoreValues",
489      * <BR>"javax.jdo.option.IgnoreCache",
490      * <BR>"javax.jdo.option.NontransactionalRead",
491      * <BR>"javax.jdo.option.NontransactionalWrite",
492      * <BR>"javax.jdo.option.Multithreaded",
493      * <BR>"javax.jdo.option.ConnectionUserName",
494      * <BR>"javax.jdo.option.ConnectionPassword",
495      * <BR>"javax.jdo.option.ConnectionURL",
496      * <BR>"javax.jdo.option.ConnectionFactoryName",
497      * <BR>"javax.jdo.option.ConnectionFactory2Name",
498      * <BR>"javax.jdo.option.Mapping",
499      * <BR>"javax.jdo.mapping.Catalog",
500      * <BR>"javax.jdo.mapping.Schema".
501      * </code><P>JDO implementations
502      * are permitted to define key values of their own.  Any key values not
503      * recognized by the implementation must be ignored.  Key values that are
504      * recognized but not supported by an implementation must result in a
505      * <code>JDOFatalUserException</code> thrown by the method.
506      * <P>The returned <code>PersistenceManagerFactory</code> is not 
507      * configurable (the <code>set<I>XXX</I></code> methods will throw an 
508      * exception).
509      * <P>JDO implementations might manage a map of instantiated
510      * <code>PersistenceManagerFactory</code> instances based on specified 
511      * property key values, and return a previously instantiated 
512      * <code>PersistenceManagerFactory</code> instance.  In this case, the 
513      * properties of the returned instance must exactly match the requested 
514      * properties.
515      * @return the <code>PersistenceManagerFactory</code>.
516      * @param props a <code>Properties</code> instance with properties of the 
517      * <code>PersistenceManagerFactory</code>.
518      * @param cl the class loader to use to load the 
519      * <code>PersistenceManagerFactory</code> class
520      */
521     public static PersistenceManagerFactory getPersistenceManagerFactory
522             (Map props, ClassLoader cl) {
523         String pmfClassName = (String) props.get (
524             "javax.jdo.PersistenceManagerFactoryClass"); //NOI18N
525         if (pmfClassName == null) {
526             throw new JDOFatalUserException (msg.msg(
527                 "EXC_GetPMFNoClassNameProperty")); // NOI18N
528         }
529         try {
530             Class pmfClass = cl.loadClass (pmfClassName);
531             Method pmfMethod = pmfClass.getMethod(
532                 "getPersistenceManagerFactory", //NOI18N
533                     new Class[] {Map.class});
534             return (PersistenceManagerFactory) pmfMethod.invoke (
535                 null, new Object[] {props});
536         } catch (ClassNotFoundException cnfe) {
537             throw new JDOFatalUserException (msg.msg(
538                 "EXC_GetPMFClassNotFound", pmfClassName), cnfe); //NOI18N
539         } catch (IllegalAccessException iae) {
540             throw new JDOFatalUserException (msg.msg(
541                 "EXC_GetPMFIllegalAccess", pmfClassName), iae); //NOI18N
542         } catch (NoSuchMethodException nsme) {
543             throw new JDOFatalInternalException (msg.msg(
544                 "EXC_GetPMFNoSuchMethod"), nsme); //NOI18N
545         } catch (InvocationTargetException ite) {
546             Throwable nested = ite.getTargetException();
547             if  (nested instanceof JDOException) {
548                 throw (JDOException)nested;
549             } else throw new JDOFatalInternalException (msg.msg(
550                 "EXC_GetPMFUnexpectedException"), ite); //NOI18N
551         } catch (NullPointerException e) {
552             throw new JDOFatalInternalException (msg.msg(
553                 "EXC_GetPMFNullPointerException", pmfClassName), e); //NOI18N
554         } catch (ClassCastException e) {
555             throw new JDOFatalInternalException (msg.msg(
556                 "EXC_GetPMFClassCastException", pmfClassName), e); //NOI18N
557         } catch (Exception e) {
558             throw new JDOFatalInternalException (msg.msg(
559                 "EXC_GetPMFUnexpectedException"), e); //NOI18N
560         }
561     }
562     
563     /***
564      * Returns a {@link PersistenceManagerFactory} configured based
565      * on the properties stored in the resource at
566      * <code>propsResource</code>. This method is equivalent to
567      * invoking {@link
568      * #getPersistenceManagerFactory(String,ClassLoader)} with
569      * <code>Thread.currentThread().getContextClassLoader()</code> as
570      * the <code>loader</code> argument.
571      * @since 2.0
572      * @param propsResource the resource containing the Properties
573      * @return the PersistenceManagerFactory
574      */
575     public static PersistenceManagerFactory getPersistenceManagerFactory
576         (String propsResource) {
577         return getPersistenceManagerFactory (propsResource,
578             getContextClassLoader());
579     }
580 
581     /***
582      * Returns a {@link PersistenceManagerFactory} configured based
583      * on the properties stored in the resource at
584      * <code>propsResource</code>. Loads the resource via
585      * <code>loader</code>, and creates a {@link
586      * PersistenceManagerFactory} with <code>loader</code>. Any
587      * <code>IOException</code>s thrown during resource loading will
588      * be wrapped in a {@link JDOFatalUserException}.
589      * @since 2.0
590      * @param propsResource the resource containing the Properties
591      * @param loader the class loader to use to load both the propsResource and 
592      * the <code>PersistenceManagerFactory</code> class
593      * @return the PersistenceManagerFactory
594      */
595     public static PersistenceManagerFactory getPersistenceManagerFactory
596         (String propsResource, ClassLoader loader) {
597         return getPersistenceManagerFactory(propsResource, loader, loader);
598     }
599         
600     /***
601      * Returns a {@link PersistenceManagerFactory} configured based
602      * on the properties stored in the resource at
603      * <code>propsResource</code>. Loads the Properties via
604      * <code>propsLoader</code>, and creates a {@link
605      * PersistenceManagerFactory} with <code>pmfLoader</code>. Any
606      * <code>IOException</code>s thrown during resource loading will
607      * be wrapped in a {@link JDOFatalUserException}.
608      * @since 2.0
609      * @param propsResource the resource containing the Properties
610      * @param propsLoader the class loader to use to load the propsResource
611      * @param pmfLoader the class loader to use to load the 
612      * <code>PersistenceManagerFactory</code> class
613      * @return the PersistenceManagerFactory
614      */
615     public static PersistenceManagerFactory getPersistenceManagerFactory
616         (String propsResource, ClassLoader propsLoader, ClassLoader pmfLoader) {
617         
618         if (propsResource == null)
619             throw new JDOFatalUserException (msg.msg (
620                 "EXC_GetPMFNullResource")); //NOI18N
621         if (propsLoader == null)
622             throw new JDOFatalUserException (msg.msg (
623                 "EXC_GetPMFNullPropsLoader")); //NOI18N
624         if (pmfLoader == null)
625             throw new JDOFatalUserException (msg.msg (
626                 "EXC_GetPMFNullPMFLoader")); //NOI18N
627 
628         Properties props = new Properties ();
629         InputStream in = null;
630         try {
631             in = propsLoader.getResourceAsStream (propsResource);
632             if (in == null)
633                 throw new JDOFatalUserException (msg.msg (
634                     "EXC_GetPMFNoResource", propsResource, propsLoader)); //NOI18N
635             props.load (in);
636         } catch (IOException ioe) {
637             throw new JDOFatalUserException (msg.msg (
638                 "EXC_GetPMFIOExceptionRsrc", propsResource), ioe); //NOI18N
639         }
640         finally {
641             if (in != null)
642                 try {
643                     in.close (); 
644                 } catch (IOException ioe) { }
645         }
646 
647         return getPersistenceManagerFactory (props, pmfLoader);
648     }
649 
650 
651     /***
652      * Returns a {@link PersistenceManagerFactory} configured based
653      * on the properties stored in the file at
654      * <code>propsFile</code>. This method is equivalent to
655      * invoking {@link
656      * #getPersistenceManagerFactory(File,ClassLoader)} with
657      * <code>Thread.currentThread().getContextClassLoader()</code> as
658      * the <code>loader</code> argument.
659      * @since 2.0
660      * @param propsFile the file containing the Properties
661      * @return the PersistenceManagerFactory
662      */
663     public static PersistenceManagerFactory getPersistenceManagerFactory
664         (File propsFile) {
665         return getPersistenceManagerFactory (propsFile,
666             getContextClassLoader());
667     }
668 
669     /***
670      * Returns a {@link PersistenceManagerFactory} configured based
671      * on the properties stored in the file at
672      * <code>propsFile</code>. Creates a {@link
673      * PersistenceManagerFactory} with <code>loader</code>. Any
674      * <code>IOException</code>s or
675      * <code>FileNotFoundException</code>s thrown during resource
676      * loading will be wrapped in a {@link JDOFatalUserException}.
677      * @since 2.0
678      * @param propsFile the file containing the Properties
679      * @param loader the class loader to use to load the 
680      * <code>PersistenceManagerFactory</code> class
681      * @return the PersistenceManagerFactory
682      */
683     public static PersistenceManagerFactory getPersistenceManagerFactory
684         (File propsFile, ClassLoader loader) {
685         if (propsFile == null)
686             throw new JDOFatalUserException (msg.msg (
687                 "EXC_GetPMFNullFile")); //NOI18N
688         if (loader == null)
689             throw new JDOFatalUserException (msg.msg (
690                 "EXC_GetPMFNullLoader")); //NOI18N
691         Properties props = new Properties ();
692         InputStream in = null;
693         try {
694             in = new FileInputStream (propsFile);
695             props.load (in);
696         } catch (FileNotFoundException fnfe) {
697             throw new JDOFatalUserException (msg.msg (
698                 "EXC_GetPMFNoFile", propsFile, loader), fnfe); //NOI18N
699         } catch (IOException ioe) {
700             throw new JDOFatalUserException (msg.msg (
701                 "EXC_GetPMFIOExceptionFile", propsFile), ioe); //NOI18N
702         } finally {
703             if (in != null)
704                 try { 
705                     in.close (); 
706                 } catch (IOException ioe) { }
707         }
708         return getPersistenceManagerFactory (props, loader);
709     }
710 
711     /***
712      * Returns a {@link PersistenceManagerFactory} at the JNDI
713      * location specified by <code>jndiLocation</code> in the context
714      * <code>context</code>. If <code>context</code> is
715      * <code>null</code>, <code>new InitialContext()</code> will be
716      * used. This method is equivalent to invoking {@link
717      * #getPersistenceManagerFactory(String,Context,ClassLoader)}
718      * with <code>Thread.currentThread().getContextClassLoader()</code> as
719      * the <code>loader</code> argument.
720      * @since 2.0
721      * @param jndiLocation the JNDI location containing the 
722      * PersistenceManagerFactory
723      * @param context the context in which to find the named
724      * PersistenceManagerFactory
725      * @return the PersistenceManagerFactory
726      */
727     public static PersistenceManagerFactory getPersistenceManagerFactory
728         (String jndiLocation, Context context) {
729         return getPersistenceManagerFactory (jndiLocation, context,
730             getContextClassLoader());
731     }
732 
733 
734     /***
735      * Returns a {@link PersistenceManagerFactory} at the JNDI
736      * location specified by <code>jndiLocation</code> in the context
737      * <code>context</code>. If <code>context</code> is
738      * <code>null</code>, <code>new InitialContext()</code> will be
739      * used. Creates a {@link PersistenceManagerFactory} with
740      * <code>loader</code>. Any <code>NamingException</code>s thrown
741      * will be wrapped in a {@link JDOFatalUserException}.
742      * @since 2.0
743      * @param jndiLocation the JNDI location containing the 
744      * PersistenceManagerFactory
745      * @param context the context in which to find the named 
746      * PersistenceManagerFactory
747      * @param loader the class loader to use to load the 
748      * <code>PersistenceManagerFactory</code> class
749      * @return the PersistenceManagerFactory
750      */
751     public static PersistenceManagerFactory getPersistenceManagerFactory
752         (String jndiLocation, Context context, ClassLoader loader) {
753         if (jndiLocation == null)
754             throw new JDOFatalUserException (msg.msg (
755                 "EXC_GetPMFNullJndiLoc")); //NOI18N
756         if (loader == null)
757             throw new JDOFatalUserException (msg.msg (
758                 "EXC_GetPMFNullLoader")); //NOI18N
759         try {
760             if (context == null)
761                 context = new InitialContext ();
762 
763             Object o = context.lookup (jndiLocation);
764             return (PersistenceManagerFactory) PortableRemoteObject.narrow
765                 (o, PersistenceManagerFactory.class);
766         } catch (NamingException ne) {
767             throw new JDOFatalUserException (msg.msg (
768                 "EXC_GetPMFNamingException", jndiLocation, loader), ne); //NOI18N
769         }
770     }
771     
772     /***
773      * Returns a {@link PersistenceManagerFactory} configured based
774      * on the Properties stored in the input stream at
775      * <code>stream</code>. This method is equivalent to
776      * invoking {@link
777      * #getPersistenceManagerFactory(InputStream,ClassLoader)} with
778      * <code>Thread.currentThread().getContextClassLoader()</code> as
779      * the <code>loader</code> argument.
780      * @since 2.0
781      * @param stream the stream containing the Properties
782      * @return the PersistenceManagerFactory
783      */
784     public static PersistenceManagerFactory getPersistenceManagerFactory
785         (InputStream stream) {
786         return getPersistenceManagerFactory (stream,
787             getContextClassLoader());
788     }
789 
790     /***
791      * Returns a {@link PersistenceManagerFactory} configured based
792      * on the Properties stored in the input stream at
793      * <code>stream</code>. Creates a {@link
794      * PersistenceManagerFactory} with <code>loader</code>. Any
795      * <code>IOException</code>s thrown during resource
796      * loading will be wrapped in a {@link JDOFatalUserException}.
797      * @since 2.0
798      * @param stream the stream containing the Properties
799      * @param loader the class loader to use to load the 
800      * <code>PersistenceManagerFactory</code> class
801      * @return the PersistenceManagerFactory
802      */
803     public static PersistenceManagerFactory getPersistenceManagerFactory
804         (InputStream stream, ClassLoader loader) {
805         if (stream == null)
806             throw new JDOFatalUserException (msg.msg (
807                 "EXC_GetPMFNullStream")); //NOI18N
808         if (loader == null)
809             throw new JDOFatalUserException (msg.msg (
810                 "EXC_GetPMFNullLoader")); //NOI18N
811         Properties props = new Properties ();
812         try {
813             props.load (stream);
814         } catch (IOException ioe) {
815             throw new JDOFatalUserException
816                 (msg.msg ("EXC_GetPMFIOExceptionStream"), ioe); //NOI18N
817         }
818         return getPersistenceManagerFactory (props, loader);
819     }
820 
821     /*** Get the context class loader associated with the current thread. 
822      * This is done in a doPrivileged block because it is a secure method.
823      * @return the current thread's context class loader.
824      * @since 2.0
825      */
826     private static ClassLoader getContextClassLoader() {
827         return (ClassLoader)AccessController.doPrivileged(
828             new PrivilegedAction () {
829                 public Object run () {
830                     return Thread.currentThread().getContextClassLoader();
831                 }
832             }
833         );
834     }
835 }