View Javadoc

    1   /***************************************************************************************
    2    * Copyright (c) Jonas BonŽr, Alexandre Vasseur. All rights reserved.                 *
    3    * http://aspectwerkz.codehaus.org                                                    *
    4    * ---------------------------------------------------------------------------------- *
    5    * The software in this package is published under the terms of the LGPL license      *
    6    * a copy of which has been included with this distribution in the license.txt file.  *
    7    **************************************************************************************/
    8   package org.codehaus.aspectwerkz.hook.impl;
    9
    10  import org.codehaus.aspectwerkz.hook.ClassPreProcessor;
    11
    12  import java.io.File;
    13  import java.io.IOException;
    14  import java.net.MalformedURLException;
    15  import java.net.URL;
    16  import java.util.ArrayList;
    17  import java.util.Collections;
    18  import java.util.Enumeration;
    19  import java.util.Hashtable;
    20  import java.util.Iterator;
    21  import java.util.List;
    22  import java.util.Map;
    23  import java.util.WeakHashMap;
    24
    25  /***
    26   * A simple implementation of class preprocessor. <p/>It does not modify the bytecode. It just prints on stdout some
    27   * messages.
    28   *
    29   * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
    30   */
    31  public class StdoutPreProcessor implements ClassPreProcessor {
    32      /***
    33       * Classloaders repository, based on a synchronized weak hashmap key = classloader value = List of URL[]
    34       * representing the local search path for .class files of the classloader value is completed at each class loading
    35       */
    36      private static Map classloaders;
    37
    38      /***
    39       * ms interval betwee classloader hierarchy printing
    40       */
    41      private static final long stepms = 15000;
    42
    43      private static transient long lastPrinted = 0;
    44
    45      private void log(String s) {
    46          System.out.println(Thread.currentThread().getName() + ": StdoutPreProcessor: " + s);
    47      }
    48
    49      public void initialize() {
    50          log("initialize");
    51          log("loaded by " + this.getClass().getClassLoader());
    52          classloaders = Collections.synchronizedMap(new WeakHashMap());
    53
    54          // register the classloader - except bootstrapCL
    55          registerClassLoader(this.getClass().getClassLoader(), this.getClass().getName());
    56      }
    57
    58      public byte[] preProcess(String klass, byte[] abyte, ClassLoader caller) {
    59          // emulate a -verbose:class mode
    60          klass = klass.replace('.', '/') + ".class";
    61          URL u = caller.getResource(klass);
    62          log("> " + klass + " [" + ((u == null) ? "?" : u.toString()) + "] [" + caller + "]");
    63
    64          /*
    65           * URL uRoot = null; if (u!=null) { // u =
    66           * jar:file:/C:/bea/weblogic81/server/lib/weblogic.jar!/weblogic/t3/srvr/T3Srvr.class // getPath =
    67           * file:/C:/bea/weblogic81/server/lib/weblogic.jar!/weblogic/t3/srvr/T3Srvr.class // getFile =
    68           * file:/C:/bea/weblogic81/server/lib/weblogic.jar!/weblogic/t3/srvr/T3Srvr.class int i =
    69           * u.toString().indexOf('!'); if (i > 0) { try { uRoot = new URL(u.toString().substring(0, i)+"!/"); } catch
    70           * (MalformedURLException e) { ; } } }
    71           */
    72          // register the classloader
    73          registerClassLoader(caller, klass);
    74
    75          // complete the url path of the classloader
    76          registerSearchPath(caller, klass);
    77
    78          // dump the hierarchy if needed
    79          if (System.currentTimeMillis() > (lastPrinted + stepms)) {
    80              lastPrinted = System.currentTimeMillis();
    81              log("*******************************");
    82              log("size=" + classloaders.size());
    83              dumpHierarchy(null, "");
    84              log("*******************************");
    85          }
    86          return abyte;
    87      }
    88
    89      /***
    90       * Register a weak reference on the classloader Looks for META-INF/manifest.mf resource and log a line
    91       *
    92       * @param loader
    93       * @param firstClassLoaded
    94       */
    95      private void registerClassLoader(ClassLoader loader, String firstClassLoaded) {
    96          if (loader != null) {
    97              if (!classloaders.containsKey(loader)) {
    98                  // register the loader and the parent hierarchy if not already registered
    99                  registerClassLoader(loader.getParent(), loader.getClass().getName());
    100                 registerSearchPath(loader.getParent(), loader.getClass().getName());
    101                 URL u = null;
    102
    103                 // *** THIS IS NOT WORKING for other than .class files
    104                 // *** since manifest.mf can be several time
    105                 // *** but getResource follow parent first delegation model
    106                 // try to locate the first META-INF/manifest.mf (should be the aw.xml)
    107                 // case sensitive of META-INF, meta-inf, Meta-Inf, Meta-inf ? YES IT IS
    108                 //u = loader.getResource("META-INF/MANIFEST.MF");
    109                 // *** THIS could be enough for early registration
    110                 // add resources in some struct, allow multiple deploy of same resource
    111                 // if in parallel CL hierarchy - got it ?
    112                 try {
    113                     //@todo - case sensitive stuff is dangerous
    114                     // we could merge all aw.xml in META-INF and WEB-INF and meta-inf ...
    115                     Enumeration ue = loader.getResources("META-INF/MANIFEST.MF");
    116                     if (ue.hasMoreElements()) {
    117                         log("--- in scope for " + loader);
    118                     }
    119                     while (ue.hasMoreElements()) {
    120                         log("--- " + ue.nextElement().toString());
    121                     }
    122                 } catch (IOException e) {
    123                     ;
    124                 }
    125
    126                 // register this loader
    127                 log("****" + loader + " [" + ((u == null) ? "?" : u.toString()) + "] [" + firstClassLoaded + ']');
    128                 classloaders.put(loader, new ArrayList());
    129             }
    130
    131             // register search path based on firstClassLoaded
    132         }
    133     }
    134
    135     /***
    136      * Dumps on stdout the registered classloader hierarchy child of "parent" Using the depth to track recursivity level
    137      */
    138     private void dumpHierarchy(ClassLoader parent, String depth) {
    139         // do a copy of the registered CL to allow access on classloaders structure
    140         List cl = new ArrayList(classloaders.keySet());
    141         ClassLoader current = null;
    142         for (Iterator i = cl.iterator(); i.hasNext();) {
    143             current = (ClassLoader) i.next();
    144             if (current.getParent() == parent) {
    145                 log(depth + current + '[' + classloaders.get(current));
    146
    147                 // handcheck for duplicate path (?)
    148                 List path = (List) classloaders.get(current);
    149                 ClassLoader currentParent = current.getParent();
    150                 while (currentParent != null) {
    151                     for (Iterator us = path.iterator(); us.hasNext();) {
    152                         URL u = (URL) us.next();
    153                         if (((List) classloaders.get(currentParent)).contains(u)) {
    154                             log("!!!! duplicate detected for " + u + " in " + current);
    155                         }
    156                     }
    157                     currentParent = currentParent.getParent();
    158                 }
    159                 dumpHierarchy(current, depth + "  ");
    160             }
    161         }
    162     }
    163
    164     private void registerSearchPath(final ClassLoader loader, final String klass) {
    165         // bootCL
    166         if (loader == null) {
    167             return;
    168         }
    169
    170         // locate the klass
    171         String klassFile = klass.replace('.', '/') + ".class";
    172         URL uKlass = loader.getResource(klassFile);
    173         if (uKlass == null) {
    174             return;
    175         }
    176
    177         // retrieve the location root (jar/zip or directory)
    178         URL uRoot = null;
    179         int i = uKlass.toString().indexOf('!');
    180         if (i > 0) {
    181             // jar/zip
    182             try {
    183                 // remove the jar: zip: prefix
    184                 //@todo !! zip: seems to be BEA specific
    185                 uRoot = (new File(uKlass.toString().substring(4, i))).getCanonicalFile().toURL();
    186
    187                 //uRoot = new URL(uKlass.toString().substring(0, i)+"!/");
    188             } catch (MalformedURLException e) {
    189                 e.printStackTrace();
    190                 return;
    191             } catch (IOException e2) {
    192                 e2.printStackTrace();
    193                 return;
    194             }
    195         } else {
    196             // directory
    197             i = uKlass.toString().indexOf(klassFile);
    198             try {
    199                 uRoot = (new File(uKlass.toString().substring(0, i))).getCanonicalFile().toURL();
    200             } catch (MalformedURLException e) {
    201                 e.printStackTrace();
    202                 return;
    203             } catch (IOException e2) {
    204                 e2.printStackTrace();
    205                 return;
    206             }
    207         }
    208
    209         // check if the location is not in a parent
    210         ClassLoader parent = loader.getParent();
    211         while (parent != null) {
    212             if (((List) classloaders.get(parent)).contains(uRoot)) {
    213                 return;
    214             }
    215             parent = parent.getParent();
    216         }
    217
    218         // add the location if not already registered
    219         // @todo !! not thread safe
    220         List path = (List) classloaders.get(loader);
    221         if (!path.contains(uRoot)) {
    222             log("adding path " + uRoot + " to " + loader);
    223             path.add(uRoot);
    224         }
    225     }
    226
    227     public static void main(String[] args) throws Exception {
    228         URL u = new URL(
    229                 "jar:file:/C:/bea/user_projects/domains/mydomain/myserver/.wlnotdelete/gallery/gallery-rar.jar!/"
    230         );
    231
    232         // differ from a "/./"
    233         URL u2 = new URL(
    234                 "jar:file:/C:/bea/user_projects/domains/mydomain/./myserver/.wlnotdelete/gallery/gallery-rar.jar!/"
    235         );
    236         if (u.sameFile(u2)) {
    237             System.out.println("same");
    238         } else {
    239             System.out.println("differ");
    240         }
    241     }
    242 }