001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.aspectwerkz.hook.impl;
005:
006: import com.tc.aspectwerkz.hook.ClassPreProcessor;
007:
008: import java.io.File;
009: import java.io.IOException;
010: import java.net.MalformedURLException;
011: import java.net.URL;
012: import java.util.ArrayList;
013: import java.util.Collections;
014: import java.util.Enumeration;
015: import java.util.Iterator;
016: import java.util.List;
017: import java.util.Map;
018: import java.util.WeakHashMap;
019:
020: /**
021: * A simple implementation of class preprocessor. <p/>It does not modify the bytecode. It just prints on stdout some
022: * messages.
023: *
024: * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
025: */
026: public class StdoutPreProcessor implements ClassPreProcessor {
027: /**
028: * Classloaders repository, based on a synchronized weak hashmap key = classloader value = List of URL[]
029: * representing the local search path for .class files of the classloader value is completed at each class loading
030: */
031: private static Map classloaders;
032:
033: /**
034: * ms interval betwee classloader hierarchy printing
035: */
036: private static final long stepms = 15000;
037:
038: private static transient long lastPrinted = 0;
039:
040: private void log(String s) {
041: System.out.println(Thread.currentThread().getName()
042: + ": StdoutPreProcessor: " + s);
043: }
044:
045: public void initialize() {
046: log("initialize");
047: log("loaded by " + this .getClass().getClassLoader());
048: classloaders = Collections.synchronizedMap(new WeakHashMap());
049:
050: // register the classloader - except bootstrapCL
051: registerClassLoader(this .getClass().getClassLoader(), this
052: .getClass().getName());
053: }
054:
055: public byte[] preProcess(String klass, byte[] abyte,
056: ClassLoader caller) {
057: // emulate a -verbose:class mode
058: klass = klass.replace('.', '/') + ".class";
059: URL u = caller.getResource(klass);
060: log("> " + klass + " [" + ((u == null) ? "?" : u.toString())
061: + "] [" + caller + "]");
062:
063: /*
064: * URL uRoot = null; if (u!=null) { // u =
065: * jar:file:/C:/bea/weblogic81/server/lib/weblogic.jar!/weblogic/t3/srvr/T3Srvr.class // getPath =
066: * file:/C:/bea/weblogic81/server/lib/weblogic.jar!/weblogic/t3/srvr/T3Srvr.class // getFile =
067: * file:/C:/bea/weblogic81/server/lib/weblogic.jar!/weblogic/t3/srvr/T3Srvr.class int i =
068: * u.toString().indexOf('!'); if (i > 0) { try { uRoot = new URL(u.toString().substring(0, i)+"!/"); } catch
069: * (MalformedURLException e) { ; } } }
070: */
071: // register the classloader
072: registerClassLoader(caller, klass);
073:
074: // complete the url path of the classloader
075: registerSearchPath(caller, klass);
076:
077: // dump the hierarchy if needed
078: if (System.currentTimeMillis() > (lastPrinted + stepms)) {
079: lastPrinted = System.currentTimeMillis();
080: log("*******************************");
081: log("size=" + classloaders.size());
082: dumpHierarchy(null, "");
083: log("*******************************");
084: }
085: return abyte;
086: }
087:
088: /**
089: * Register a weak reference on the classloader Looks for META-INF/manifest.mf resource and log a line
090: *
091: * @param loader
092: * @param firstClassLoaded
093: */
094: private void registerClassLoader(ClassLoader loader,
095: String firstClassLoaded) {
096: if (loader != null) {
097: if (!classloaders.containsKey(loader)) {
098: // register the loader and the parent hierarchy if not already registered
099: registerClassLoader(loader.getParent(), loader
100: .getClass().getName());
101: registerSearchPath(loader.getParent(), loader
102: .getClass().getName());
103: URL u = null;
104:
105: // *** THIS IS NOT WORKING for other than .class files
106: // *** since manifest.mf can be several time
107: // *** but getResource follow parent first delegation model
108: // try to locate the first META-INF/manifest.mf (should be the aw.xml)
109: // case sensitive of META-INF, meta-inf, Meta-Inf, Meta-inf ? YES IT IS
110: //u = loader.getResource("META-INF/MANIFEST.MF");
111: // *** THIS could be enough for early registration
112: // add resources in some struct, allow multiple deploy of same resource
113: // if in parallel CL hierarchy - got it ?
114: try {
115: //@todo - case sensitive stuff is dangerous
116: // we could merge all aw.xml in META-INF and WEB-INF and meta-inf ...
117: Enumeration ue = loader
118: .getResources("META-INF/MANIFEST.MF");
119: if (ue.hasMoreElements()) {
120: log("--- in scope for " + loader);
121: }
122: while (ue.hasMoreElements()) {
123: log("--- " + ue.nextElement().toString());
124: }
125: } catch (IOException e) {
126: ;
127: }
128:
129: // register this loader
130: log("****" + loader + " ["
131: + ((u == null) ? "?" : u.toString()) + "] ["
132: + firstClassLoaded + ']');
133: classloaders.put(loader, new ArrayList());
134: }
135:
136: // register search path based on firstClassLoaded
137: }
138: }
139:
140: /**
141: * Dumps on stdout the registered classloader hierarchy child of "parent" Using the depth to track recursivity level
142: */
143: private void dumpHierarchy(ClassLoader parent, String depth) {
144: // do a copy of the registered CL to allow access on classloaders structure
145: List cl = new ArrayList(classloaders.keySet());
146: ClassLoader current = null;
147: for (Iterator i = cl.iterator(); i.hasNext();) {
148: current = (ClassLoader) i.next();
149: if (current.getParent() == parent) {
150: log(depth + current + '[' + classloaders.get(current));
151:
152: // handcheck for duplicate path (?)
153: List path = (List) classloaders.get(current);
154: ClassLoader currentParent = current.getParent();
155: while (currentParent != null) {
156: for (Iterator us = path.iterator(); us.hasNext();) {
157: URL u = (URL) us.next();
158: if (((List) classloaders.get(currentParent))
159: .contains(u)) {
160: log("!!!! duplicate detected for " + u
161: + " in " + current);
162: }
163: }
164: currentParent = currentParent.getParent();
165: }
166: dumpHierarchy(current, depth + " ");
167: }
168: }
169: }
170:
171: private void registerSearchPath(final ClassLoader loader,
172: final String klass) {
173: // bootCL
174: if (loader == null) {
175: return;
176: }
177:
178: // locate the klass
179: String klassFile = klass.replace('.', '/') + ".class";
180: URL uKlass = loader.getResource(klassFile);
181: if (uKlass == null) {
182: return;
183: }
184:
185: // retrieve the location root (jar/zip or directory)
186: URL uRoot = null;
187: int i = uKlass.toString().indexOf('!');
188: if (i > 0) {
189: // jar/zip
190: try {
191: // remove the jar: zip: prefix
192: //@todo !! zip: seems to be BEA specific
193: uRoot = (new File(uKlass.toString().substring(4, i)))
194: .getCanonicalFile().toURL();
195:
196: //uRoot = new URL(uKlass.toString().substring(0, i)+"!/");
197: } catch (MalformedURLException e) {
198: e.printStackTrace();
199: return;
200: } catch (IOException e2) {
201: e2.printStackTrace();
202: return;
203: }
204: } else {
205: // directory
206: i = uKlass.toString().indexOf(klassFile);
207: try {
208: uRoot = (new File(uKlass.toString().substring(0, i)))
209: .getCanonicalFile().toURL();
210: } catch (MalformedURLException e) {
211: e.printStackTrace();
212: return;
213: } catch (IOException e2) {
214: e2.printStackTrace();
215: return;
216: }
217: }
218:
219: // check if the location is not in a parent
220: ClassLoader parent = loader.getParent();
221: while (parent != null) {
222: if (((List) classloaders.get(parent)).contains(uRoot)) {
223: return;
224: }
225: parent = parent.getParent();
226: }
227:
228: // add the location if not already registered
229: // @todo !! not thread safe
230: List path = (List) classloaders.get(loader);
231: if (!path.contains(uRoot)) {
232: log("adding path " + uRoot + " to " + loader);
233: path.add(uRoot);
234: }
235: }
236:
237: public static void main(String[] args) throws Exception {
238: URL u = new URL(
239: "jar:file:/C:/bea/user_projects/domains/mydomain/myserver/.wlnotdelete/gallery/gallery-rar.jar!/");
240:
241: // differ from a "/./"
242: URL u2 = new URL(
243: "jar:file:/C:/bea/user_projects/domains/mydomain/./myserver/.wlnotdelete/gallery/gallery-rar.jar!/");
244: if (u.sameFile(u2)) {
245: System.out.println("same");
246: } else {
247: System.out.println("differ");
248: }
249: }
250: }
|