KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > ejb > cmp3 > persistence > PersistenceUnitProcessor


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21 // Copyright (c) 1998, 2006, Oracle. All rights reserved.
22
package oracle.toplink.essentials.ejb.cmp3.persistence;
23
24 import java.net.URL JavaDoc;
25 import java.net.URI JavaDoc;
26 import java.net.URISyntaxException JavaDoc;
27 import java.util.jar.JarInputStream JavaDoc;
28 import java.util.zip.ZipEntry JavaDoc;
29 import java.util.Enumeration JavaDoc;
30 import java.io.File JavaDoc;
31 import java.io.IOException JavaDoc;
32 import java.io.InputStream JavaDoc;
33 import java.io.FileInputStream JavaDoc;
34 import java.io.FileNotFoundException JavaDoc;
35 import java.util.List JavaDoc;
36 import java.util.Vector JavaDoc;
37 import java.util.Iterator JavaDoc;
38 import java.util.Set JavaDoc;
39 import java.util.HashSet JavaDoc;
40
41 import javax.xml.parsers.SAXParser JavaDoc;
42 import javax.xml.parsers.SAXParserFactory JavaDoc;
43 import javax.persistence.spi.PersistenceUnitInfo;
44
45 import org.xml.sax.XMLReader JavaDoc;
46 import org.xml.sax.InputSource JavaDoc;
47
48 import oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException;
49 import oracle.toplink.essentials.exceptions.XMLParseException;
50 import oracle.toplink.essentials.internal.ejb.cmp3.xml.XMLConstants;
51 import oracle.toplink.essentials.internal.ejb.cmp3.xml.parser.PersistenceContentHandler;
52 import oracle.toplink.essentials.internal.ejb.cmp3.xml.parser.XMLException;
53 import oracle.toplink.essentials.internal.ejb.cmp3.xml.parser.XMLExceptionHandler;
54 import oracle.toplink.essentials.logging.AbstractSessionLog;
55
56 /**
57  * INTERNAL:
58  * Utility Class that deals with persistence archives for EJB 3.0
59  * Provides functions like searching for persistence archives, processing persistence.xml
60  * and searching for Entities in a Persistence archive
61  */

