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  import javax.jdo.spi.StateManager; // for javadoc
49  
50  import javax.naming.Context;
51  import javax.naming.InitialContext;
52  import javax.naming.NamingException;
53  
54  import javax.rmi.PortableRemoteObject;
55  
56  
57  /***
58   * This class can be used by a JDO-aware application to call the JDO behavior
59   * of <code>PersistenceCapable</code> instances without declaring them to be
60   * <code>PersistenceCapable</code>.
61   * <P>It is also used to acquire a <code>PersistenceManagerFactory</code> via 
62   * various methods.
63   * <P>This helper class defines static methods that allow a JDO-aware
64   * application to examine the runtime state of instances.  For example,
65   * an application can discover whether the instance is persistent, transactional,
66   * dirty, new, deleted, or detached; and to get its associated
67   * <code>PersistenceManager</code> if it has one.
68   * 
69   * @version 2.0
70   */
71  public class JDOHelper extends Object {
72        
73      /*** The Internationalization message helper.
74       */
75      private final static I18NHelper msg = 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 <code>null</code>.
195      * @see PersistenceCapable#jdoGetPersistenceManager()
196      * @param pc the <code>PersistenceCapable</code> instance.
197      * @return the <code>PersistenceManager</code> associated with the parameter instance.
198      */
199      public static PersistenceManager getPersistenceManager(Object pc) {
200         if (pc instanceof PersistenceCapable) {
201             return ((PersistenceCapable)pc).jdoGetPersistenceManager();
202         } else {
203             return (PersistenceManager)
204                 implHelper.nonBinaryCompatibleGet(pc, getPersistenceManager);
205         }
206       }
207     
208     /*** Explicitly mark the parameter instance and field dirty.
209      * Normally, <code>PersistenceCapable</code> classes are able to detect changes made
210      * to their fields.  However, if a reference to an array is given to a
211      * method outside the class, and the array is modified, then the
212      * persistent instance is not aware of the change.  This API allows the
213      * application to notify the instance that a change was made to a field.
214      *
215      * <P>Transient instances and instances of classes 
216      * that do not implement <code>PersistenceCapable</code> ignore this method.
217      * @see PersistenceCapable#jdoMakeDirty(String fieldName)
218      * @param pc the <code>PersistenceCapable</code> instance.
219      * @param fieldName the name of the field to be marked dirty.
220      */
221     public static void makeDirty(Object pc, String fieldName) {
222         if (pc instanceof PersistenceCapable) {
223             ((PersistenceCapable)pc).jdoMakeDirty(fieldName);
224         } else {
225              implHelper.nonBinaryCompatibleMakeDirty(pc, fieldName);
226         }
227     }
228     
229     /*** Return a copy of the JDO identity associated with the parameter instance.
230      *
231      * <P>Persistent instances of <code>PersistenceCapable</code> classes have a JDO identity
232      * managed by the <code>PersistenceManager</code>.  This method returns a copy of the
233      * ObjectId that represents the JDO identity.  
234      * 
235      * <P>Transient instances and instances of classes 
236      * that do not implement <code>PersistenceCapable</code> return <code>null</code>.
237      *
238      * <P>The ObjectId may be serialized
239      * and later restored, and used with a <code>PersistenceManager</code> from the same JDO
240      * implementation to locate a persistent instance with the same data store
241      * identity.
242      *
243      * <P>If the JDO identity is managed by the application, then the ObjectId may
244      * be used with a <code>PersistenceManager</code> from any JDO implementation that supports
245      * the <code>PersistenceCapable</code> class.
246      *
247      * <P>If the JDO identity is not managed by the application or the data store,
248      * then the ObjectId returned is only valid within the current transaction.
249      *<P>
250      * @see PersistenceManager#getObjectId(Object pc)
251      * @see PersistenceCapable#jdoGetObjectId()
252      * @see PersistenceManager#getObjectById(Object oid, boolean validate)
253      * @param pc the PersistenceCapable instance.
254      * @return a copy of the ObjectId of the parameter instance as of the beginning of the transaction.
255      */
256     public static Object getObjectId(Object pc) {
257       if (pc instanceof PersistenceCapable) {
258           return ((PersistenceCapable)pc).jdoGetObjectId();
259         } else {
260             return implHelper.nonBinaryCompatibleGet(pc, getObjectId);
261         }
262     }
263 
264     /*** Get object ids for a collection of instances. For each instance
265      * in the parameter, the getObjectId method is called. This method
266      * returns one identity instance for each element 
267      * in the parameter. The order of iteration of the returned
268      * Collection exactly matches the order of iteration of the
269      * parameter Collection.
270      * @param pcs the persistence-capable instances
271      * @return the object ids of the parameters
272      * @see #getObjectId(Object pc)
273      * @see #getObjectIds(Object[] pcs)
274      * @since 2.0
275      */
276     public static Collection getObjectIds(Collection pcs) {
277         ArrayList result = new ArrayList();
278         for (Iterator it = pcs.iterator(); it.hasNext();) {
279             result.add(getObjectId(it.next()));
280         }
281         return result;
282     }
283 
284     /*** Get object ids for an array of instances. For each instance
285      * in the parameter, the getObjectId method is called. This method
286      * returns one identity instance for each element 
287      * in the parameter. The order of instances of the returned
288      * array exactly matches the order of instances of the
289      * parameter array.
290      * @param pcs the persistence-capable instances
291      * @return the object ids of the parameters
292      * @see #getObjectId(Object pc)
293      * @see #getObjectIds(Collection pcs)
294      * @since 2.0
295      */
296     public static Object[] getObjectIds(Object[] pcs) {
297         Object[] result = new Object[pcs.length];
298         for (int i = 0; i < pcs.length; ++i) {
299             result[i] = getObjectId(pcs[i]);
300         }
301         return result;
302     }
303 
304     /*** Return a copy of the JDO identity associated with the parameter instance.
305      *
306      * @see PersistenceCapable#jdoGetTransactionalObjectId()
307      * @see PersistenceManager#getObjectById(Object oid, boolean validate)
308      * @param pc the <code>PersistenceCapable</code> instance.
309      * @return a copy of the ObjectId of the parameter instance as modified in this transaction.
310      */
311     public static Object getTransactionalObjectId(Object pc) {
312       if (pc instanceof PersistenceCapable) {
313           return ((PersistenceCapable)pc).jdoGetTransactionalObjectId();
314         } else {
315             return implHelper.nonBinaryCompatibleGet(pc, getTransactionalObjectId);
316         }
317     }
318     
319     /***
320      * Return the version of the instance.
321      * @since 2.0
322      * @param pc the instance
323      * @return the version of the instance
324      */
325     public static Object getVersion (Object pc) {
326       if (pc instanceof PersistenceCapable) {
327           return ((PersistenceCapable)pc).jdoGetVersion();
328         } else {
329             return implHelper.nonBinaryCompatibleGet(pc, getVersion);
330         }
331     }
332     /*** Tests whether the parameter instance is dirty.
333      *
334      * Instances that have been modified, deleted, or newly 
335      * made persistent in the current transaction return <code>true</code>.
336      *
337      *<P>Transient instances and instances of classes 
338      * that do not implement <code>PersistenceCapable</code> return <code>false</code>.
339      *<P>
340      * @see StateManager#makeDirty(PersistenceCapable pc, String fieldName)
341      * @see PersistenceCapable#jdoIsDirty()
342      * @param pc the <code>PersistenceCapable</code> instance.
343      * @return <code>true</code> if the parameter instance has been modified in the current transaction.
344      */
345     public static boolean isDirty(Object pc) {
346       if (pc instanceof PersistenceCapable) {
347           return ((PersistenceCapable)pc).jdoIsDirty();
348         } else {
349             return implHelper.nonBinaryCompatibleIs(pc, isDirty);
350         }
351     }
352 
353     /*** Tests whether the parameter instance is transactional.
354      *
355      * Instances whose state is associated with the current transaction 
356      * return true. 
357      *
358      *<P>Transient instances and instances of classes 
359      * that do not implement <code>PersistenceCapable</code> return <code>false</code>.
360      * @see PersistenceCapable#jdoIsTransactional()
361      * @param pc the <code>PersistenceCapable</code> instance.
362      * @return <code>true</code> if the parameter instance is transactional.
363      */
364     public static boolean isTransactional(Object pc) {
365       if (pc instanceof PersistenceCapable) {
366           return ((PersistenceCapable)pc).jdoIsTransactional();
367         } else {
368             return implHelper.nonBinaryCompatibleIs(pc, isTransactional);
369         }
370     }
371 
372     /*** Tests whether the parameter instance is persistent.
373      *
374      * Instances that represent persistent objects in the data store 
375      * return <code>true</code>. 
376      *
377      *<P>Transient instances and instances of classes 
378      * that do not implement <code>PersistenceCapable</code> return <code>false</code>.
379      *<P>
380      * @see PersistenceManager#makePersistent(Object pc)
381      * @see PersistenceCapable#jdoIsPersistent()
382      * @param pc the <code>PersistenceCapable</code> instance.
383      * @return <code>true</code> if the parameter instance is persistent.
384      */
385     public static boolean isPersistent(Object pc) {
386       if (pc instanceof PersistenceCapable) {
387           return ((PersistenceCapable)pc).jdoIsPersistent();
388         } else {
389             return implHelper.nonBinaryCompatibleIs(pc, isPersistent);
390         }
391     }
392 
393     /*** Tests whether the parameter instance has been newly made persistent.
394      *
395      * Instances that have been made persistent in the current transaction 
396      * return <code>true</code>.
397      *
398      *<P>Transient instances and instances of classes 
399      * that do not implement <code>PersistenceCapable</code> return <code>false</code>.
400      *<P>
401      * @see PersistenceManager#makePersistent(Object pc)
402      * @see PersistenceCapable#jdoIsNew()
403      * @param pc the <code>PersistenceCapable</code> instance.
404      * @return <code>true</code> if the parameter instance was made persistent
405      * in the current transaction.
406      */
407     public static boolean isNew(Object pc) {
408       if (pc instanceof PersistenceCapable) {
409           return ((PersistenceCapable)pc).jdoIsNew();
410         } else {
411             return implHelper.nonBinaryCompatibleIs(pc, isNew);
412         }
413     }
414 
415     /*** Tests whether the parameter instance has been deleted.
416      *
417      * Instances that have been deleted in the current transaction return <code>true</code>.
418      *
419      *<P>Transient instances and instances of classes 
420      * that do not implement <code>PersistenceCapable</code> return <code>false</code>.
421      *<P>
422      * @see PersistenceManager#deletePersistent(Object pc)
423      * @see PersistenceCapable#jdoIsDeleted()
424      * @param pc the <code>PersistenceCapable</code> instance.
425      * @return <code>true</code> if the parameter instance was deleted
426      * in the current transaction.
427      */
428     public static boolean isDeleted(Object pc) {
429       if (pc instanceof PersistenceCapable) {
430           return ((PersistenceCapable)pc).jdoIsDeleted();
431         } else {
432             return implHelper.nonBinaryCompatibleIs(pc, isDeleted);
433         }
434     }
435     
436     /***
437      * Tests whether the parameter instance has been detached.
438      * 
439      * Instances that have been detached return true.
440      * 
441      * <P>Transient instances return false.
442      * <P>
443      * @see PersistenceCapable#jdoIsDetached()
444      * @return <code>true</code> if this instance is detached.
445      * @since 2.0
446      * @param pc the instance
447      */
448     public static boolean isDetached(Object pc) {
449       if (pc instanceof PersistenceCapable) {
450           return ((PersistenceCapable)pc).jdoIsDetached();
451         } else {
452             return implHelper.nonBinaryCompatibleIs(pc, isDetached);
453         }
454     }
455     
456     /*** Get a <code>PersistenceManagerFactory</code> based on a <code>Properties</code> instance, using
457      * the current thread's context class loader to locate the
458      * <code>PersistenceManagerFactory</code> class.
459      * @return the <code>PersistenceManagerFactory</code>.
460      * @param props a <code>Properties</code> instance with properties of the <code>PersistenceManagerFactory</code>.
461      * @see #getPersistenceManagerFactory(Map,ClassLoader)
462      */
463     public static PersistenceManagerFactory getPersistenceManagerFactory
464             (Map props) {
465         ClassLoader cl = getContextClassLoader();
466         return getPersistenceManagerFactory (props, cl);
467     }
468     
469     /***
470      * Get a <code>PersistenceManagerFactory</code> based on a <code>Properties</code>
471      * instance and a class loader.
472      * The following are standard key values:
473      * <BR><code>"javax.jdo.PersistenceManagerFactoryClass"
474      * <BR>"javax.jdo.option.Optimistic",
475      * <BR>"javax.jdo.option.RetainValues",
476      * <BR>"javax.jdo.option.RestoreValues",
477      * <BR>"javax.jdo.option.IgnoreCache",
478      * <BR>"javax.jdo.option.NontransactionalRead",
479      * <BR>"javax.jdo.option.NontransactionalWrite",
480      * <BR>"javax.jdo.option.Multithreaded",
481      * <BR>"javax.jdo.option.ConnectionUserName",
482      * <BR>"javax.jdo.option.ConnectionPassword",
483      * <BR>"javax.jdo.option.ConnectionURL",
484      * <BR>"javax.jdo.option.ConnectionFactoryName",
485      * <BR>"javax.jdo.option.ConnectionFactory2Name",
486      * <BR>"javax.jdo.option.Mapping",
487      * <BR>"javax.jdo.mapping.Catalog",
488      * <BR>"javax.jdo.mapping.Schema".
489      * </code><P>JDO implementations
490      * are permitted to define key values of their own.  Any key values not
491      * recognized by the implementation must be ignored.  Key values that are
492      * recognized but not supported by an implementation must result in a
493      * <code>JDOFatalUserException</code> thrown by the method.
494      * <P>The returned <code>PersistenceManagerFactory</code> is not configurable (the
495      * <code>set<I>XXX</I></code> methods will throw an exception).
496      * <P>JDO implementations might manage a map of instantiated
497      * <code>PersistenceManagerFactory</code> instances based on specified property key
498      * values, and return a previously instantiated <code>PersistenceManagerFactory</code>
499      * instance.  In this case, the properties of the returned
500      * instance must exactly match the requested properties.
501      * @return the <code>PersistenceManagerFactory</code>.
502      * @param props a <code>Properties</code> instance with properties of the <code>PersistenceManagerFactory</code>.
503      * @param cl the class loader to use to load the <code>PersistenceManagerFactory</code> class
504      */
505     public static PersistenceManagerFactory getPersistenceManagerFactory
506             (Map props, ClassLoader cl) {
507         String pmfClassName = (String) props.get ("javax.jdo.PersistenceManagerFactoryClass"); //NOI18N
508         if (pmfClassName == null) {
509             throw new JDOFatalUserException (msg.msg("EXC_GetPMFNoClassNameProperty")); // NOI18N
510         }
511         try {
512             Class pmfClass = cl.loadClass (pmfClassName);
513             Method pmfMethod = pmfClass.getMethod("getPersistenceManagerFactory",  //NOI18N
514                     new Class[] {Map.class});
515             return (PersistenceManagerFactory) pmfMethod.invoke (null, new Object[] {props});
516         } catch (ClassNotFoundException cnfe) {
517             throw new JDOFatalUserException (msg.msg("EXC_GetPMFClassNotFound", pmfClassName), cnfe); //NOI18N
518         } catch (IllegalAccessException iae) {
519             throw new JDOFatalUserException (msg.msg("EXC_GetPMFIllegalAccess", pmfClassName), iae); //NOI18N
520         } catch (NoSuchMethodException nsme) {
521             throw new JDOFatalInternalException (msg.msg("EXC_GetPMFNoSuchMethod"), nsme); //NOI18N
522         } catch (InvocationTargetException ite) {
523             Throwable nested = ite.getTargetException();
524             if  (nested instanceof JDOException) {
525                 throw (JDOException)nested;
526             } else throw new JDOFatalInternalException (msg.msg("EXC_GetPMFUnexpectedException"), ite); //NOI18N
527         } catch (NullPointerException e) {
528             throw new JDOFatalInternalException (msg.msg("EXC_GetPMFNullPointerException", pmfClassName), e); //NOI18N
529         } catch (ClassCastException e) {
530             throw new JDOFatalInternalException (msg.msg("EXC_GetPMFClassCastException", pmfClassName), e); //NOI18N
531         } catch (Exception e) {
532             throw new JDOFatalInternalException (msg.msg("EXC_GetPMFUnexpectedException"), e); //NOI18N
533         }
534     }
535     
536     /***
537      * Returns a {@link PersistenceManagerFactory} configured based
538      * on the properties stored in the resource at
539      * <code>propsResource</code>. This method is equivalent to
540      * invoking {@link
541      * #getPersistenceManagerFactory(String,ClassLoader)} with
542      * <code>Thread.currentThread().getContextClassLoader()</code> as
543      * the <code>loader</code> argument.
544      * @since 2.0
545      * @param propsResource the resource containing the Properties
546      * @return the PersistenceManagerFactory
547      */
548     public static PersistenceManagerFactory getPersistenceManagerFactory
549         (String propsResource) {
550         return getPersistenceManagerFactory (propsResource,
551             getContextClassLoader());
552     }
553 
554     /***
555      * Returns a {@link PersistenceManagerFactory} configured based
556      * on the properties stored in the resource at
557      * <code>propsResource</code>. Loads the resource via
558      * <code>loader</code>, and creates a {@link
559      * PersistenceManagerFactory} with <code>loader</code>. Any
560      * <code>IOException</code>s thrown during resource loading will
561      * be wrapped in a {@link JDOFatalUserException}.
562      * @since 2.0
563      * @param propsResource the resource containing the Properties
564      * @param loader the class loader to use to load both the propsResource and the <code>PersistenceManagerFactory</code> class
565      * @return the PersistenceManagerFactory
566      */
567     public static PersistenceManagerFactory getPersistenceManagerFactory
568         (String propsResource, ClassLoader loader) {
569         return getPersistenceManagerFactory(propsResource, loader, loader);
570     }
571         
572     /***
573      * Returns a {@link PersistenceManagerFactory} configured based
574      * on the properties stored in the resource at
575      * <code>propsResource</code>. Loads the Properties via
576      * <code>propsLoader</code>, and creates a {@link
577      * PersistenceManagerFactory} with <code>pmfLoader</code>. Any
578      * <code>IOException</code>s thrown during resource loading will
579      * be wrapped in a {@link JDOFatalUserException}.
580      * @since 2.0
581      * @param propsResource the resource containing the Properties
582      * @param propsLoader the class loader to use to load the propsResource
583      * @param pmfLoader the class loader to use to load the <code>PersistenceManagerFactory</code> class
584      * @return the PersistenceManagerFactory
585      */
586     public static PersistenceManagerFactory getPersistenceManagerFactory
587         (String propsResource, ClassLoader propsLoader, ClassLoader pmfLoader) {
588         
589         if (propsResource == null)
590             throw new JDOFatalUserException (msg.msg ("EXC_GetPMFNullResource")); //NOI18N
591         if (propsLoader == null)
592             throw new JDOFatalUserException (msg.msg ("EXC_GetPMFNullPropsLoader")); //NOI18N
593         if (pmfLoader == null)
594             throw new JDOFatalUserException (msg.msg ("EXC_GetPMFNullPMFLoader")); //NOI18N
595 
596         Properties props = new Properties ();
597         InputStream in = null;
598         try {
599             in = propsLoader.getResourceAsStream (propsResource);
600             if (in == null)
601                 throw new JDOFatalUserException
602                     (msg.msg ("EXC_GetPMFNoResource", propsResource, propsLoader)); //NOI18N
603             props.load (in);
604         } catch (IOException ioe) {
605             throw new JDOFatalUserException
606                 (msg.msg ("EXC_GetPMFIOExceptionRsrc", propsResource), ioe); //NOI18N
607         }
608         finally {
609             if (in != null)
610                 try {
611                     in.close (); 
612                 } catch (IOException ioe) { }
613         }
614 
615         return getPersistenceManagerFactory (props, pmfLoader);
616     }
617 
618 
619     /***
620      * Returns a {@link PersistenceManagerFactory} configured based
621      * on the properties stored in the file at
622      * <code>propsFile</code>. This method is equivalent to
623      * invoking {@link
624      * #getPersistenceManagerFactory(File,ClassLoader)} with
625      * <code>Thread.currentThread().getContextClassLoader()</code> as
626      * the <code>loader</code> argument.
627      * @since 2.0
628      * @param propsFile the file containing the Properties
629      * @return the PersistenceManagerFactory
630      */
631     public static PersistenceManagerFactory getPersistenceManagerFactory
632         (File propsFile) {
633         return getPersistenceManagerFactory (propsFile,
634             getContextClassLoader());
635     }
636 
637     /***
638      * Returns a {@link PersistenceManagerFactory} configured based
639      * on the properties stored in the file at
640      * <code>propsFile</code>. Creates a {@link
641      * PersistenceManagerFactory} with <code>loader</code>. Any
642      * <code>IOException</code>s or
643      * <code>FileNotFoundException</code>s thrown during resource
644      * loading will be wrapped in a {@link JDOFatalUserException}.
645      * @since 2.0
646      * @param propsFile the file containing the Properties
647      * @param loader the class loader to use to load the <code>PersistenceManagerFactory</code> class
648      * @return the PersistenceManagerFactory
649      */
650     public static PersistenceManagerFactory getPersistenceManagerFactory
651         (File propsFile, ClassLoader loader) {
652         if (propsFile == null)
653             throw new JDOFatalUserException (msg.msg ("EXC_GetPMFNullFile")); //NOI18N
654         if (loader == null)
655             throw new JDOFatalUserException (msg.msg ("EXC_GetPMFNullLoader")); //NOI18N
656         Properties props = new Properties ();
657         InputStream in = null;
658         try {
659             in = new FileInputStream (propsFile);
660             props.load (in);
661         } catch (FileNotFoundException fnfe) {
662             throw new JDOFatalUserException
663                 (msg.msg ("EXC_GetPMFNoFile", propsFile, loader), fnfe); //NOI18N
664         } catch (IOException ioe) {
665             throw new JDOFatalUserException
666                 (msg.msg ("EXC_GetPMFIOExceptionFile", propsFile), ioe); //NOI18N
667         } finally {
668             if (in != null)
669                 try { 
670                     in.close (); 
671                 } catch (IOException ioe) { }
672         }
673         return getPersistenceManagerFactory (props, loader);
674     }
675 
676     /***
677      * Returns a {@link PersistenceManagerFactory} at the JNDI
678      * location specified by <code>jndiLocation</code> in the context
679      * <code>context</code>. If <code>context</code> is
680      * <code>null</code>, <code>new InitialContext()</code> will be
681      * used. This method is equivalent to invoking {@link
682      * #getPersistenceManagerFactory(String,Context,ClassLoader)}
683      * with <code>Thread.currentThread().getContextClassLoader()</code> as
684      * the <code>loader</code> argument.
685      * @since 2.0
686      * @param jndiLocation the JNDI location containing the PersistenceManagerFactory
687      * @param context the context in which to find the named PersistenceManagerFactory
688      * @return the PersistenceManagerFactory
689      */
690     public static PersistenceManagerFactory getPersistenceManagerFactory
691         (String jndiLocation, Context context) {
692         return getPersistenceManagerFactory (jndiLocation, context,
693             getContextClassLoader());
694     }
695 
696 
697     /***
698      * Returns a {@link PersistenceManagerFactory} at the JNDI
699      * location specified by <code>jndiLocation</code> in the context
700      * <code>context</code>. If <code>context</code> is
701      * <code>null</code>, <code>new InitialContext()</code> will be
702      * used. Creates a {@link PersistenceManagerFactory} with
703      * <code>loader</code>. Any <code>NamingException</code>s thrown
704      * will be wrapped in a {@link JDOFatalUserException}.
705      * @since 2.0
706      * @param jndiLocation the JNDI location containing the PersistenceManagerFactory
707      * @param context the context in which to find the named PersistenceManagerFactory
708      * @param loader the class loader to use to load the <code>PersistenceManagerFactory</code> class
709      * @return the PersistenceManagerFactory
710      */
711     public static PersistenceManagerFactory getPersistenceManagerFactory
712         (String jndiLocation, Context context, ClassLoader loader) {
713         if (jndiLocation == null)
714             throw new JDOFatalUserException (msg.msg ("EXC_GetPMFNullJndiLoc")); //NOI18N
715         if (loader == null)
716             throw new JDOFatalUserException (msg.msg ("EXC_GetPMFNullLoader")); //NOI18N
717         try {
718             if (context == null)
719                 context = new InitialContext ();
720 
721             Object o = context.lookup (jndiLocation);
722             return (PersistenceManagerFactory) PortableRemoteObject.narrow
723                 (o, PersistenceManagerFactory.class);
724         } catch (NamingException ne) {
725             throw new JDOFatalUserException
726                 (msg.msg ("EXC_GetPMFNamingException", jndiLocation, loader), ne); //NOI18N
727         }
728     }
729     
730     /***
731      * Returns a {@link PersistenceManagerFactory} configured based
732      * on the Properties stored in the input stream at
733      * <code>stream</code>. This method is equivalent to
734      * invoking {@link
735      * #getPersistenceManagerFactory(InputStream,ClassLoader)} with
736      * <code>Thread.currentThread().getContextClassLoader()</code> as
737      * the <code>loader</code> argument.
738      * @since 2.0
739      * @param stream the stream containing the Properties
740      * @return the PersistenceManagerFactory
741      */
742     public static PersistenceManagerFactory getPersistenceManagerFactory
743         (InputStream stream) {
744         return getPersistenceManagerFactory (stream,
745             getContextClassLoader());
746     }
747 
748     /***
749      * Returns a {@link PersistenceManagerFactory} configured based
750      * on the Properties stored in the input stream at
751      * <code>stream</code>. Creates a {@link
752      * PersistenceManagerFactory} with <code>loader</code>. Any
753      * <code>IOException</code>s thrown during resource
754      * loading will be wrapped in a {@link JDOFatalUserException}.
755      * @since 2.0
756      * @param stream the stream containing the Properties
757      * @param loader the class loader to use to load the <code>PersistenceManagerFactory</code> class
758      * @return the PersistenceManagerFactory
759      */
760     public static PersistenceManagerFactory getPersistenceManagerFactory
761         (InputStream stream, ClassLoader loader) {
762         if (stream == null)
763             throw new JDOFatalUserException (msg.msg ("EXC_GetPMFNullStream")); //NOI18N
764         if (loader == null)
765             throw new JDOFatalUserException (msg.msg ("EXC_GetPMFNullLoader")); //NOI18N
766         Properties props = new Properties ();
767         try {
768             props.load (stream);
769         } catch (IOException ioe) {
770             throw new JDOFatalUserException
771                 (msg.msg ("EXC_GetPMFIOExceptionStream"), ioe); //NOI18N
772         }
773         return getPersistenceManagerFactory (props, loader);
774     }
775 
776     /*** Get the context class loader associated with the current thread. 
777      * This is done in a doPrivileged block because it is a secure method.
778      * @return the current thread's context class loader.
779      * @since 2.0
780      */
781     private static ClassLoader getContextClassLoader() {
782         return (ClassLoader)AccessController.doPrivileged(
783             new PrivilegedAction () {
784                 public Object run () {
785                     return Thread.currentThread().getContextClassLoader();
786                 }
787             }
788         );
789     }
790 }