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