001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.loader.enhancer;
031:
032: import java.io.*;
033: import java.net.URL;
034: import java.util.*;
035: import java.util.logging.*;
036: import java.util.zip.*;
037:
038: import com.caucho.bytecode.ByteCodeClassMatcher;
039: import com.caucho.bytecode.ByteCodeClassScanner;
040: import com.caucho.loader.EnvironmentClassLoader;
041: import com.caucho.util.CharBuffer;
042: import com.caucho.vfs.*;
043:
044: /**
045: * Interface for a scan manager
046: */
047: public class ScanManager {
048: private static final Logger log = Logger
049: .getLogger(ScanManager.class.getName());
050:
051: private final ScanListener[] _listeners;
052:
053: public ScanManager(ArrayList<ScanListener> listeners) {
054: _listeners = new ScanListener[listeners.size()];
055:
056: listeners.toArray(_listeners);
057: }
058:
059: public void scan(EnvironmentClassLoader loader, URL url) {
060: scan(loader, Vfs.lookup(url.toString()));
061: }
062:
063: public void scan(EnvironmentClassLoader loader, Path root) {
064: ScanListener[] listeners = new ScanListener[_listeners.length];
065:
066: boolean hasListener = false;
067: for (int i = 0; i < _listeners.length; i++) {
068: if (_listeners[i].isRootScannable(root)) {
069: listeners[i] = _listeners[i];
070: hasListener = true;
071: }
072: }
073:
074: if (!hasListener) {
075: return;
076: }
077:
078: if (root instanceof JarPath) {
079: JarByteCodeMatcher matcher = new JarByteCodeMatcher(loader,
080: root, listeners);
081:
082: scanForJarClasses(((JarPath) root).getContainer(), matcher);
083: } else {
084: PathByteCodeMatcher matcher = new PathByteCodeMatcher(
085: loader, root, listeners);
086:
087: scanForClasses(root, root, matcher);
088: }
089: }
090:
091: private void scanForClasses(Path root, Path path,
092: PathByteCodeMatcher matcher) {
093: try {
094: if (path.isDirectory()) {
095: for (String name : path.list())
096: scanForClasses(root, path.lookup(name), matcher);
097:
098: return;
099: }
100:
101: if (!path.getPath().endsWith(".class"))
102: return;
103:
104: matcher.init(root, path);
105:
106: ReadStream is = path.openRead();
107:
108: try {
109: ByteCodeClassScanner classScanner = new ByteCodeClassScanner(
110: path.getPath(), is, matcher);
111:
112: classScanner.scan();
113: } finally {
114: is.close();
115: }
116: } catch (IOException e) {
117: log.log(Level.FINE, e.toString(), e);
118: }
119: }
120:
121: private void scanForJarClasses(Path path, JarByteCodeMatcher matcher) {
122: ZipFile zipFile = null;
123:
124: try {
125: zipFile = new ZipFile(path.getNativePath());
126:
127: Enumeration<? extends ZipEntry> e = zipFile.entries();
128:
129: while (e.hasMoreElements()) {
130: ZipEntry entry = e.nextElement();
131:
132: String entryName = entry.getName();
133: if (!entryName.endsWith(".class"))
134: continue;
135:
136: matcher.init(entryName);
137:
138: ReadStream is = Vfs.openRead(zipFile
139: .getInputStream(entry));
140: try {
141: ByteCodeClassScanner classScanner = new ByteCodeClassScanner(
142: path.getPath(), is, matcher);
143:
144: classScanner.scan();
145: } finally {
146: is.close();
147: }
148: }
149: } catch (IOException e) {
150: log.log(Level.FINE, e.toString(), e);
151: } finally {
152: try {
153: if (zipFile != null)
154: zipFile.close();
155: } catch (Exception e) {
156: }
157: }
158: }
159:
160: static class JarByteCodeMatcher extends ScanByteCodeMatcher {
161: private String _entryName;
162:
163: JarByteCodeMatcher(EnvironmentClassLoader loader, Path root,
164: ScanListener[] listeners) {
165: super (loader, root, listeners);
166: }
167:
168: void init(String entryName) {
169: super .init();
170:
171: _entryName = entryName;
172: }
173:
174: String getClassName() {
175: int p = _entryName.lastIndexOf('.');
176:
177: String className = _entryName.substring(0, p);
178:
179: return className.replace('/', '.');
180: }
181: }
182:
183: static class PathByteCodeMatcher extends ScanByteCodeMatcher {
184: private Path _root;
185: private Path _path;
186:
187: PathByteCodeMatcher(EnvironmentClassLoader loader, Path root,
188: ScanListener[] listeners) {
189: super (loader, root, listeners);
190: }
191:
192: void init(Path root, Path path) {
193: super .init();
194:
195: _root = root;
196: _path = path;
197: }
198:
199: String getClassName() {
200: String rootName = _root.getFullPath();
201: String name = _path.getFullPath();
202:
203: int p = name.lastIndexOf('.');
204:
205: String className = name.substring(rootName.length(), p);
206:
207: return className.replace('/', '.');
208: }
209: }
210:
211: abstract static class ScanByteCodeMatcher implements
212: ByteCodeClassMatcher {
213: private final EnvironmentClassLoader _loader;
214: private final Path _root;
215: private final ScanListener[] _listeners;
216: private final ScanListener[] _currentListeners;
217:
218: ScanByteCodeMatcher(EnvironmentClassLoader loader, Path root,
219: ScanListener[] listeners) {
220: _loader = loader;
221: _root = root;
222:
223: _listeners = listeners;
224: _currentListeners = new ScanListener[listeners.length];
225: }
226:
227: void init() {
228: for (int i = 0; i < _listeners.length; i++)
229: _currentListeners[i] = _listeners[i];
230: }
231:
232: /**
233: * Returns true if the annotation class is a match.
234: */
235: public boolean isMatch(CharBuffer annotationClassName) {
236: int activeCount = 0;
237:
238: for (int i = _listeners.length - 1; i >= 0; i--) {
239: ScanListener listener = _currentListeners[i];
240:
241: if (listener == null)
242: continue;
243:
244: if (listener.isScanMatch(annotationClassName)) {
245: listener.classMatchEvent(_loader, _root,
246: getClassName());
247: _currentListeners[i] = null;
248: } else
249: activeCount++;
250: }
251:
252: return activeCount == 0;
253: }
254:
255: abstract String getClassName();
256: }
257: }
|