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