001: package com.bm.ejb3metadata.annotations.analyzer;
002:
003: import java.io.File;
004: import java.io.FileInputStream;
005: import java.io.FileNotFoundException;
006: import java.io.IOException;
007: import java.io.InputStream;
008: import java.util.Enumeration;
009: import java.util.jar.JarFile;
010: import java.util.zip.ZipEntry;
011:
012: import org.ejb3unit.asm.ClassReader;
013:
014: import com.bm.ejb3metadata.annotations.exceptions.AnalyzerException;
015: import com.bm.ejb3metadata.annotations.metadata.EjbJarAnnotationMetadata;
016:
017: /**
018: * This class finds the annotated class and fill metadata class.
019: *
020: * @author Daniel Wiese
021: */
022: public class AnnotationDeploymentAnalyzer {
023:
024: private static final org.apache.log4j.Logger logger = org.apache.log4j.Logger
025: .getLogger(AnnotationDeploymentAnalyzer.class);
026:
027: /**
028: * Archive which will be analyzed.
029: */
030: private File archive = null;
031:
032: /**
033: * Metadata representing the parsed ejb-jar file.
034: */
035: private EjbJarAnnotationMetadata ejbJarAnnotationMetadata = null;
036:
037: /**
038: * ASM visitor used to visit classes.
039: */
040: private ScanClassVisitor scanVisitor = null;
041:
042: /**
043: * Constructor.<br>
044: * Archive which will be used when analyzing.
045: *
046: * @param archive
047: * the archive to analyze.
048: */
049: public AnnotationDeploymentAnalyzer(final File archive) {
050: this .archive = archive;
051: this .ejbJarAnnotationMetadata = new EjbJarAnnotationMetadata();
052: scanVisitor = new ScanClassVisitor(ejbJarAnnotationMetadata);
053: }
054:
055: /**
056: * Analyzes the archive and fill metadata struct.
057: *
058: * @throws AnalyzerException
059: * if analyze of archive fails
060: */
061: public void analyze() throws AnalyzerException {
062:
063: // two cases :
064: // - archive is a jar file
065: // - archive is an exploded directory
066:
067: if (archive.isFile()) {
068: scanJarArchive();
069: } else {
070: // exploded mode
071: // need recursion on all directories of the archive
072: scanDirectory(archive);
073: }
074: }
075:
076: /**
077: * Scan all classes from the archive which is a jar file.
078: *
079: * @throws AnalyzerException
080: * if scan is aborted.
081: */
082: private void scanJarArchive() throws AnalyzerException {
083: JarFile jarFile;
084: try {
085: jarFile = new JarFile(archive);
086: } catch (IOException ioe) {
087: throw new AnalyzerException(
088: "Cannot build jar file on archive '" + archive
089: + "'.", ioe);
090: }
091: Enumeration<? extends ZipEntry> en = jarFile.entries();
092: while (en.hasMoreElements()) {
093: ZipEntry e = en.nextElement();
094: String name = e.getName();
095: // iterate through the jar file
096: if (name.toLowerCase().endsWith(".class")) {
097: try {
098: new ClassReader(jarFile.getInputStream(e)).accept(
099: scanVisitor, ClassReader.SKIP_CODE);
100: } catch (Exception ioe) {
101: throw new AnalyzerException(
102: "Error while analyzing file entry '" + name
103: + "' in jar file '" + archive + "'",
104: ioe);
105: }
106:
107: }
108: }
109: try {
110: jarFile.close();
111: } catch (IOException ioe) {
112: logger.warn("Error while trying to close the file '"
113: + jarFile + "'", ioe);
114: }
115:
116: }
117:
118: /**
119: * Scan (recursively) all classes from the given directory. It starts with
120: * the archive root directory first.
121: *
122: * @param directory
123: * the directory in which proceed all classes.
124: * @throws AnalyzerException
125: * if analyzer fails to scan classes.
126: */
127: private void scanDirectory(final File directory)
128: throws AnalyzerException {
129: File[] files = directory.listFiles();
130: for (File f : files) {
131: // scan .class file
132: if (f.isFile()
133: && f.getName().toLowerCase().endsWith(".class")) {
134: InputStream is = null;
135: try {
136: is = new FileInputStream(f);
137: } catch (FileNotFoundException e) {
138: throw new AnalyzerException(
139: "Cannot read input stream from '"
140: + f.getAbsolutePath() + "'.", e);
141: }
142: try {
143: new ClassReader(is).accept(scanVisitor,
144: ClassReader.SKIP_CODE);
145: } catch (Exception e) {
146: throw new AnalyzerException(
147: "Cannot launch class visitor on the file '"
148: + f.getAbsolutePath() + "'.", e);
149: }
150: try {
151: is.close();
152: } catch (IOException e) {
153: throw new AnalyzerException(
154: "Cannot close input stream on the file '"
155: + f.getAbsolutePath() + "'.", e);
156: }
157: } else {
158: // loop on childs
159: if (f.isDirectory()) {
160: scanDirectory(f);
161: }
162: }
163: }
164: }
165:
166: /**
167: * struct (metadata) filled by this analyzer.
168: *
169: * @return struct (metadata) filled by this analyzer
170: */
171: public EjbJarAnnotationMetadata getEjbJarAnnotationMetadata() {
172: return ejbJarAnnotationMetadata;
173: }
174:
175: }
|