1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package javax.jdo;
19  
20  import junit.framework.TestSuite;
21  
22  import javax.jdo.util.AbstractTest;
23  import javax.jdo.util.BatchTestRunner;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.net.URL;
27  import java.net.URLClassLoader;
28  import java.util.Enumeration;
29  import java.util.HashMap;
30  import java.util.Iterator;
31  import java.util.Map;
32  import java.util.Random;
33  
34  /***
35   * Tests class javax.jdo.JDOHelper for META-INF/jdoconfig.xml compliance.
36   */
37  public class JDOHelperConfigTest extends AbstractTest implements Constants {
38  
39      public static void main(String args[]) {
40          BatchTestRunner.run(JDOHelperConfigTest.class);
41      }
42  
43      public static TestSuite suite() {
44          return new TestSuite(JDOHelperConfigTest.class);
45      }
46  
47      protected static String JDOCONFIG_CLASSPATH_PREFIX
48              = initJDOConfigClasspathPrefix();
49  
50      protected static String initJDOConfigClasspathPrefix() {
51          String basedir = System.getProperty("basedir");
52          if (basedir != null) {
53              if (!basedir.endsWith("/")) {
54                  basedir += "/";
55              }
56          } else {
57              basedir = "";
58          }
59          return basedir + "test/schema/jdoconfig";
60      }
61  
62      protected static Random RANDOM = new Random(System.currentTimeMillis());
63  
64      protected Map prepareInitialExpectedMap(
65              String testVariant,
66              int listenerCount,
67              int vendorSpecificPropertyCount,
68              boolean excludeName,
69              boolean excludePUName
70      ) {
71          Map expected = new HashMap();
72  
73          if (!excludeName) {
74              expected.put(
75                      PROPERTY_NAME,
76                      PMF_ATTRIBUTE_NAME + "." + testVariant);
77          }
78          if (!excludePUName) {
79              expected.put(
80                      PROPERTY_PERSISTENCE_UNIT_NAME,
81                      PMF_ATTRIBUTE_PERSISTENCE_UNIT_NAME + "." + testVariant);
82          }
83  
84          expected.put(PROPERTY_PERSISTENCE_MANAGER_FACTORY_CLASS,
85                  PMF_ATTRIBUTE_CLASS + "." + testVariant);
86          expected.put(
87                  PROPERTY_CONNECTION_DRIVER_NAME,
88                  PMF_ATTRIBUTE_CONNECTION_DRIVER_NAME + "." + testVariant);
89          expected.put(
90                  PROPERTY_CONNECTION_FACTORY_NAME,
91                  PMF_ATTRIBUTE_CONNECTION_FACTORY_NAME + "." + testVariant);
92          expected.put(
93                  PROPERTY_CONNECTION_FACTORY2_NAME,
94                  PMF_ATTRIBUTE_CONNECTION_FACTORY2_NAME + "." + testVariant);
95          expected.put(
96                  PROPERTY_CONNECTION_PASSWORD,
97                  PMF_ATTRIBUTE_CONNECTION_PASSWORD + "." + testVariant);
98          expected.put(
99                  PROPERTY_CONNECTION_URL,
100                 PMF_ATTRIBUTE_CONNECTION_URL + "." + testVariant);
101         expected.put(
102                 PROPERTY_CONNECTION_USER_NAME,
103                 PMF_ATTRIBUTE_CONNECTION_USER_NAME + "." + testVariant);
104         expected.put(
105                 PROPERTY_IGNORE_CACHE,
106                 PMF_ATTRIBUTE_IGNORE_CACHE + "." + testVariant);
107         expected.put(
108                 PROPERTY_MAPPING,
109                 PMF_ATTRIBUTE_MAPPING + "." + testVariant);
110         expected.put(
111                 PROPERTY_MULTITHREADED,
112                 PMF_ATTRIBUTE_MULTITHREADED + "." + testVariant);
113         expected.put(
114                 PROPERTY_NONTRANSACTIONAL_READ,
115                 PMF_ATTRIBUTE_NONTRANSACTIONAL_READ + "." + testVariant);
116         expected.put(
117                 PROPERTY_NONTRANSACTIONAL_WRITE,
118                 PMF_ATTRIBUTE_NONTRANSACTIONAL_WRITE + "." + testVariant);
119         expected.put(
120                 PROPERTY_OPTIMISTIC,
121                 PMF_ATTRIBUTE_OPTIMISTIC + "." + testVariant);
122         expected.put(
123                 PROPERTY_RESTORE_VALUES,
124                 PMF_ATTRIBUTE_RESTORE_VALUES + "." + testVariant);
125         expected.put(
126                 PROPERTY_RETAIN_VALUES,
127                 PMF_ATTRIBUTE_RETAIN_VALUES + "." + testVariant);
128         expected.put(
129                 PROPERTY_DETACH_ALL_ON_COMMIT,
130                 PMF_ATTRIBUTE_DETACH_ALL_ON_COMMIT + "." + testVariant);
131         expected.put(
132                 PROPERTY_SERVER_TIME_ZONE_ID,
133                 PMF_ATTRIBUTE_SERVER_TIME_ZONE_ID + "." + testVariant);
134 
135         // listeners
136         for (int i = 0; i < listenerCount; i++) {
137             expected.put(
138                     PROPERTY_PREFIX_INSTANCE_LIFECYCLE_LISTENER +
139                             "listener." + testVariant + ".listener" + i,
140                     "classes." + testVariant + ".classes" + i
141             );
142         }
143 
144         // vendor-specific properties
145         for (int i = 0; i < vendorSpecificPropertyCount; i++) {
146             expected.put(
147                     "property." + testVariant + ".name" + i,
148                     "property." + testVariant + ".value" + i
149             );
150         }
151 
152         return expected;
153     }
154 
155     static void assertEqualProperties(Map expected, Map actual) {
156         Iterator i = expected.entrySet().iterator();
157         while (i.hasNext()) {
158             Map.Entry entry = (Map.Entry) i.next();
159             String key = (String) entry.getKey();
160             String expectedValue = (String) entry.getValue();
161             String actualValue = (String) actual.get(key);
162 
163             assertEquals(
164                     "Actual property at key [" + key + "] with value [" +
165                             actualValue + "] not equal to expected value [" +
166                             expectedValue + "]",
167                     expectedValue,
168                     actualValue);
169         }
170     }
171 
172     protected void doPositiveTest(
173             String[] classpaths,
174             String testVariantName,
175             int listenerCount,
176             int vendorSpecificPropertyCount,
177             boolean checkEqualProperties)
178             throws IOException {
179 
180         doPositiveTest(
181                 classpaths,
182                 testVariantName,
183                 listenerCount,
184                 vendorSpecificPropertyCount,
185                 checkEqualProperties,
186                 false,
187                 false);
188     }
189 
190     protected void doPositiveTest(
191             String[] classpaths,
192             String testVariantName,
193             int listenerCount,
194             int vendorSpecificPropertyCount,
195             boolean checkEqualProperties,
196             boolean excludeName,
197             boolean excludePUName)
198             throws IOException {
199 
200         URLClassLoader loader = new JDOConfigTestClassLoader(
201                 JDOCONFIG_CLASSPATH_PREFIX,
202                 getClass().getClassLoader());
203 
204         for (int i = 0; i < classpaths.length; i++) {
205             ClasspathHelper.addFile(classpaths[i], loader);
206         }
207 
208         Map expected = prepareInitialExpectedMap(
209                 testVariantName,
210                 listenerCount,
211                 vendorSpecificPropertyCount,
212                 excludeName,
213                 excludePUName);
214         
215         String name = testVariantName == null
216                 ? null
217                 : (String) expected.get(PROPERTY_NAME);
218 
219         Map actual = JDOHelper.getPropertiesFromJdoconfig(name, loader);
220 
221         assertNotNull("No properties found", actual);
222         if (checkEqualProperties) {
223             assertEqualProperties(expected, actual);
224         }
225     }
226 
227     public void testPositive00_PMF0_BasicPMFConfigUsingOnlyStandardAttributesAndListeners()
228             throws IOException {
229         doPositiveTest(
230                 new String[]{JDOCONFIG_CLASSPATH_PREFIX + "/Positive00"},
231                 "positive00.pmf0",
232                 2,
233                 0,
234                 true);
235     }
236 
237     public void testPositive00_PMF1_BasicPMFConfigUsingOnlyPropertyElementsWithStandardJavaxDotJDOProperties()
238             throws IOException {
239         doPositiveTest(
240                 new String[]{JDOCONFIG_CLASSPATH_PREFIX + "/Positive00"},
241                 "positive00.pmf1",
242                 2,
243                 0,
244                 true);
245     }
246 
247     public void testPositive00_PMF2_NestedPropertyElementsWithOnlyStandardAttributeNames()
248             throws IOException {
249         doPositiveTest(
250                 new String[]{JDOCONFIG_CLASSPATH_PREFIX + "/Positive00"},
251                 "positive00.pmf2",
252                 2,
253                 0,
254                 true);
255     }
256 
257     public void testPositive00_PMF3_StandardAttributesPlusNonstandardPropertiesInPropertyElements()
258             throws IOException {
259         doPositiveTest(
260                 new String[]{JDOCONFIG_CLASSPATH_PREFIX + "/Positive00"},
261                 "positive00.pmf3",
262                 2,
263                 2,
264                 true);
265     }
266 
267     public void testPositive00_PMF4_StandardAttributesPlusNonstandardAttributes()
268             throws IOException {
269         doPositiveTest(
270                 new String[]{JDOCONFIG_CLASSPATH_PREFIX + "/Positive00"},
271                 "positive00.pmf4",
272                 0,
273                 2,
274                 true);
275     }
276 
277     public void testPositive01_DuplicatePUsInDifferentConfigFilesButNotRequested()
278             throws IOException {
279 
280         URLClassLoader loader = new JDOConfigTestClassLoader(
281                 JDOCONFIG_CLASSPATH_PREFIX,
282                 getClass().getClassLoader());
283 
284         String[] classpaths = new String[]{
285             JDOCONFIG_CLASSPATH_PREFIX + "/Positive01/1a",
286             JDOCONFIG_CLASSPATH_PREFIX + "/Positive01/1b"
287         };
288         for (int i = 0; i < classpaths.length; i++) {
289             ClasspathHelper.addFile(classpaths[i], loader);
290         }
291 
292         Map actual = JDOHelper.getPropertiesFromJdoconfig(
293                 ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME, loader);
294     }
295 
296     public void testPositive02_GetAnonymousPMFWithNoProperties()
297             throws IOException {
298         
299         URLClassLoader loader = new JDOConfigTestClassLoader(
300                 JDOCONFIG_CLASSPATH_PREFIX,
301                 getClass().getClassLoader());
302 
303             ClasspathHelper.addFile(
304                     JDOCONFIG_CLASSPATH_PREFIX + "/Positive02", loader);
305 
306         Map properties = JDOHelper.getPropertiesFromJdoconfig(
307                 ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME, loader);
308         assertNotNull(
309                 "Anonymous PMF with no properties returned null", properties);
310         assertTrue(
311                 "Anonymous PMF with no properties had properties",
312                 properties.size() == 0);
313     }
314 
315     public void testPositive03_PMF0_PMFClassNameViaServicesLookup()
316             throws IOException {
317 
318         URLClassLoader loader = new JDOConfigTestClassLoader(
319                 JDOCONFIG_CLASSPATH_PREFIX,
320                 getClass().getClassLoader());
321         ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive03", loader);
322 
323         String expected = "class.positive03.pmf0";
324         String actual = getPMFClassNameViaServiceLookup(loader);
325 
326         assertNotNull("No PMF name found via services lookup", actual);
327         assertEquals(expected, actual);
328     }
329 
330     public void testPositive04_PMF0_PMFClassNameViaServicesLookup()
331             throws IOException {
332 
333         URLClassLoader loader = new JDOConfigTestClassLoader(
334                 JDOCONFIG_CLASSPATH_PREFIX,
335                 getClass().getClassLoader());
336         ClasspathHelper.addFile(JDOCONFIG_CLASSPATH_PREFIX + "/Positive04", loader);
337 
338         String expected = "class.positive04.pmf0";
339         String actual = getPMFClassNameViaServiceLookup(loader);
340 
341         assertNotNull("No PMF name found via services lookup", actual);
342         assertEquals(expected, actual);
343     }
344 
345     public void testPositive05_PMF0_PMFClassNameViaServicesLookup()
346             throws IOException {
347 
348         URLClassLoader loader = new JDOConfigTestClassLoader(
349                 JDOCONFIG_CLASSPATH_PREFIX,
350                 getClass().getClassLoader());
351         ClasspathHelper.addFile(
352                 JDOCONFIG_CLASSPATH_PREFIX + "/Positive05", loader);
353 
354         String expected = "class.positive05.pmf0";
355         String actual = getPMFClassNameViaServiceLookup(loader);
356 
357         assertNotNull("No PMF name found via services lookup", actual);
358         assertEquals(expected, actual);
359     }
360 
361     public void testPositive06_PMF0_GetAnonymousPMFProperties()
362             throws IOException {
363 
364         URLClassLoader loader = new JDOConfigTestClassLoader(
365                 JDOCONFIG_CLASSPATH_PREFIX,
366                 getClass().getClassLoader());
367 
368         ClasspathHelper.addFile(
369                 JDOCONFIG_CLASSPATH_PREFIX + "/Positive06", loader);
370 
371         Map expected = prepareInitialExpectedMap(
372                 "positive06.pmf0", 2, 0, true, true);
373 
374         Map actual = JDOHelper.getPropertiesFromJdoconfig(
375                 ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME, loader);
376 
377         assertNotNull("No properties found", actual);
378         assertEqualProperties(expected, actual);
379     }
380 
381     public void testPositive07_PMF0_GetAnonymousPMFPropertiesWithPUName()
382             throws IOException {
383 
384         URLClassLoader loader = new JDOConfigTestClassLoader(
385                 JDOCONFIG_CLASSPATH_PREFIX,
386                 getClass().getClassLoader());
387 
388         ClasspathHelper.addFile(
389                 JDOCONFIG_CLASSPATH_PREFIX + "/Positive07", loader);
390 
391         Map expected = prepareInitialExpectedMap(
392                 "positive07.pmf0", 2, 0, true, false);
393 
394         Map actual = JDOHelper.getPropertiesFromJdoconfig(
395                 ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME, loader);
396 
397         assertNotNull("No properties found", actual);
398         assertEqualProperties(expected, actual);
399     }
400 
401     public void testNegative00_EmptyJDOConfigXML() throws IOException {
402         try {
403             URLClassLoader loader = new JDOConfigTestClassLoader(
404                     JDOCONFIG_CLASSPATH_PREFIX,
405                     getClass().getClassLoader());
406             ClasspathHelper.addFile(
407                     JDOCONFIG_CLASSPATH_PREFIX + "/Negative0", loader);
408 
409             JDOHelper.getPersistenceManagerFactory(loader);
410             fail("JDOHelper failed to throw JDOFatalUserException");
411         }
412         catch (JDOFatalUserException x) {
413             // sunny day
414         }
415     }
416 
417     public void testNegative01_NoPersistenceUnitsDefined() throws IOException {
418         try {
419             URLClassLoader loader = new JDOConfigTestClassLoader(
420                     JDOCONFIG_CLASSPATH_PREFIX,
421                     getClass().getClassLoader());
422             ClasspathHelper.addFile(
423                     JDOCONFIG_CLASSPATH_PREFIX + "/Negative01", loader);
424 
425             JDOHelper.getPersistenceManagerFactory(loader);
426             fail("JDOHelper failed to throw JDOFatalUserException");
427         }
428         catch (JDOFatalUserException x) {
429             // joy, sweet joy
430         }
431     }
432 
433     public void testNegative02_DuplicateAnonymousPersistenceUnitsInSameConfig()
434             throws IOException {
435         try {
436             URLClassLoader loader = new JDOConfigTestClassLoader(
437                     JDOCONFIG_CLASSPATH_PREFIX,
438                     getClass().getClassLoader());
439             ClasspathHelper.addFile(
440                     JDOCONFIG_CLASSPATH_PREFIX + "/Negative02", loader);
441 
442             JDOHelper.getPersistenceManagerFactory(loader);
443             fail("JDOHelper failed to throw JDOFatalUserException");
444         }
445         catch (JDOFatalUserException x) {
446             // the cockles of my heart warmeth
447         }
448     }
449 
450     public void testNegative03_DuplicateNamedPersistenceUnitsInSameConfig()
451             throws IOException {
452         try {
453             URLClassLoader loader = new JDOConfigTestClassLoader(
454                     JDOCONFIG_CLASSPATH_PREFIX,
455                     getClass().getClassLoader());
456             ClasspathHelper.addFile(
457                     JDOCONFIG_CLASSPATH_PREFIX + "/Negative03", loader);
458 
459             JDOHelper.getPersistenceManagerFactory(
460                     "name.negative03",
461                     loader);
462 
463             fail("JDOHelper failed to throw JDOFatalUserException");
464         }
465         catch (JDOFatalUserException x) {
466             // warm fuzzies
467         }
468     }
469 
470     public void testNegative04_DuplicatePUNamePropertyInAttributeAndElement()
471             throws IOException {
472         try {
473             URLClassLoader loader = new JDOConfigTestClassLoader(
474                     JDOCONFIG_CLASSPATH_PREFIX,
475                     getClass().getClassLoader());
476             ClasspathHelper.addFile(
477                     JDOCONFIG_CLASSPATH_PREFIX + "/Negative04", loader);
478 
479             JDOHelper.getPersistenceManagerFactory(
480                     "name.negative04.value0",
481                     loader);
482 
483             fail("JDOHelper failed to throw JDOFatalUserException");
484         }
485         catch (JDOFatalUserException x) {
486             // no cold pricklies
487         }
488     }
489 
490     public void testNegative05_DuplicatePropertyInAttributeAndElement()
491             throws IOException {
492         try {
493             URLClassLoader loader = new JDOConfigTestClassLoader(
494                     JDOCONFIG_CLASSPATH_PREFIX,
495                     getClass().getClassLoader());
496             ClasspathHelper.addFile(
497                     JDOCONFIG_CLASSPATH_PREFIX + "/Negative05", loader);
498 
499             JDOHelper.getPersistenceManagerFactory(loader);
500 
501             fail("JDOHelper failed to throw JDOFatalUserException");
502         }
503         catch (JDOFatalUserException x) {
504             // party!
505         }
506     }
507 
508     public void testNegative06_DuplicatePUInDifferentConfigFiles()
509             throws IOException {
510         try {
511             URLClassLoader loader = new JDOConfigTestClassLoader(
512                     JDOCONFIG_CLASSPATH_PREFIX,
513                     getClass().getClassLoader());
514             ClasspathHelper.addFile(
515                     JDOCONFIG_CLASSPATH_PREFIX + "/Negative06/6a", loader);
516             ClasspathHelper.addFile(
517                     JDOCONFIG_CLASSPATH_PREFIX + "/Negative06/6b", loader);
518 
519             JDOHelper.getPersistenceManagerFactory(
520                     "name.negative06",
521                     loader);
522 
523             fail("JDOHelper failed to throw JDOFatalUserException");
524         }
525         catch (JDOFatalUserException x) {
526             // clear blue sky
527         }
528     }
529 
530     public void testNegative07_EmptyServicesFile()
531             throws IOException {
532         JDOConfigTestClassLoader testLoader = new JDOConfigTestClassLoader(
533                 new String[]{JDOCONFIG_CLASSPATH_PREFIX},
534                 getClass().getClassLoader());
535         ClasspathHelper.addFile(
536                 JDOCONFIG_CLASSPATH_PREFIX + "/Negative07", testLoader);
537         String shouldBeNull =
538                getPMFClassNameViaServiceLookup(testLoader);
539         assertNull(shouldBeNull);
540     }
541 
542     public void testNegative08_NoResourcesFound() {
543         String resource = "" + RANDOM.nextLong();
544 
545         InputStream in =
546                 getClass().getClassLoader().getResourceAsStream(resource);
547         assertNull(in);
548 
549         // resource pretty much guaranteed not to exist
550         try {
551             JDOHelper.getPersistenceManagerFactory(resource);
552             fail("JDOHelper failed to throw JDOFatalUserException");
553         }
554         catch (JDOFatalUserException x) {
555             // happy path
556         }
557     }
558 
559     public void testNegative08_ServicesFileWithOnlyComments()
560             throws IOException {
561         JDOConfigTestClassLoader testLoader = new JDOConfigTestClassLoader(
562                 new String[]{JDOCONFIG_CLASSPATH_PREFIX},
563                 getClass().getClassLoader());
564         ClasspathHelper.addFile(
565                 JDOCONFIG_CLASSPATH_PREFIX + "/Negative08", testLoader);
566         String shouldBeNull =
567                 getPMFClassNameViaServiceLookup(testLoader);
568         assertNull(shouldBeNull);
569     }
570     
571     private String getPMFClassNameViaServiceLookup(ClassLoader loader) {
572         try {
573             Enumeration urls = JDOHelper.getResources(loader, 
574                 SERVICE_LOOKUP_PMF_RESOURCE_NAME);
575             while (urls.hasMoreElements()) {
576                 // return the first one found
577                 return JDOHelper.getClassNameFromURL((URL)urls.nextElement());
578             }
579         } catch (Exception ex) {
580             // ignore exceptions from i/o errors
581         }
582         return null;            
583     }
584 }