001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.openjpa.meta;
020:
021: import java.io.File;
022: import java.io.FileNotFoundException;
023: import java.io.IOException;
024: import java.io.InputStream;
025: import java.net.MalformedURLException;
026: import java.net.URL;
027: import java.security.AccessController;
028: import java.security.PrivilegedActionException;
029: import java.util.ArrayList;
030: import java.util.Arrays;
031: import java.util.Collection;
032: import java.util.HashMap;
033: import java.util.HashSet;
034: import java.util.Iterator;
035: import java.util.List;
036: import java.util.Map;
037: import java.util.Set;
038: import java.util.zip.ZipFile;
039: import java.util.zip.ZipInputStream;
040:
041: import org.apache.commons.lang.StringUtils;
042: import org.apache.openjpa.lib.meta.ClassArgParser;
043: import org.apache.openjpa.lib.meta.ClasspathMetaDataIterator;
044: import org.apache.openjpa.lib.meta.FileMetaDataIterator;
045: import org.apache.openjpa.lib.meta.MetaDataFilter;
046: import org.apache.openjpa.lib.meta.MetaDataIterator;
047: import org.apache.openjpa.lib.meta.MetaDataParser;
048: import org.apache.openjpa.lib.meta.MetaDataSerializer;
049: import org.apache.openjpa.lib.meta.ResourceMetaDataIterator;
050: import org.apache.openjpa.lib.meta.URLMetaDataIterator;
051: import org.apache.openjpa.lib.meta.ZipFileMetaDataIterator;
052: import org.apache.openjpa.lib.meta.ZipStreamMetaDataIterator;
053: import org.apache.openjpa.lib.util.Files;
054: import org.apache.openjpa.lib.util.J2DoPrivHelper;
055: import org.apache.openjpa.lib.util.Localizer;
056: import org.apache.openjpa.util.GeneralException;
057: import org.apache.openjpa.util.UserException;
058: import serp.util.Strings;
059:
060: /**
061: * Base class for factory implementations built around XML metadata files
062: * in the common fomat.
063: *
064: * @author Abe White
065: * @since 0.4.0
066: */
067: public abstract class AbstractCFMetaDataFactory extends
068: AbstractMetaDataFactory {
069:
070: private static final Localizer _loc = Localizer
071: .forPackage(AbstractMetaDataFactory.class);
072:
073: protected Collection files = null;
074: protected Collection urls = null;
075: protected Collection rsrcs = null;
076: protected Collection cpath = null;
077:
078: private Set _typeNames = null;
079:
080: /**
081: * Set of {@link File}s of metadata files or directories supplied by user.
082: */
083: public void setFiles(Collection files) {
084: this .files = files;
085: }
086:
087: /**
088: * Set of semicolon-separated {@link File}s of metadata files or
089: * directories supplied by user via auto-configuration.
090: */
091: public void setFiles(String files) {
092: if (StringUtils.isEmpty(files))
093: this .files = null;
094: else {
095: String[] strs = Strings.split(files, ";", 0);
096: this .files = new HashSet((int) (strs.length * 1.33 + 1));
097:
098: File file;
099: for (int i = 0; i < strs.length; i++) {
100: file = new File(strs[i]);
101: if (((Boolean) AccessController
102: .doPrivileged(J2DoPrivHelper.existsAction(file)))
103: .booleanValue())
104: this .files.add(file);
105: }
106: }
107: }
108:
109: /**
110: * Set of {@link URL}s of metadata files or jars supplied by user.
111: */
112: public void setURLs(Collection urls) {
113: this .urls = urls;
114: }
115:
116: /**
117: * Set of semicolon-separated {@link URL}s of metadata files or jars
118: * supplied by user via auto-configuration.
119: */
120: public void setURLs(String urls) {
121: if (StringUtils.isEmpty(urls))
122: this .urls = null;
123: else {
124: String[] strs = Strings.split(urls, ";", 0);
125: this .urls = new HashSet((int) (strs.length * 1.33 + 1));
126: try {
127: for (int i = 0; i < strs.length; i++)
128: this .urls.add(new URL(strs[i]));
129: } catch (MalformedURLException mue) {
130: throw new UserException(mue);
131: }
132: }
133: }
134:
135: /**
136: * Set of resource paths of metadata files or jars supplied by user.
137: */
138: public void setResources(Collection rsrcs) {
139: this .rsrcs = rsrcs;
140: }
141:
142: /**
143: * Set of semicolon-separated resource paths of metadata files or jars
144: * supplied by user via auto-configuration.
145: */
146: public void setResources(String rsrcs) {
147: // keep list mutable so subclasses can add implicit locations
148: this .rsrcs = (StringUtils.isEmpty(rsrcs)) ? null
149: : new ArrayList(Arrays.asList(Strings.split(rsrcs, ";",
150: 0)));
151: }
152:
153: /**
154: * Set of classpath directories or jars to scan for metadata supplied
155: * by user.
156: */
157: public void setClasspathScan(Collection cpath) {
158: this .cpath = cpath;
159: }
160:
161: /**
162: * Set of classpath directories or jars to scan for metadata supplied
163: * by user via auto-configuration.
164: */
165: public void setClasspathScan(String cpath) {
166: // keep list mutable so subclasses can add implicit locations
167: this .cpath = (StringUtils.isEmpty(cpath)) ? null
168: : new ArrayList(Arrays.asList(Strings.split(cpath, ";",
169: 0)));
170: }
171:
172: public boolean store(ClassMetaData[] metas,
173: QueryMetaData[] queries, SequenceMetaData[] seqs, int mode,
174: Map output) {
175: if (mode == MODE_NONE)
176: return true;
177: if (isMappingOnlyFactory() && (mode & MODE_MAPPING) == 0)
178: return true;
179:
180: if (!strict && (mode & MODE_META) != 0)
181: mode |= MODE_MAPPING;
182: Class cls = (metas.length == 0) ? null : metas[0]
183: .getDescribedType();
184: ClassLoader loader = repos.getConfiguration()
185: .getClassResolverInstance().getClassLoader(cls, null);
186: Map clsNames = new HashMap((int) (metas.length * 1.33 + 1));
187: for (int i = 0; i < metas.length; i++)
188: clsNames.put(metas[i].getDescribedType().getName(),
189: metas[i]);
190:
191: // assign default files if in metadata mode (in other modes we assume
192: // the files would have to be read already to create the metadatas)
193: Set metaFiles = null;
194: Set queryFiles = null;
195: if (isMappingOnlyFactory() || (mode & MODE_META) != 0)
196: metaFiles = assignDefaultMetaDataFiles(metas, queries,
197: seqs, mode, clsNames);
198: if (!isMappingOnlyFactory() && (mode & MODE_QUERY) != 0)
199: queryFiles = assignDefaultQueryFiles(queries, clsNames);
200:
201: // parse all files to be sure we don't delete existing metadata when
202: // writing out new metadata, then serialize
203: Serializer ser;
204: Parser parser;
205: if (mode != MODE_QUERY) {
206: int sermode = (isMappingOnlyFactory()) ? mode : mode
207: | MODE_META;
208: if ((mode & MODE_ANN_MAPPING) != 0)
209: ser = newAnnotationSerializer();
210: else
211: ser = newSerializer();
212: ser.setMode(sermode);
213: if (metaFiles != null) {
214: parser = newParser(false);
215: parser.setMode(sermode);
216: parser.setClassLoader(loader);
217: parse(parser, metaFiles);
218:
219: MetaDataRepository pr = parser.getRepository();
220: pr.setSourceMode(mode);
221: if (isMappingOnlyFactory())
222: pr.setResolve(MODE_NONE);
223: else
224: pr.setResolve(MODE_MAPPING, false);
225: ser.addAll(pr);
226: }
227:
228: for (int i = 0; i < metas.length; i++)
229: ser.addMetaData(metas[i]);
230: if ((mode & MODE_MAPPING) != 0)
231: for (int i = 0; i < seqs.length; i++)
232: ser.addSequenceMetaData(seqs[i]);
233: for (int i = 0; i < queries.length; i++)
234: if (queries[i].getSourceMode() != MODE_QUERY
235: && (queries[i].getSourceMode() & mode) != 0)
236: ser.addQueryMetaData(queries[i]);
237:
238: int flags = ser.PRETTY;
239: if ((store & STORE_VERBOSE) != 0)
240: flags |= ser.VERBOSE;
241: serialize(ser, output, flags);
242: }
243:
244: // do we have any queries stored in query files?
245: if (!isMappingOnlyFactory()) {
246: boolean qFiles = queryFiles != null;
247: for (int i = 0; !qFiles && i < queries.length; i++)
248: qFiles = queries[i].getSourceMode() == MODE_QUERY;
249: if (qFiles) {
250: if ((mode & MODE_ANN_MAPPING) != 0)
251: ser = newAnnotationSerializer();
252: else
253: ser = newSerializer();
254: ser.setMode(MODE_QUERY);
255: if (queryFiles != null) {
256: parser = newParser(false);
257: parser.setMode(MODE_QUERY);
258: parser.setClassLoader(loader);
259: parse(parser, queryFiles);
260: ser.addAll(parser.getRepository());
261: }
262: for (int i = 0; i < queries.length; i++)
263: if (queries[i].getSourceMode() == MODE_QUERY)
264: ser.addQueryMetaData(queries[i]);
265: serialize(ser, output, ser.PRETTY);
266: }
267: }
268: return true;
269: }
270:
271: public boolean drop(Class[] cls, int mode, ClassLoader envLoader) {
272: if (mode == MODE_NONE)
273: return true;
274: if (isMappingOnlyFactory() && (mode & MODE_MAPPING) == 0)
275: return true;
276:
277: Parser parser = newParser(false);
278: MetaDataRepository pr = parser.getRepository();
279: pr.setSourceMode(MODE_MAPPING, false);
280: pr.setResolve(MODE_MAPPING, false);
281:
282: // parse metadata for all these classes
283: if ((mode & (MODE_META | MODE_MAPPING)) != 0) {
284: parser.setMode((isMappingOnlyFactory()) ? mode : MODE_META
285: | MODE_MAPPING | MODE_QUERY);
286: parse(parser, cls);
287: }
288: if (!isMappingOnlyFactory() && (mode & MODE_QUERY) != 0) {
289: parser.setMode(MODE_QUERY);
290: parse(parser, cls);
291: }
292:
293: // remove metadatas from repository or clear their mappings
294: Set files = new HashSet();
295: Set clsNames = null;
296: if ((mode & (MODE_META | MODE_MAPPING)) != 0) {
297: clsNames = new HashSet((int) (cls.length * 1.33 + 1));
298: ClassMetaData meta;
299: for (int i = 0; i < cls.length; i++) {
300: if (cls[i] == null)
301: clsNames.add(null);
302: else
303: clsNames.add(cls[i].getName());
304: meta = pr.getMetaData(cls[i], envLoader, false);
305: if (meta != null) {
306: if (getSourceFile(meta) != null)
307: files.add(getSourceFile(meta));
308: if ((mode & MODE_META) != 0)
309: pr.removeMetaData(meta);
310: else if (!isMappingOnlyFactory())
311: clearMapping(meta);
312: }
313: }
314: }
315:
316: // remove query mode metadatas so we can store them separately
317: QueryMetaData[] queries = pr.getQueryMetaDatas();
318: List qqs = (!isMappingOnlyFactory() && (mode & MODE_QUERY) == 0) ? null
319: : new ArrayList();
320: boolean rem;
321: Class def;
322: for (int i = 0; i < queries.length; i++) {
323: if (!isMappingOnlyFactory()
324: && queries[i].getSourceFile() != null)
325: files.add(queries[i].getSourceFile());
326: def = queries[i].getDefiningType();
327: rem = (queries[i].getSourceMode() & mode) != 0
328: && clsNames.contains((def == null) ? null : def
329: .getName());
330: if (rem
331: || (!isMappingOnlyFactory() && queries[i]
332: .getSourceMode() == MODE_QUERY))
333: pr.removeQueryMetaData(queries[i]);
334: if (qqs != null && queries[i].getSourceMode() == MODE_QUERY
335: && !rem)
336: qqs.add(queries[i]);
337: }
338:
339: // write new metadata without removed instances
340: backupAndDelete(files);
341: Serializer ser;
342: if ((mode & (MODE_META | MODE_MAPPING)) != 0) {
343: ser = newSerializer();
344: ser.setMode((isMappingOnlyFactory()) ? mode : mode
345: | MODE_META);
346: ser.addAll(pr);
347: // remove from serializer rather than from repository above so that
348: // calling code can take advantage of metadata still in repos
349: if (isMappingOnlyFactory())
350: for (int i = 0; i < cls.length; i++)
351: ser.removeMetaData(pr.getMetaData(cls[i],
352: envLoader, false));
353: serialize(ser, null, ser.PRETTY);
354: }
355: if (qqs != null && !qqs.isEmpty()) {
356: ser = newSerializer();
357: ser.setMode(MODE_QUERY);
358: for (int i = 0; i < qqs.size(); i++)
359: ser.addQueryMetaData((QueryMetaData) qqs.get(i));
360: serialize(ser, null, ser.PRETTY);
361: }
362: return true;
363: }
364:
365: /**
366: * Assign default source files to the given metadatas.
367: *
368: * @param clsNames map of class names to metadatas
369: * @return set of existing files used by these metadatas, or
370: * null if no existing files
371: */
372: private Set assignDefaultMetaDataFiles(ClassMetaData[] metas,
373: QueryMetaData[] queries, SequenceMetaData[] seqs, int mode,
374: Map clsNames) {
375: Set files = null;
376: for (int i = 0; i < metas.length; i++) {
377: if (getSourceFile(metas[i]) == null)
378: setSourceFile(metas[i], defaultSourceFile(metas[i]));
379: if (((Boolean) AccessController.doPrivileged(J2DoPrivHelper
380: .existsAction(getSourceFile(metas[i]))))
381: .booleanValue()) {
382: if (files == null)
383: files = new HashSet();
384: files.add(getSourceFile(metas[i]));
385: }
386: }
387: for (int i = 0; i < queries.length; i++) {
388: if (queries[i].getSourceMode() == MODE_QUERY
389: || (mode & queries[i].getSourceMode()) == 0)
390: continue;
391: if (queries[i].getSourceFile() == null)
392: queries[i].setSource(defaultSourceFile(queries[i],
393: clsNames), queries[i].getSourceScope(),
394: queries[i].getSourceType());
395: if (((Boolean) AccessController.doPrivileged(J2DoPrivHelper
396: .existsAction(queries[i].getSourceFile())))
397: .booleanValue()) {
398: if (files == null)
399: files = new HashSet();
400: files.add(queries[i].getSourceFile());
401: }
402: }
403: if ((mode & MODE_MAPPING) != 0) {
404: for (int i = 0; i < seqs.length; i++) {
405: if (getSourceFile(seqs[i]) == null)
406: setSourceFile(seqs[i], defaultSourceFile(seqs[i],
407: clsNames));
408: if (((Boolean) AccessController
409: .doPrivileged(J2DoPrivHelper
410: .existsAction(getSourceFile(seqs[i]))))
411: .booleanValue()) {
412: if (files == null)
413: files = new HashSet();
414: files.add(getSourceFile(seqs[i]));
415: }
416: }
417: }
418: return files;
419: }
420:
421: /**
422: * Assign default source files to the given queries.
423: *
424: * @param clsNames map of class names to metadatas
425: * @return set of existing files used by these metadatas, or
426: * null if no existing files
427: */
428: private Set assignDefaultQueryFiles(QueryMetaData[] queries,
429: Map clsNames) {
430: Set files = null;
431: for (int i = 0; i < queries.length; i++) {
432: if (queries[i].getSourceMode() != MODE_QUERY)
433: continue;
434: if (queries[i].getSourceFile() == null)
435: queries[i].setSource(defaultSourceFile(queries[i],
436: clsNames), queries[i].getSourceScope(),
437: queries[i].getSourceType());
438: if (((Boolean) AccessController.doPrivileged(J2DoPrivHelper
439: .existsAction(queries[i].getSourceFile())))
440: .booleanValue()) {
441: if (files == null)
442: files = new HashSet();
443: files.add(queries[i].getSourceFile());
444: }
445: }
446: return files;
447: }
448:
449: /**
450: * Return true if this factory deals only with mapping data, and relies
451: * on a separate factory for metadata.
452: */
453: protected boolean isMappingOnlyFactory() {
454: return false;
455: }
456:
457: /**
458: * Parse all given files.
459: */
460: protected void parse(MetaDataParser parser, Collection files) {
461: try {
462: for (Iterator itr = files.iterator(); itr.hasNext();)
463: parser.parse((File) itr.next());
464: } catch (IOException ioe) {
465: throw new GeneralException(ioe);
466: }
467: }
468:
469: /**
470: * Parse all given classses.
471: */
472: protected void parse(MetaDataParser parser, Class[] cls) {
473: try {
474: for (int i = 0; i < cls.length; i++)
475: parser.parse(cls[i], isParseTopDown());
476: } catch (IOException ioe) {
477: throw new GeneralException(ioe);
478: }
479: }
480:
481: /**
482: * Whether to parse classes top down. Defaults to false.
483: */
484: protected boolean isParseTopDown() {
485: return false;
486: }
487:
488: /**
489: * Tell the given serialier to write its metadatas.
490: */
491: protected void serialize(MetaDataSerializer ser, Map output,
492: int flags) {
493: try {
494: if (output == null)
495: ser.serialize(flags);
496: else
497: ser.serialize(output, flags);
498: } catch (IOException ioe) {
499: throw new GeneralException(ioe);
500: }
501: }
502:
503: /**
504: * Backup and delete the source files for the given metadatas.
505: */
506: protected void backupAndDelete(Collection files) {
507: File file;
508: for (Iterator itr = files.iterator(); itr.hasNext();) {
509: file = (File) itr.next();
510: if (Files.backup(file, false) != null)
511: AccessController.doPrivileged(J2DoPrivHelper
512: .deleteAction(file));
513: }
514: }
515:
516: /**
517: * Clear mapping information from the given metadata.
518: */
519: protected void clearMapping(ClassMetaData meta) {
520: meta.setSourceMode(MODE_MAPPING, false);
521: }
522:
523: /**
524: * Return the current source file of the given metadata.
525: */
526: protected File getSourceFile(ClassMetaData meta) {
527: return meta.getSourceFile();
528: }
529:
530: /**
531: * Set the current source file of the given metadata.
532: */
533: protected void setSourceFile(ClassMetaData meta, File sourceFile) {
534: meta.setSource(sourceFile, meta.getSourceType());
535: }
536:
537: /**
538: * Return the current source file of the given metadata.
539: */
540: protected File getSourceFile(SequenceMetaData meta) {
541: return meta.getSourceFile();
542: }
543:
544: /**
545: * Set the current source file of the given metadata.
546: */
547: protected void setSourceFile(SequenceMetaData meta, File sourceFile) {
548: meta.setSource(sourceFile, meta.getSourceScope(), meta
549: .getSourceType());
550: }
551:
552: /**
553: * Return the default file for the given metadata.
554: */
555: protected abstract File defaultSourceFile(ClassMetaData meta);
556:
557: /**
558: * Return a default file for the given query.
559: */
560: protected abstract File defaultSourceFile(QueryMetaData query,
561: Map clsNames);
562:
563: /**
564: * Return a default file for the given sequence.
565: */
566: protected abstract File defaultSourceFile(SequenceMetaData seq,
567: Map clsNames);
568:
569: /**
570: * Create a new metadata parser.
571: *
572: * @param loading if true, this will be the cached parser used for
573: * loading metadata
574: */
575: protected abstract Parser newParser(boolean loading);
576:
577: /**
578: * Create a new metadata serializer.
579: */
580: protected abstract Serializer newSerializer();
581:
582: /**
583: * Create a new annotation metadata serializer.
584: */
585: protected abstract Serializer newAnnotationSerializer();
586:
587: /**
588: * Return the metadata that defines the given query, if any.
589: *
590: * @param clsNames map of class names to metadatas
591: */
592: protected ClassMetaData getDefiningMetaData(QueryMetaData query,
593: Map clsNames) {
594: Class def = query.getDefiningType();
595: if (def != null)
596: return (ClassMetaData) clsNames.get(def.getName());
597:
598: Map.Entry entry;
599: String pkg;
600: for (Iterator itr = clsNames.entrySet().iterator(); itr
601: .hasNext();) {
602: entry = (Map.Entry) itr.next();
603: pkg = Strings.getPackageName((String) entry.getKey());
604: if (pkg.length() == 0)
605: return (ClassMetaData) entry.getValue();
606: }
607: return null;
608: }
609:
610: public Set getPersistentTypeNames(boolean devpath,
611: ClassLoader envLoader) {
612: // some configured locations might be implicit in spec, so return
613: // null if we don't find any classes, rather than if we don't have
614: // any locations
615: if (_typeNames != null)
616: return (_typeNames.isEmpty()) ? null : _typeNames;
617:
618: try {
619: ClassLoader loader = repos.getConfiguration()
620: .getClassResolverInstance().getClassLoader(
621: getClass(), envLoader);
622: long start = System.currentTimeMillis();
623:
624: Set names = parsePersistentTypeNames(loader);
625: if (names.isEmpty() && devpath)
626: scan(new ClasspathMetaDataIterator(null,
627: newMetaDataFilter()), newClassArgParser(),
628: names, false, null);
629: else
630: // we don't cache a full dev cp scan
631: _typeNames = names;
632:
633: if (log.isTraceEnabled())
634: log.trace(_loc.get("found-pcs", String.valueOf(names
635: .size()), String.valueOf(System
636: .currentTimeMillis()
637: - start)));
638: return (names.isEmpty()) ? null : names;
639: } catch (IOException ioe) {
640: throw new GeneralException(ioe);
641: }
642: }
643:
644: /**
645: * Parse persistent type names.
646: */
647: private Set parsePersistentTypeNames(ClassLoader loader)
648: throws IOException {
649: ClassArgParser cparser = newClassArgParser();
650: String[] clss;
651: Set names = new HashSet();
652: if (files != null) {
653: File file;
654: for (Iterator itr = files.iterator(); itr.hasNext();) {
655: file = (File) itr.next();
656: if (((Boolean) AccessController
657: .doPrivileged(J2DoPrivHelper
658: .isDirectoryAction(file)))
659: .booleanValue()) {
660: if (log.isTraceEnabled())
661: log.trace(_loc.get("scanning-directory", file));
662: scan(new FileMetaDataIterator(file,
663: newMetaDataFilter()), cparser, names, true,
664: file);
665: } else if (file.getName().endsWith(".jar")) {
666: if (log.isTraceEnabled())
667: log.trace(_loc.get("scanning-jar", file));
668: try {
669: ZipFile zFile = (ZipFile) AccessController
670: .doPrivileged(J2DoPrivHelper
671: .newZipFileAction(file));
672: scan(new ZipFileMetaDataIterator(zFile,
673: newMetaDataFilter()), cparser, names,
674: true, file);
675: } catch (PrivilegedActionException pae) {
676: throw (IOException) pae.getException();
677: }
678: } else {
679: if (log.isTraceEnabled())
680: log.trace(_loc.get("scanning-file", file));
681: clss = cparser
682: .parseTypeNames(new FileMetaDataIterator(
683: file));
684: if (log.isTraceEnabled())
685: log.trace(_loc.get("scan-found-names", clss,
686: file));
687: names.addAll(Arrays.asList(clss));
688: File f = (File) AccessController
689: .doPrivileged(J2DoPrivHelper
690: .getAbsoluteFileAction(file));
691: try {
692: mapPersistentTypeNames(AccessController
693: .doPrivileged(J2DoPrivHelper
694: .toURLAction(f)), clss);
695: } catch (PrivilegedActionException pae) {
696: throw (FileNotFoundException) pae
697: .getException();
698: }
699: }
700: }
701: }
702: URL url;
703: if (urls != null) {
704: for (Iterator itr = urls.iterator(); itr.hasNext();) {
705: url = (URL) itr.next();
706: if ("file".equals(url.getProtocol())) {
707: File file = (File) AccessController
708: .doPrivileged(J2DoPrivHelper
709: .getAbsoluteFileAction(new File(url
710: .getFile())));
711: if (files != null && files.contains(file)) {
712: continue;
713: } else if (((Boolean) AccessController
714: .doPrivileged(J2DoPrivHelper
715: .isDirectoryAction(file)))
716: .booleanValue()) {
717: if (log.isTraceEnabled())
718: log.trace(_loc.get("scanning-directory",
719: file));
720: scan(new FileMetaDataIterator(file,
721: newMetaDataFilter()), cparser, names,
722: true, file);
723: continue;
724: }
725: }
726: if ("jar".equals(url.getProtocol())
727: && url.getPath().endsWith("!/")) {
728: if (log.isTraceEnabled())
729: log.trace(_loc.get("scanning-jar-url", url));
730: scan(new ZipFileMetaDataIterator(url,
731: newMetaDataFilter()), cparser, names, true,
732: url);
733: } else if (url.getPath().endsWith(".jar")) {
734: if (log.isTraceEnabled())
735: log.trace(_loc.get("scanning-jar-at-url", url));
736: try {
737: InputStream is = (InputStream) AccessController
738: .doPrivileged(J2DoPrivHelper
739: .openStreamAction(url));
740: scan(new ZipStreamMetaDataIterator(
741: new ZipInputStream(is),
742: newMetaDataFilter()), cparser, names,
743: true, url);
744: } catch (PrivilegedActionException pae) {
745: throw (IOException) pae.getException();
746: }
747: } else {
748: if (log.isTraceEnabled())
749: log.trace(_loc.get("scanning-url", url));
750: clss = cparser
751: .parseTypeNames(new URLMetaDataIterator(url));
752: if (log.isTraceEnabled())
753: log.trace(_loc.get("scan-found-names", clss,
754: url));
755: names.addAll(Arrays.asList(clss));
756: mapPersistentTypeNames(url, clss);
757: }
758: }
759: }
760: if (rsrcs != null) {
761: String rsrc;
762: MetaDataIterator mitr;
763: for (Iterator itr = rsrcs.iterator(); itr.hasNext();) {
764: rsrc = (String) itr.next();
765: if (rsrc.endsWith(".jar")) {
766: url = (URL) AccessController
767: .doPrivileged(J2DoPrivHelper
768: .getResourceAction(loader, rsrc));
769: if (url != null) {
770: if (log.isTraceEnabled())
771: log.trace(_loc.get(
772: "scanning-jar-stream-url", url));
773: try {
774: InputStream is = (InputStream) AccessController
775: .doPrivileged(J2DoPrivHelper
776: .openStreamAction(url));
777: scan(new ZipStreamMetaDataIterator(
778: new ZipInputStream(is),
779: newMetaDataFilter()), cparser,
780: names, true, url);
781: } catch (PrivilegedActionException pae) {
782: throw (IOException) pae.getException();
783: }
784: }
785: } else {
786: if (log.isTraceEnabled())
787: log.trace(_loc.get("scanning-resource", rsrc));
788: mitr = new ResourceMetaDataIterator(rsrc, loader);
789: while (mitr.hasNext()) {
790: url = (URL) mitr.next();
791: clss = cparser
792: .parseTypeNames(new URLMetaDataIterator(
793: url));
794: if (log.isTraceEnabled())
795: log.trace(_loc.get("scan-found-names",
796: clss, rsrc));
797: names.addAll(Arrays.asList(clss));
798: mapPersistentTypeNames(url, clss);
799: }
800: mitr.close();
801: }
802: }
803: }
804: if (cpath != null) {
805: String[] dirs = (String[]) cpath.toArray(new String[cpath
806: .size()]);
807: scan(new ClasspathMetaDataIterator(dirs,
808: newMetaDataFilter()), cparser, names, true, dirs);
809: }
810: if (types != null)
811: names.addAll(types);
812:
813: if (log.isTraceEnabled())
814: log.trace(_loc.get("parse-found-names", names));
815:
816: return names;
817: }
818:
819: /**
820: * Scan for persistent type names using the given metadata iterator.
821: */
822: private void scan(MetaDataIterator mitr, ClassArgParser cparser,
823: Set names, boolean mapNames, Object debugContext)
824: throws IOException {
825: Map map;
826: try {
827: map = cparser.mapTypeNames(mitr);
828: } finally {
829: mitr.close();
830: }
831:
832: Map.Entry entry;
833: for (Iterator itr = map.entrySet().iterator(); itr.hasNext();) {
834: entry = (Map.Entry) itr.next();
835: if (mapNames)
836: mapPersistentTypeNames(entry.getKey(), (String[]) entry
837: .getValue());
838: List newNames = Arrays.asList((String[]) entry.getValue());
839: if (log.isTraceEnabled())
840: log.trace(_loc.get("scan-found-names", newNames,
841: debugContext));
842: names.addAll(newNames);
843: }
844: }
845:
846: /**
847: * Implement this method to map metadata resources to the persistent
848: * types contained within them. The method will be called when
849: * {@link #getPersistentTypeNames} is invoked.
850: */
851: protected void mapPersistentTypeNames(Object rsrc, String[] names) {
852: }
853:
854: /**
855: * Return a metadata filter that identifies metadata resources when
856: * performing jar and classpath scans.
857: */
858: protected abstract MetaDataFilter newMetaDataFilter();
859:
860: public void clear() {
861: super .clear();
862: _typeNames = null;
863: }
864:
865: /**
866: * Internal parser interface.
867: */
868: public static interface Parser extends MetaDataParser {
869:
870: /**
871: * Returns the repository for this parser. If none has been set,
872: * creates a new repository and sets it.
873: */
874: public MetaDataRepository getRepository();
875:
876: /**
877: * The parse mode according to the expected document type.
878: */
879: public void setMode(int mode);
880: }
881:
882: /**
883: * Internal serializer interface.
884: */
885: public static interface Serializer extends MetaDataSerializer {
886:
887: /**
888: * The serialization mode according to the expected document type. The
889: * mode constants act as bit flags, and therefore can be combined.
890: */
891: public void setMode(int mode);
892:
893: /**
894: * Add a class meta data to the set to be serialized.
895: */
896: public void addMetaData(ClassMetaData meta);
897:
898: /**
899: * Remove a class meta data from the set to be serialized.
900: */
901: public boolean removeMetaData(ClassMetaData meta);
902:
903: /**
904: * Add a sequence meta data to the set to be serialized.
905: */
906: public void addSequenceMetaData(SequenceMetaData meta);
907:
908: /**
909: * Add a query meta data to the set to be serialized.
910: */
911: public void addQueryMetaData(QueryMetaData meta);
912:
913: /**
914: * Add all components in the given repository to the set to be
915: * serialized.
916: */
917: public void addAll(MetaDataRepository repos);
918: }
919: }
|