001: /*
002: * Copyright (c) 2001-2007, Jean Tessier
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions
007: * are met:
008: *
009: * * Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: *
012: * * Redistributions in binary form must reproduce the above copyright
013: * notice, this list of conditions and the following disclaimer in the
014: * documentation and/or other materials provided with the distribution.
015: *
016: * * Neither the name of Jean Tessier nor the names of his contributors
017: * may be used to endorse or promote products derived from this software
018: * without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
021: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
022: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
023: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
024: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
027: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
028: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
029: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
030: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031: */
032:
033: package com.jeantessier.classreader;
034:
035: import java.io.*;
036: import java.util.*;
037:
038: import org.apache.log4j.*;
039:
040: public abstract class ClassfileLoaderEventSource extends
041: ClassfileLoader {
042: public static final ClassfileLoaderDispatcher DEFAULT_DISPATCHER = new PermissiveDispatcher();
043:
044: private ClassfileLoaderDispatcher dispatcher;
045:
046: private ClassfileLoader dirLoader = new DirectoryClassfileLoader(
047: this );
048: private ClassfileLoader jarLoader = new JarClassfileLoader(this );
049: private ClassfileLoader zipLoader = new ZipClassfileLoader(this );
050:
051: private HashSet<LoadListener> loadListeners = new HashSet<LoadListener>();
052:
053: private LinkedList<String> groupNames = new LinkedList<String>();
054: private LinkedList<Integer> groupSizes = new LinkedList<Integer>();
055:
056: private ClassfileLoaderDispatcher.Action previousDispatch;
057:
058: public ClassfileLoaderEventSource() {
059: this (DEFAULT_DISPATCHER);
060: }
061:
062: public ClassfileLoaderEventSource(
063: ClassfileLoaderDispatcher dispatcher) {
064: this .dispatcher = dispatcher;
065: }
066:
067: protected void load(String filename) {
068: ClassfileLoaderDispatcher.Action dispatch = dispatcher
069: .dispatch(filename);
070:
071: previousDispatch = dispatch;
072:
073: switch (dispatch) {
074: case IGNORE:
075: Logger.getLogger(getClass()).debug(
076: "IGNORE \"" + filename + "\"");
077: break;
078:
079: case CLASS:
080: case DIRECTORY:
081: Logger.getLogger(getClass()).debug(
082: "DIRECTORY or CLASS \"" + filename + "\"");
083: dirLoader.load(filename);
084: break;
085:
086: case ZIP:
087: Logger.getLogger(getClass()).debug(
088: "ZIP \"" + filename + "\"");
089: zipLoader.load(filename);
090: break;
091:
092: case JAR:
093: Logger.getLogger(getClass()).debug(
094: "JAR \"" + filename + "\"");
095: jarLoader.load(filename);
096: break;
097:
098: default:
099: Logger.getLogger(getClass()).debug(
100: "default (IGNORE) \"" + filename + "\"");
101: break;
102: }
103: }
104:
105: protected void load(String filename, InputStream in) {
106: ClassfileLoaderDispatcher.Action dispatch = dispatcher
107: .dispatch(filename);
108:
109: if (dispatch == ClassfileLoaderDispatcher.Action.IGNORE
110: && getTopGroupSize() == 1
111: && filename.equals(getTopGroupName())) {
112: dispatch = previousDispatch;
113: }
114:
115: switch (dispatch) {
116: case IGNORE:
117: Logger.getLogger(getClass()).debug(
118: "IGNORE \"" + filename + "\"");
119: break;
120:
121: case DIRECTORY:
122: Logger.getLogger(getClass()).debug(
123: "DIRECTORY \"" + filename + "\"");
124: dirLoader.load(filename, in);
125: break;
126:
127: case ZIP:
128: Logger.getLogger(getClass()).debug(
129: "ZIP \"" + filename + "\"");
130: zipLoader.load(filename, in);
131: break;
132:
133: case JAR:
134: Logger.getLogger(getClass()).debug(
135: "JAR \"" + filename + "\"");
136: jarLoader.load(filename, in);
137: break;
138:
139: case CLASS:
140: Logger.getLogger(getClass()).debug(
141: "CLASS \"" + filename + "\"");
142: try {
143: fireBeginClassfile(filename);
144: Classfile classfile = load(new DataInputStream(in));
145: fireEndClassfile(filename, classfile);
146: } catch (IOException ex) {
147: Logger.getLogger(getClass()).warn(
148: "Cannot load class from file \"" + filename
149: + "\"", ex);
150: }
151: break;
152:
153: default:
154: Logger.getLogger(getClass()).debug(
155: "default (IGNORE) \"" + filename + "\"");
156: break;
157: }
158: }
159:
160: public void addLoadListener(LoadListener listener) {
161: synchronized (loadListeners) {
162: loadListeners.add(listener);
163: }
164: }
165:
166: public void removeLoadListener(LoadListener listener) {
167: synchronized (loadListeners) {
168: loadListeners.remove(listener);
169: }
170: }
171:
172: protected void fireBeginSession() {
173: Logger.getLogger(getClass()).debug("Begin session");
174:
175: LoadEvent event = new LoadEvent(this , null, null, null);
176:
177: HashSet<LoadListener> listeners;
178: synchronized (loadListeners) {
179: listeners = (HashSet<LoadListener>) loadListeners.clone();
180: }
181:
182: for (LoadListener listener : listeners) {
183: listener.beginSession(event);
184: }
185: }
186:
187: protected void fireBeginGroup(String groupName, int size) {
188: Logger.getLogger(getClass()).debug(
189: "Begin group \"" + groupName + "\" of size " + size);
190:
191: LoadEvent event = new LoadEvent(this , groupName, size);
192:
193: HashSet<LoadListener> listeners;
194: synchronized (loadListeners) {
195: listeners = (HashSet<LoadListener>) loadListeners.clone();
196: }
197:
198: for (LoadListener listener : listeners) {
199: listener.beginGroup(event);
200: }
201:
202: pushGroupName(groupName);
203: pushGroupSize(size);
204: }
205:
206: protected void fireBeginFile(String filename) {
207: Logger.getLogger(getClass()).debug(
208: "Begin file \"" + filename + "\"");
209:
210: LoadEvent event = new LoadEvent(this , getTopGroupName(),
211: filename, null);
212:
213: HashSet<LoadListener> listeners;
214: synchronized (loadListeners) {
215: listeners = (HashSet<LoadListener>) loadListeners.clone();
216: }
217:
218: for (LoadListener listener : listeners) {
219: listener.beginFile(event);
220: }
221: }
222:
223: protected void fireBeginClassfile(String filename) {
224: Logger.getLogger(getClass()).debug(
225: "Begin classfile \"" + filename + "\"");
226:
227: LoadEvent event = new LoadEvent(this , getTopGroupName(),
228: filename, null);
229:
230: HashSet<LoadListener> listeners;
231: synchronized (loadListeners) {
232: listeners = (HashSet<LoadListener>) loadListeners.clone();
233: }
234:
235: for (LoadListener listener : listeners) {
236: listener.beginClassfile(event);
237: }
238: }
239:
240: protected void fireEndClassfile(String filename, Classfile classfile) {
241: Logger.getLogger(getClass()).debug(
242: "End classfile \""
243: + filename
244: + "\": "
245: + ((classfile != null) ? classfile
246: .getClassName() : "nothing"));
247:
248: LoadEvent event = new LoadEvent(this , getTopGroupName(),
249: filename, classfile);
250:
251: HashSet<LoadListener> listeners;
252: synchronized (loadListeners) {
253: listeners = (HashSet<LoadListener>) loadListeners.clone();
254: }
255:
256: for (LoadListener listener : listeners) {
257: listener.endClassfile(event);
258: }
259: }
260:
261: protected void fireEndFile(String filename) {
262: Logger.getLogger(getClass()).debug(
263: "End file \"" + filename + "\"");
264:
265: LoadEvent event = new LoadEvent(this , getTopGroupName(),
266: filename, null);
267:
268: HashSet<LoadListener> listeners;
269: synchronized (loadListeners) {
270: listeners = (HashSet<LoadListener>) loadListeners.clone();
271: }
272:
273: for (LoadListener listener : listeners) {
274: listener.endFile(event);
275: }
276: }
277:
278: protected void fireEndGroup(String groupName) {
279: Logger.getLogger(getClass()).debug(
280: "End group \"" + groupName + "\"");
281:
282: LoadEvent event = new LoadEvent(this , groupName, null, null);
283:
284: HashSet<LoadListener> listeners;
285: synchronized (loadListeners) {
286: listeners = (HashSet<LoadListener>) loadListeners.clone();
287: }
288:
289: for (LoadListener listener : listeners) {
290: listener.endGroup(event);
291: }
292:
293: popGroupName();
294: popGroupSize();
295: }
296:
297: protected void fireEndSession() {
298: Logger.getLogger(getClass()).debug("End session");
299:
300: LoadEvent event = new LoadEvent(this , null, null, null);
301:
302: HashSet<LoadListener> listeners;
303: synchronized (loadListeners) {
304: listeners = (HashSet<LoadListener>) loadListeners.clone();
305: }
306:
307: for (LoadListener listener : listeners) {
308: listener.endSession(event);
309: }
310: }
311:
312: private String getTopGroupName() {
313: String result = null;
314:
315: if (!groupNames.isEmpty()) {
316: result = groupNames.getLast();
317: }
318:
319: return result;
320: }
321:
322: private void pushGroupName(String groupName) {
323: groupNames.addLast(groupName);
324: }
325:
326: private String popGroupName() {
327: return groupNames.removeLast();
328: }
329:
330: private int getTopGroupSize() {
331: int result = 0;
332:
333: if (!groupSizes.isEmpty()) {
334: result = groupSizes.getLast();
335: }
336:
337: return result;
338: }
339:
340: private void pushGroupSize(int size) {
341: groupSizes.addLast(size);
342: }
343:
344: private int popGroupSize() {
345: return groupSizes.removeLast();
346: }
347: }
|