62 public class PersistenceUnitProcessor {
63    
64     public static final String JavaDoc JAR_OPENING_EXCEPTION = "attempted_to_open_url_as_jar";
65     public static final String JavaDoc DIRECTORY_OPENING_EXCEPTION = "attempted_to_open_url_as_directory";
66     public static final String JavaDoc JAR_ENTRY_OPENING_EXCEPTION = "attempted_to_open_entry_in_url_as_jar";
67     public static final String JavaDoc DIRECTORY_ENTRY_OPENING_EXCEPTION = "attempted_to_open_file_url_as_directory";
68
69     /**
70      * Get a list of persitence units from the file or directory at the given url
71      * PersistenceUnits are built based on the presence of persistence.xml in a META-INF directory
72      * at the base of the URL
73      * @param url The url of a jar file or directory to check
74      * @return
75      */

76     public static List JavaDoc<SEPersistenceUnitInfo> getPersistenceUnits(URL JavaDoc url, ClassLoader JavaDoc loader){
77         return processPersistenceArchive(url, loader);
78     }
79     
80     
81   /**
82    * Open a stream on a url representing a persistence.xml and process it.
83    * The URL passed into this method should be a persistence.xml file.
84    * @param file
85    */

86     protected static List JavaDoc<SEPersistenceUnitInfo> processPersistenceArchveFromUnconvertableURL(URL JavaDoc baseURL, ClassLoader JavaDoc loader){
87         InputStream JavaDoc stream = null;
88         try{
89             stream = baseURL.openStream();
90             return processPersistenceXML(baseURL, stream, loader);
91
92         } catch (IOException JavaDoc exc){
93             throw PersistenceUnitLoadingException.exceptionLoadingFromUrl(baseURL.toString(), exc);
94         } finally {
95             try{
96                 if (stream != null){
97                     stream.close();
98                 }
99             } catch (IOException JavaDoc exc){};
100
101         }
102     }
103     
104   /**
105    * Search a directory for persistence.xml. It should be found in a
106    * meta-inf directory contained within the passed directory.
107    * The file passed into this method should be a jar file or null will be returned
108    * @param file a File representing the directory to search
109    */

110     private static List JavaDoc<SEPersistenceUnitInfo> processDirectory(URL JavaDoc baseURL, File JavaDoc file, ClassLoader JavaDoc loader){
111         FileInputStream JavaDoc inputStream = null;
112         try{
113             String JavaDoc filePath = file.getPath();
114             File JavaDoc persistenceXMLFile = new File JavaDoc(filePath + File.separator + "META-INF" + File.separator + "persistence.xml");
115             
116             if (!persistenceXMLFile.exists()){
117                 persistenceXMLFile = new File JavaDoc(filePath + File.separator + "meta-inf" + File.separator + "persistence.xml");
118             }
119             if (persistenceXMLFile.exists()){
120                 inputStream = new FileInputStream JavaDoc(persistenceXMLFile);
121                 return processPersistenceXML(baseURL, inputStream, loader);
122             }
123             return null;
124         } catch (FileNotFoundException JavaDoc exc){
125             throw PersistenceUnitLoadingException.exceptionLoadingFromDirectory(file, exc);
126         } finally {
127             try{
128                 if (inputStream != null){
129                     inputStream.close();
130                 }
131             } catch (IOException JavaDoc exc){};
132
133         }
134     }
135     
136   /**
137    * Search a jar file for persistence.xml. It should be found in the
138    * the meta-inf subdirectory. When persistence.xml is found, process it.
139    * The file passed into this method should be a jar file.
140    * @param file
141    */

142     protected static List JavaDoc<SEPersistenceUnitInfo> processJarFile(URL JavaDoc baseURL, ClassLoader JavaDoc loader){
143         JarInputStream JavaDoc jarFile = null;
144         InputStream JavaDoc stream = null;
145         try{
146             stream = createInputStreamForURL(baseURL);
147             jarFile = new JarInputStream JavaDoc(stream);
148             ZipEntry JavaDoc entry = jarFile.getNextEntry();
149             while (entry != null && !entry.getName().equals("META-INF/persistence.xml") && !entry.getName().equals("meta-inf/persistence.xml")){
150                 entry = jarFile.getNextEntry();
151             }
152             if (entry != null && (entry.getName().equals("META-INF/persistence.xml") || entry.getName().equals("meta-inf/persistence.xml"))){
153                 return processPersistenceXML(baseURL, jarFile, loader);
154             }
155             return null;
156         } catch (IOException JavaDoc exc){
157             throw PersistenceUnitLoadingException.exceptionLoadingFromJar(baseURL, exc);
158         } finally {
159             try{
160                 if (jarFile != null){
161                     jarFile.close();
162                 }
163                 if (stream != null){
164                     stream.close();
165                 }
166             } catch (IOException JavaDoc exc){};
167
168         }
169     }
170     
171     /**
172      * Go through the jar file for this PeristeneUnitProcessor and process any XML provided in it
173      */

174     private static List JavaDoc<SEPersistenceUnitInfo> processPersistenceArchive(URL JavaDoc url, ClassLoader JavaDoc loader){
175         File JavaDoc file = null;
176         List JavaDoc<SEPersistenceUnitInfo> persistenceUnitList = null;
177         // Should be called from JavaSE, and so the url string should still contain
178
// the meta-inf/persistence.xml at the end that should be stripped off to be handled as a file
179
URL JavaDoc tempURL = truncateURLAndRemoveFileReference(url);
180         try{
181             persistenceUnitList = processJarFile(tempURL, loader);
182             if (persistenceUnitList != null){
183                 return persistenceUnitList;
184             }
185         } catch (Exception JavaDoc exception){
186             AbstractSessionLog.getLog().log(AbstractSessionLog.FINEST, JAR_OPENING_EXCEPTION, url, exception);
187         };
188         
189         try{
190             // Only URL.toURI() handles spaces and special characters correctly
191
file = new File JavaDoc(convertURLToURI(tempURL));
192             if (file.isDirectory()){
193                 persistenceUnitList = processDirectory(tempURL, file, loader);
194                 if (persistenceUnitList != null){
195                     return persistenceUnitList;
196                 }
197             }
198         } catch (Exception JavaDoc exception){
199             AbstractSessionLog.getLog().log(AbstractSessionLog.FINEST, DIRECTORY_OPENING_EXCEPTION, url, exception);
200         };
201             
202         persistenceUnitList = processPersistenceArchveFromUnconvertableURL(url, loader);
203
204         return persistenceUnitList;
205     }
206     
207     /**
208      * Create an input stream for a file contained in a persistence unit.
209      * This method will use the root url in the persistence unit as a base and try to discover the
210      * given filename within that context
211      *
212      * This method will handle root urls that can be converted to JarFiles and to directories in a
213      * special manner and if it fails, will guess which System resource to use.
214      */

215     public static InputStream JavaDoc createInputStreamForFileInPersistenceUnit(String JavaDoc fileName, PersistenceUnitInfo persistenceUnitInfo, ClassLoader JavaDoc classLoader) throws IOException JavaDoc{
216         InputStream JavaDoc stream = null;
217         try{
218             stream = createInputStreamForJarFile(fileName, persistenceUnitInfo.getPersistenceUnitRootUrl());
219             if (stream != null){
220                 return stream;
221             }
222         } catch (Exception JavaDoc e){
223             AbstractSessionLog.getLog().log(AbstractSessionLog.FINEST, JAR_ENTRY_OPENING_EXCEPTION, persistenceUnitInfo.getPersistenceUnitRootUrl(), fileName, e);
224         };
225            
226         try {
227             // Only URL.toURI() handles spaces and special characters correctly
228
File JavaDoc file = new File JavaDoc(convertURLToURI(persistenceUnitInfo.getPersistenceUnitRootUrl()));
229             if (file.isDirectory()){
230                 stream = createInputStreamForDirectory(fileName, file);
231                 if (stream != null){
232                     return stream;
233                 }
234             }
235         } catch (Exception JavaDoc e){
236             AbstractSessionLog.getLog().log(AbstractSessionLog.FINEST, DIRECTORY_ENTRY_OPENING_EXCEPTION, persistenceUnitInfo.getPersistenceUnitRootUrl(), fileName, e);
237         };
238
239         return createInputStreamForUnconvertableURL(fileName, persistenceUnitInfo.getPersistenceUnitRootUrl(), classLoader);
240    }
241     
242     /**
243      * Create an input stream for a file in a jar file
244      */

245     public static InputStream JavaDoc createInputStreamForJarFile(String JavaDoc fileName, URL JavaDoc url) throws IOException JavaDoc{
246         JarInputStream JavaDoc jarInputStream = new JarInputStream JavaDoc(createInputStreamForURL(url));
247  
248         ZipEntry JavaDoc entry = jarInputStream.getNextEntry();
249         while (entry != null && !entry.getName().equals(fileName)){
250             entry = jarInputStream.getNextEntry();
251         }
252         if (entry != null && (entry.getName().equals(fileName))){
253             return jarInputStream;
254         }
255         return null;
256     }
257
258     /**
259      * Create an input stream for a file in a directory
260      */

261     public static InputStream JavaDoc createInputStreamForDirectory(String JavaDoc fileName, File JavaDoc inputFile) throws IOException JavaDoc{
262         String JavaDoc filePath = inputFile.getPath();
263         String JavaDoc tempFileName = fileName;
264         if (!filePath.endsWith(File.separator) && !fileName.startsWith(File.separator)){
265             tempFileName = File.separator + tempFileName;
266         }
267         
268         File JavaDoc xmlFile = new File JavaDoc(filePath + tempFileName);
269         if (xmlFile.exists()){
270             return new FileInputStream JavaDoc(xmlFile);
271         }
272         return null;
273     }
274
275     /**
276      * Create an InputStream for a fileName in a URL that could not be converted to a JarFile
277      * or a directory.
278      * This method looks up the fileName as a resources on the given ClassLoader and guesses
279      * whether it is the correct file by comparing the URL of the discovered resource to the
280      * base URL of the file being searched for
281      */

282     public static InputStream JavaDoc createInputStreamForUnconvertableURL(String JavaDoc fileName, URL JavaDoc url, ClassLoader JavaDoc loader) throws IOException JavaDoc{
283         String JavaDoc persistenceUnitRoolUrlString = url.toString();
284         Enumeration JavaDoc<URL JavaDoc> resources = loader.getResources(fileName);
285         while (resources.hasMoreElements()){
286             URL JavaDoc mappingFileResource = resources.nextElement();
287             String JavaDoc mappingFileResourceString = mappingFileResource.toString();
288             if(mappingFileResourceString.contains(persistenceUnitRoolUrlString)) {
289                 return url.openStream();
290             }
291         }
292         return null;
293     }
294     
295     /**
296      * This method will attempt to open an InputStream on a URL by first calling the url.openStream() method
297      * If that succeeds, the stream will be returned. If it fails, we will attempt to modify the URL to a form
298      * that we can open and returned a stream based on the modified stream.
299      * If that fails, we will throw in exception we initially got on openStream()
300      */

301     public static InputStream JavaDoc createInputStreamForURL(URL JavaDoc url) throws IOException JavaDoc{
302         InputStream JavaDoc stream = null;
303         IOException JavaDoc initialException = null;
304         try{
305             // attempt to open a stream on the given URL
306
stream = url.openStream();
307         } catch (IOException JavaDoc exc){
308             AbstractSessionLog.getLog().log(AbstractSessionLog.FINEST, JAR_OPENING_EXCEPTION, url, exc);
309             initialException = exc;
310             try{
311                 // guess at an alternate form of the URL to open
312
stream = createTruncatedJarURLFromString(url.toString()).openStream();
313             } catch (PersistenceUnitLoadingException exception){
314                 AbstractSessionLog.getLog().log(AbstractSessionLog.FINEST, JAR_OPENING_EXCEPTION, url, exception);
315                 throw initialException;
316             } catch (IOException JavaDoc exception2){
317                 AbstractSessionLog.getLog().log(AbstractSessionLog.FINEST, JAR_OPENING_EXCEPTION, url, exception2);
318                 throw initialException;
319             }
320         }
321         return stream;
322     }
323     
324   /**
325    * Build a persistence.xml file into a SEPersistenceUnitInfo object
326    * @param input
327    */

328     public static List JavaDoc<SEPersistenceUnitInfo> processPersistenceXML(URL JavaDoc baseURL, InputStream JavaDoc input, ClassLoader JavaDoc loader){
329         SAXParserFactory JavaDoc spf = SAXParserFactory.newInstance();
330         spf.setNamespaceAware(true);
331         spf.setValidating(true);
332         
333         XMLReader JavaDoc xmlReader = null;
334         SAXParser JavaDoc sp = null;
335         XMLExceptionHandler xmlErrorHandler = new XMLExceptionHandler();
336
337         // create a SAX parser
338
try {
339             sp = spf.newSAXParser();
340             sp.setProperty(XMLConstants.SCHEMA_LANGUAGE, XMLConstants.XML_SCHEMA);
341         } catch (javax.xml.parsers.ParserConfigurationException JavaDoc exc){
342             throw XMLParseException.exceptionCreatingSAXParser(baseURL, exc);
343         } catch (org.xml.sax.SAXException JavaDoc exc){
344             throw XMLParseException.exceptionCreatingSAXParser(baseURL, exc);
345         }
346             
347         // create an XMLReader
348
try {
349             xmlReader = sp.getXMLReader();
350             xmlReader.setErrorHandler(xmlErrorHandler);
351         } catch (org.xml.sax.SAXException JavaDoc exc){
352             throw XMLParseException.exceptionCreatingXMLReader(baseURL, exc);
353         }
354        
355         // attempt to load the schema from the classpath
356
URL JavaDoc schemaURL = loader.getResource(XMLConstants.PERSISTENCE_SCHEMA_NAME);
357         if (schemaURL != null) {
358             try {
359                 sp.setProperty(XMLConstants.JAXP_SCHEMA_SOURCE, schemaURL.toString());
360             } catch (org.xml.sax.SAXException JavaDoc exc){
361                 throw XMLParseException.exceptionSettingSchemaSource(baseURL, schemaURL, exc);
362             }
363         }
364         
365         PersistenceContentHandler myContentHandler = new PersistenceContentHandler();
366         xmlReader.setContentHandler(myContentHandler);
367
368         InputSource JavaDoc inputSource = new InputSource JavaDoc(input);
369         try{
370             xmlReader.parse(inputSource);
371         } catch (IOException JavaDoc exc){
372             throw PersistenceUnitLoadingException.exceptionProcessingPersistenceXML(baseURL, exc);
373         } catch (org.xml.sax.SAXException JavaDoc exc){
374             // XMLErrorHandler will handle SAX exceptions
375
}
376         
377         // handle any parse exceptions
378
XMLException xmlError = xmlErrorHandler.getXMLException();
379         if (xmlError != null) {
380             throw PersistenceUnitLoadingException.exceptionProcessingPersistenceXML(baseURL, xmlError);
381         }
382
383         Iterator JavaDoc<SEPersistenceUnitInfo> persistenceInfos = myContentHandler.getPersistenceUnits().iterator();
384         while (persistenceInfos.hasNext()){
385             SEPersistenceUnitInfo info = persistenceInfos.next();
386             info.setPersistenceUnitRootUrl(baseURL);
387         }
388         return myContentHandler.getPersistenceUnits();
389     }
390     
391   /**
392    * Strips down a URL for a persistence.xml so that it's base can be used to create a file
393    */

394     private static URL JavaDoc truncateURLAndRemoveFileReference(URL JavaDoc url) {
395         String JavaDoc newURLString = url.toString().substring(0, url.toString().length() - 25);
396         return createTruncatedJarURLFromString(newURLString);
397
398     }
399
400     /**
401      * Clean up a string that represents a jar. This will create a URL based on the url parameter, but remove
402      * a leading 'jar:' and trailing characters starting with the first '!'. The functionality guesses at a URL
403      * that a stream can be opened on based on the url parameter.
404      * This method is implemented to attempt to provide a URL that can be opened based on a URL retrieved from
405      * a classLoader.getResource(String) call on a TomCat deployment.
406      * @param url
407      * @return
408      */

409     private static URL JavaDoc createTruncatedJarURLFromString(String JavaDoc url){
410         try{
411             String JavaDoc cleanUrl = url;
412             int index = url.lastIndexOf('!');
413             if (index > 0){
414                 cleanUrl = cleanUrl.substring(0, index);
415             }
416             if (cleanUrl.startsWith("jar:")){
417                 cleanUrl = cleanUrl.substring(4, cleanUrl.length());
418             }
419             return new URL JavaDoc(cleanUrl);
420                 
421         } catch (java.net.MalformedURLException JavaDoc exc){
422             throw PersistenceUnitLoadingException.exceptionLoadingFromUrl(url, exc);
423         }
424     }
425     
426    /**
427    * Entries in a zip file are directory entries using slashes to separate them.
428    * Build a class name using '.' instead of slash and removing the '.class' extension.
429    * @param classEntryString
430    * @return
431    */

432     public static String JavaDoc buildClassNameFromEntryString(String JavaDoc classEntryString){
433         String JavaDoc classNameForLoader = classEntryString;
434         if (classEntryString.endsWith(".class")){
435             classNameForLoader = classNameForLoader.substring(0, classNameForLoader.length() - 6);;
436             classNameForLoader = classNameForLoader.replace("/", ".");
437         }
438         return classNameForLoader;
439     }
440
441    /**
442    * Build a set that contains all the class names at a URL
443    * @return a Set of class name strings
444    */

445     public static Set JavaDoc<String JavaDoc> buildClassSet(PersistenceUnitInfo persistenceUnitInfo){
446         Set JavaDoc<String JavaDoc> set = new HashSet JavaDoc<String JavaDoc>();
447         set.addAll(persistenceUnitInfo.getManagedClassNames());
448         Iterator JavaDoc i = persistenceUnitInfo.getJarFileUrls().iterator();
449         while (i.hasNext()) {
450             set.addAll(PersistenceUnitProcessor.getClassNamesFromURL((URL JavaDoc)i.next()));
451         }
452         if (!persistenceUnitInfo.excludeUnlistedClasses()){
453             set.addAll(PersistenceUnitProcessor.getClassNamesFromURL(persistenceUnitInfo.getPersistenceUnitRootUrl()));
454         }
455        return set;
456     }
457
458   /**
459    * Return a set of class names that are annotated as either @Entity or @Embeddable.
460    * from the base URL of this PersistenceUnitProcessor
461    * @param loader the class loader to load the classes with
462    * @return
463    */

464     public static Set JavaDoc<String JavaDoc> buildPersistentClassSet(PersistenceUnitInfo persistenceUnitInfo, ClassLoader JavaDoc loader){
465         Set JavaDoc<String JavaDoc> set = new HashSet JavaDoc();
466         
467         for (String JavaDoc className : persistenceUnitInfo.getManagedClassNames()) {
468             if (isClassPersistent(className, loader, true)) {
469                 set.add(className);
470             }
471         }
472         
473         Iterator JavaDoc i = persistenceUnitInfo.getJarFileUrls().iterator();
474         while (i.hasNext()) {
475             set.addAll(PersistenceUnitProcessor.getPersistentClassNamesFromURL((URL JavaDoc)i.next(), loader));
476         }
477         if (!persistenceUnitInfo.excludeUnlistedClasses()){
478             set.addAll(PersistenceUnitProcessor.getPersistentClassNamesFromURL(persistenceUnitInfo.getPersistenceUnitRootUrl(), loader));
479         }
480        return set;
481     }
482
483   /**
484    * Recursive method to look through a directory and build class names for all files
485    * ending in '.class' in that directory and any subdirectory. Strips out any extraneous
486    * characters and returns a className with package names separated by '.'
487    * @param directory
488    * @param leadingCharactersToRemove
489    * @return Returns a list of class names in a directory
490    */

491     protected static List JavaDoc<String JavaDoc> findClassesInDirectory(File JavaDoc directory, int leadingCharactersToRemove){
492         Vector JavaDoc classes = new Vector JavaDoc();
493         File JavaDoc[] files = directory.listFiles();
494         for (File JavaDoc file: files){
495             if (file.isDirectory()){
496                 classes.addAll(findClassesInDirectory(file, leadingCharactersToRemove));
497             }
498             if (file.isFile() && file.getName().endsWith(".class")){
499                 String JavaDoc className = file.getPath().substring(leadingCharactersToRemove + 1, file.getPath().length() - 6);
500                 className = className.replace("/", ".");
501                 className = className.replace("\\", ".");
502                 classes.add(className);
503             }
504         }
505         return classes;
506     }
507
508     /**
509      * Search the classpath for persistence archives. A persistence archive is defined as any
510      * part of the class path that contains a META-INF directory with a persistence.xml file in it.
511      * Return a list of the URLs of those files.
512      * Use the current thread's context classloader to get the classpath. We assume it is a URL class loader
513      */

514     public static Set JavaDoc<URL JavaDoc> findPersistenceArchives(){
515         ClassLoader JavaDoc threadLoader = Thread.currentThread().getContextClassLoader();
516         return findPersistenceArchives(threadLoader);
517     }
518
519
520     /**
521      * Search the classpath for persistence archives. A persistence archive is defined as any
522      * part of the class path that contains a META-INF directory with a persistence.xml file in it..
523      * Return a list of the URLs of those files.
524      * @param loader the class loader to get the class path from
525      */

526     public static Set JavaDoc<URL JavaDoc> findPersistenceArchives(ClassLoader JavaDoc loader){
527          Set JavaDoc<URL JavaDoc> parURLs = new HashSet JavaDoc<URL JavaDoc>();
528         try {
529             Enumeration JavaDoc<URL JavaDoc> resources = loader.getResources("META-INF/persistence.xml");
530             while (resources.hasMoreElements()){
531                 URL JavaDoc url = resources.nextElement();
532                 parURLs.add(url);
533             }
534         } catch (java.io.IOException JavaDoc exc){
535             throw PersistenceUnitLoadingException.exceptionSearchingForPersistenceResources(loader, exc);
536         }
537         return parURLs;
538     }
539
540   /**
541    * Return a list of all the names of classes stored in the jar stored at this URL.
542    * Classes are assumed to be located in the base directory of the jar.
543    * @param file
544    * @return
545    */

546     private static List JavaDoc<String JavaDoc> getClassNamesFromJar(URL JavaDoc url){
547         InputStream JavaDoc stream = null;
548         List JavaDoc persistentClasses = null;
549         IOException JavaDoc initialException;
550         try {
551             stream = createInputStreamForURL(url);
552             persistentClasses = findClassesInJar(stream);
553         } catch (IOException JavaDoc exc){
554             throw PersistenceUnitLoadingException.exceptionSearchingForEntities(url, exc);
555         } finally {
556             try{
557                 if (stream != null){
558                     stream.close();
559                 }
560             } catch (IOException JavaDoc exc){};
561         }
562         return persistentClasses;
563
564     }
565     
566     /**
567      * Convert the given input stream to a jar input stream and look through the entities for classes
568      * Return a list of those classes
569      * @param stream
570      * @return
571      * @throws IOException
572      */

573     private static List JavaDoc findClassesInJar(InputStream JavaDoc stream) throws IOException JavaDoc {
574         JarInputStream JavaDoc jarFile = null;
575         List JavaDoc persistentClasses = new Vector JavaDoc();
576         try{
577             jarFile = new JarInputStream JavaDoc(stream);
578             ZipEntry JavaDoc entry = jarFile.getNextEntry();
579             if (entry == null){
580                 return null;
581             }
582             while (entry != null){
583                 String JavaDoc classNameForLoader = buildClassNameFromEntryString(entry.getName());
584                  if (entry.getName().endsWith(".class")){
585                      persistentClasses.add(classNameForLoader);
586                 }
587                 entry = jarFile.getNextEntry();
588             }
589         } finally {
590             try{
591                 if (jarFile != null){
592                     jarFile.close();
593                 }
594             } catch (IOException JavaDoc exc){};
595         }
596         return persistentClasses;
597     }
598     
599   /**
600    * Return a list of class names from this URL. This will work either with directories
601    * or jar files and assume the classes are based in the base directory of the URL
602    * @param url
603    * @return
604    */

605     private static List JavaDoc<String JavaDoc> getClassNamesFromURL(URL JavaDoc url){
606         List JavaDoc classNames = null;
607         try {
608             classNames = getClassNamesFromJar(url);
609             if (classNames != null){
610                 return classNames;
611             }
612         } catch (Exception JavaDoc exception){
613             AbstractSessionLog.getLog().log(AbstractSessionLog.FINEST, JAR_OPENING_EXCEPTION, url, exception);
614         };
615         try{
616             // Only URL.toURI() handles spaces and special characters correctly
617
File JavaDoc file = new File JavaDoc(convertURLToURI(url));
618             if (file.isDirectory()){
619                 return getClassNamesFromDirectory(file);
620             }
621         } catch (Exception JavaDoc exception){
622             AbstractSessionLog.getLog().log(AbstractSessionLog.FINEST, DIRECTORY_OPENING_EXCEPTION, url, exception);
623         }
624         return null;
625     }
626
627   /**
628    * Return a list of the names of classes that are stored in this directory. Package
629    * name for the class will assume classes are based in the directoryURL
630    * @param file the File representation of this directory
631    * @return
632    */

633     private static List JavaDoc<String JavaDoc> getClassNamesFromDirectory(File JavaDoc file){
634         List JavaDoc classList = null;
635
636         if (!file.isDirectory()){
637             return null;
638         }
639         int initialDirectoryNameLength = file.getPath().length();
640         classList = findClassesInDirectory(file, initialDirectoryNameLength);
641         return classList;
642     }
643
644   /**
645    * Create a list of the classes that from a directory referenced by the given URL that return
646    * true from the isPersistent() call.
647    * @param file the File representation of this directory
648    * @param loader the ClassLoader to use
649    * @return
650    */

651     public static List JavaDoc<String JavaDoc> getPersistentClassNamesFromDirectory(File JavaDoc file, ClassLoader JavaDoc loader){
652         List JavaDoc<String JavaDoc> persistentClasses = new Vector JavaDoc<String JavaDoc>();
653         List JavaDoc<String JavaDoc> classList = getClassNamesFromDirectory(file);
654         for (String JavaDoc className: classList){
655             if (isClassPersistent(className, loader, false)){
656                 persistentClasses.add(className);
657             }
658         }
659         return persistentClasses;
660     }
661     
662   /**
663    * Return a list of persistent classes names accessible through a given URL
664    * If the URL refers to a .jar or .par file this method will look through the entries in
665    * the jar for the class files. If it refers to a directory, this method will recursively look
666    * for the classes in the directory.
667    * @param url
668    * @return
669    */

670     public static List JavaDoc getPersistentClassNamesFromURL(URL JavaDoc url, ClassLoader JavaDoc loader){
671         List JavaDoc classNames = null;
672         try {
673             classNames = getPersistentClassNamesFromJar(url, loader);
674             if (classNames != null){
675                 return classNames;
676             }
677         } catch (Exception JavaDoc exception){
678             AbstractSessionLog.getLog().log(AbstractSessionLog.FINEST, JAR_OPENING_EXCEPTION, url, exception);
679         };
680         try{
681             // Only URL.toURI() handles spaces and special characters correctly
682
File JavaDoc file = new File JavaDoc(convertURLToURI(url));
683             if (file.isDirectory()){
684                 classNames = getPersistentClassNamesFromDirectory(file, loader);
685                 if (classNames != null){
686                     return classNames;
687                 }
688             }
689         } catch (Exception JavaDoc exception){
690             AbstractSessionLog.getLog().log(AbstractSessionLog.FINEST, DIRECTORY_OPENING_EXCEPTION, url, exception);
691         };
692         throw PersistenceUnitLoadingException.couldNotGetClassNamesFromUrl(url);
693     }
694
695   /**
696    * Create a list of the classes that from the jar with the given name. That return
697    * true from the isPersistent() call.
698    * @param file the File representation of this jar
699    * @param loader the ClassLoader to use
700    * @return
701    */

702     public static List JavaDoc<String JavaDoc> getPersistentClassNamesFromJar(URL JavaDoc url, ClassLoader JavaDoc loader){
703         List JavaDoc<String JavaDoc> classList = getClassNamesFromJar(url);
704         if (classList == null){
705             return null;
706         }
707         List JavaDoc<String JavaDoc> persistentClasses = new Vector JavaDoc();
708         for (String JavaDoc className: classList){
709             if (isClassPersistent(className, loader, false)){
710                 persistentClasses.add(className);
711             }
712         }
713         return persistentClasses;
714     }
715
716   /**
717    * Return whether the class with the given name is persistent.
718    * A class is persistent if it is annotated with @Entity or @Embeddable.
719    * @param className
720    * @return
721    */

722     public static boolean isClassPersistent(String JavaDoc className, ClassLoader JavaDoc loader, boolean throwExceptionIfNotFound){
723         Class JavaDoc candidateClass = null;
724         try{
725             candidateClass = loader.loadClass(className);
726         } catch (ClassNotFoundException JavaDoc exc){
727             if (throwExceptionIfNotFound){
728                 throw PersistenceUnitLoadingException.exceptionLoadingClassWhileLookingForAnnotations(className, exc);
729             } else {
730                 AbstractSessionLog.getLog().log(AbstractSessionLog.WARNING, "persistence_unit_processor_error_loading_class", exc.getClass().getName(), exc.getLocalizedMessage() , className);
731                 return false;
732             }
733         } catch (Exception JavaDoc exception){
734             AbstractSessionLog.getLog().log(AbstractSessionLog.WARNING, "persistence_unit_processor_error_loading_class", exception.getClass().getName(), exception.getLocalizedMessage() , className);
735             return false;
736         }
737         return isClassPersistent(candidateClass);
738     }
739     /**
740     * Return whether a given class is persistent
741     * A class is persistent if it is annotated with @Entity.
742     * We don't consider Embeddable and MappedSuperclass classes as entities,
743     * because they are lazily processed when referenced from some entity class.
744     * @param candidateClass
745     * @return
746     */

747     public static boolean isClassPersistent(Class JavaDoc candidateClass){
748         if (candidateClass.isAnnotationPresent(javax.persistence.Entity.class)) {
749             return true;
750         }
751         return false;
752     }
753
754     /**
755     * Converts URL to a URI to handle spaces and special characters correctly.
756     * Validates the URL to represent a valid file name.
757     * @param url the URL to be converted
758     * @return the corresponding URI
759     */

760     private static URI JavaDoc convertURLToURI(URL JavaDoc url) {
761         String JavaDoc filePath = url.getFile();
762         if (filePath.equals("") || filePath == null) {
763                 throw PersistenceUnitLoadingException.filePathMissingException(filePath);
764         }
765
766         URI JavaDoc uri = null;
767         try {
768             // attempt to use url.toURI since it will deal with all urls without special characters
769
// and URISyntaxException allows us to catch issues with special characters
770
// this will handle URLs what already have special characters replaced such as URLS
771
// derived from searches for persistence.xml on the Java System class loader
772
uri = url.toURI();
773         } catch (URISyntaxException JavaDoc e) {
774             try{
775                 // use multi-argument constructor for URI since single-argument constructor and URL.toURI() do not deal with special characters in path
776
uri = new URI JavaDoc(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), null);
777             } catch (URISyntaxException JavaDoc exc){};
778             if (uri == null){
779                 throw PersistenceUnitLoadingException.exceptionProcessingPersistenceUnit(url, e);
780             }
781         }
782
783         return uri;
784     }
785
786 }
787
Popular Tags