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