Logo Search packages:      
Sourcecode: aspectj version File versions  Download package

ClassLoaderWeavingAdaptor.java

/*******************************************************************************
 * Copyright (c) 2005 Contributors.
 * All rights reserved.
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution and is available at
 * http://eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Alexandre Vasseur         initial implementation
 *   David Knibb               weaving context enhancments
 *******************************************************************************/
package org.aspectj.weaver.loadtime;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;

import org.aspectj.bridge.AbortException;
import org.aspectj.bridge.Constants;
import org.aspectj.util.LangUtil;
import org.aspectj.weaver.Lint;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.World;
import org.aspectj.weaver.Lint.Kind;
import org.aspectj.weaver.bcel.BcelWeakClassLoaderReference;
import org.aspectj.weaver.bcel.BcelWeaver;
import org.aspectj.weaver.bcel.BcelWorld;
import org.aspectj.weaver.bcel.Utility;
import org.aspectj.weaver.loadtime.definition.Definition;
import org.aspectj.weaver.loadtime.definition.DocumentParser;
import org.aspectj.weaver.ltw.LTWWorld;
import org.aspectj.weaver.patterns.PatternParser;
import org.aspectj.weaver.patterns.TypePattern;
import org.aspectj.weaver.tools.GeneratedClassHandler;
import org.aspectj.weaver.tools.Trace;
import org.aspectj.weaver.tools.TraceFactory;
import org.aspectj.weaver.tools.WeavingAdaptor;

/**
 * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
 */
00057 public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {

      private final static String AOP_XML = Constants.AOP_USER_XML + ";" + Constants.AOP_AJC_XML + ";" + Constants.AOP_OSGI_XML;

      private boolean initialized;

      private List m_dumpTypePattern = new ArrayList();
      private boolean m_dumpBefore = false;
      private boolean dumpDirPerClassloader = false;
      private List m_includeTypePattern = new ArrayList();
      private List m_excludeTypePattern = new ArrayList();
      private List m_includeStartsWith = new ArrayList();
      private List m_excludeStartsWith = new ArrayList();
      private List m_aspectExcludeTypePattern = new ArrayList();
      private List m_aspectExcludeStartsWith = new ArrayList();
      private List m_aspectIncludeTypePattern = new ArrayList();
      private List m_aspectIncludeStartsWith = new ArrayList();

      private StringBuffer namespace;
      private IWeavingContext weavingContext;

      private List concreteAspects = new ArrayList();

      private static Trace trace = TraceFactory.getTraceFactory().getTrace(ClassLoaderWeavingAdaptor.class);

      public ClassLoaderWeavingAdaptor() {
            super();
            if (trace.isTraceEnabled())
                  trace.enter("<init>", this);
            if (trace.isTraceEnabled())
                  trace.exit("<init>");
      }

      /**
       * We don't need a reference to the class loader and using it during construction can cause problems with recursion. It also
       * makes sense to supply the weaving context during initialization to.
       * 
       * @deprecated
       */
00096       public ClassLoaderWeavingAdaptor(final ClassLoader deprecatedLoader, final IWeavingContext deprecatedContext) {
            super();
            if (trace.isTraceEnabled())
                  trace.enter("<init>", this, new Object[] { deprecatedLoader, deprecatedContext });
            if (trace.isTraceEnabled())
                  trace.exit("<init>");
      }

      class SimpleGeneratedClassHandler implements GeneratedClassHandler {
            private BcelWeakClassLoaderReference loaderRef;

            SimpleGeneratedClassHandler(ClassLoader loader) {
                  loaderRef = new BcelWeakClassLoaderReference(loader);
            }

            /**
             * Callback when we need to define a Closure in the JVM
             * 
             */
            public void acceptClass(String name, byte[] bytes) {
                  try {
                        if (shouldDump(name.replace('/', '.'), false)) {
                              dump(name, bytes, false);
                        }
                  } catch (Throwable throwable) {
                        throwable.printStackTrace();
                  }

                  defineClass(loaderRef.getClassLoader(), name, bytes); // could be done lazily using the hook
            }
      }

      protected void initialize(final ClassLoader classLoader, IWeavingContext context) {
            if (initialized)
                  return;

            boolean success = true;
            // if (trace.isTraceEnabled()) trace.enter("initialize",this,new Object[] { classLoader, context });

            this.weavingContext = context;
            if (weavingContext == null) {
                  weavingContext = new DefaultWeavingContext(classLoader);
            }

            createMessageHandler();

            this.generatedClassHandler = new SimpleGeneratedClassHandler(classLoader);

            List definitions = weavingContext.getDefinitions(classLoader, this);
            if (definitions.isEmpty()) {
                  disable(); // TODO maw Needed to ensure messages are flushed
                  if (trace.isTraceEnabled())
                        trace.exit("initialize", definitions);
                  return;
            }

            bcelWorld = new LTWWorld(classLoader, weavingContext, // TODO when the world works in terms of the context, we can remove
                        // the loader...
                        getMessageHandler(), null);

            weaver = new BcelWeaver(bcelWorld);

            // register the definitions
            success = registerDefinitions(weaver, classLoader, definitions);
            if (success) {

                  // after adding aspects
                  weaver.prepareForWeave();

                  enable(); // TODO maw Needed to ensure messages are flushed
                  success = weaveAndDefineConceteAspects();
            }

            if (success) {
                  enable();
            } else {
                  disable();
                  bcelWorld = null;
                  weaver = null;
            }

            initialized = true;
            if (trace.isTraceEnabled())
                  trace.exit("initialize", isEnabled());
      }

      /**
       * Load and cache the aop.xml/properties according to the classloader visibility rules
       * 
       * @param weaver
       * @param loader
       */
00188       List parseDefinitions(final ClassLoader loader) {
            if (trace.isTraceEnabled())
                  trace.enter("parseDefinitions", this);

            List definitions = new ArrayList();
            try {
                  info("register classloader " + getClassLoaderName(loader));
                  // TODO av underoptimized: we will parse each XML once per CL that see it

                  // TODO av dev mode needed ? TBD -Daj5.def=...
                  if (loader.equals(ClassLoader.getSystemClassLoader())) {
                        String file = System.getProperty("aj5.def", null);
                        if (file != null) {
                              info("using (-Daj5.def) " + file);
                              definitions.add(DocumentParser.parse((new File(file)).toURL()));
                        }
                  }

                  String resourcePath = System.getProperty("org.aspectj.weaver.loadtime.configuration", AOP_XML);
                  if (trace.isTraceEnabled())
                        trace.event("parseDefinitions", this, resourcePath);

                  StringTokenizer st = new StringTokenizer(resourcePath, ";");

                  while (st.hasMoreTokens()) {
                        String nextDefinition = st.nextToken();
                        if (nextDefinition.startsWith("file:")) {
                              try {
                                    String fpath = new URL(nextDefinition).getFile();
                                    File configFile = new File(fpath);
                                    if (!configFile.exists()) {
                                          warn("configuration does not exist: " + nextDefinition);
                                    } else {
                                          definitions.add(DocumentParser.parse(configFile.toURL()));
                                    }
                              } catch (MalformedURLException mue) {
                                    error("malformed definition url: " + nextDefinition);
                              }
                        } else {
                              Enumeration xmls = weavingContext.getResources(nextDefinition);
                              // System.out.println("? registerDefinitions: found-aop.xml=" + xmls.hasMoreElements() + ", loader=" + loader);

                              Set seenBefore = new HashSet();
                              while (xmls.hasMoreElements()) {
                                    URL xml = (URL) xmls.nextElement();
                                    if (trace.isTraceEnabled())
                                          trace.event("parseDefinitions", this, xml);
                                    if (!seenBefore.contains(xml)) {
                                          info("using configuration " + weavingContext.getFile(xml));
                                          definitions.add(DocumentParser.parse(xml));
                                          seenBefore.add(xml);
                                    } else {
                                          warn("ignoring duplicate definition: " + xml);
                                    }
                              }
                        }
                  }
                  if (definitions.isEmpty()) {
                        info("no configuration found. Disabling weaver for class loader " + getClassLoaderName(loader));
                  }
            } catch (Exception e) {
                  definitions.clear();
                  warn("parse definitions failed", e);
            }

            if (trace.isTraceEnabled())
                  trace.exit("parseDefinitions", definitions);
            return definitions;
      }

      private boolean registerDefinitions(final BcelWeaver weaver, final ClassLoader loader, List definitions) {
            if (trace.isTraceEnabled())
                  trace.enter("registerDefinitions", this, definitions);
            boolean success = true;

            try {
                  registerOptions(weaver, loader, definitions);
                  registerAspectExclude(weaver, loader, definitions);
                  registerAspectInclude(weaver, loader, definitions);
                  success = registerAspects(weaver, loader, definitions);
                  registerIncludeExclude(weaver, loader, definitions);
                  registerDump(weaver, loader, definitions);
            } catch (Exception ex) {
                  trace.error("register definition failed", ex);
                  success = false;
                  warn("register definition failed", (ex instanceof AbortException) ? null : ex);
            }

            if (trace.isTraceEnabled())
                  trace.exit("registerDefinitions", success);
            return success;
      }

      private String getClassLoaderName(ClassLoader loader) {
            return weavingContext.getClassLoaderName();
      }

      /**
       * Configure the weaver according to the option directives TODO av - don't know if it is that good to reuse, since we only allow
       * a small subset of options in LTW
       * 
       * @param weaver
       * @param loader
       * @param definitions
       */
00293       private void registerOptions(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
            StringBuffer allOptions = new StringBuffer();
            for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
                  Definition definition = (Definition) iterator.next();
                  allOptions.append(definition.getWeaverOptions()).append(' ');
            }

            Options.WeaverOption weaverOption = Options.parse(allOptions.toString(), loader, getMessageHandler());

            // configure the weaver and world
            // AV - code duplicates AspectJBuilder.initWorldAndWeaver()
            World world = weaver.getWorld();
            setMessageHandler(weaverOption.messageHandler);
            world.setXlazyTjp(weaverOption.lazyTjp);
            world.setXHasMemberSupportEnabled(weaverOption.hasMember);
            world.setOptionalJoinpoints(weaverOption.optionalJoinpoints);
            world.setPinpointMode(weaverOption.pinpoint);
            weaver.setReweavableMode(weaverOption.notReWeavable);
            world.performExtraConfiguration(weaverOption.xSet);
            world.setXnoInline(weaverOption.noInline);
            // AMC - autodetect as per line below, needed for AtAjLTWTests.testLTWUnweavable
            world.setBehaveInJava5Way(LangUtil.is15VMOrGreater());
            world.setAddSerialVerUID(weaverOption.addSerialVersionUID);

            /* First load defaults */
            bcelWorld.getLint().loadDefaultProperties();

            /* Second overlay LTW defaults */
            bcelWorld.getLint().adviceDidNotMatch.setKind(null);

            /* Third load user file using -Xlintfile so that -Xlint wins */
            if (weaverOption.lintFile != null) {
                  InputStream resource = null;
                  try {
                        resource = loader.getResourceAsStream(weaverOption.lintFile);
                        Exception failure = null;
                        if (resource != null) {
                              try {
                                    Properties properties = new Properties();
                                    properties.load(resource);
                                    world.getLint().setFromProperties(properties);
                              } catch (IOException e) {
                                    failure = e;
                              }
                        }
                        if (failure != null || resource == null) {
                              warn("Cannot access resource for -Xlintfile:" + weaverOption.lintFile, failure);
                              // world.getMessageHandler().handleMessage(new Message(
                              // "Cannot access resource for -Xlintfile:"+weaverOption.lintFile,
                              // IMessage.WARNING,
                              // failure,
                              // null));
                        }
                  } finally {
                        try {
                              resource.close();
                        } catch (Throwable t) {
                        }
                  }
            }

            /* Fourth override with -Xlint */
            if (weaverOption.lint != null) {
                  if (weaverOption.lint.equals("default")) {// FIXME should be AjBuildConfig.AJLINT_DEFAULT but yetanother deps..
                        bcelWorld.getLint().loadDefaultProperties();
                  } else {
                        bcelWorld.getLint().setAll(weaverOption.lint);
                  }
            }
            // TODO proceedOnError option
      }

      private void registerAspectExclude(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
            String fastMatchInfo = null;
            for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
                  Definition definition = (Definition) iterator.next();
                  for (Iterator iterator1 = definition.getAspectExcludePatterns().iterator(); iterator1.hasNext();) {
                        String exclude = (String) iterator1.next();
                        TypePattern excludePattern = new PatternParser(exclude).parseTypePattern();
                        m_aspectExcludeTypePattern.add(excludePattern);
                        fastMatchInfo = looksLikeStartsWith(exclude);
                        if (fastMatchInfo != null) {
                              m_aspectExcludeStartsWith.add(fastMatchInfo);
                        }
                  }
            }
      }

      private void registerAspectInclude(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
            String fastMatchInfo = null;
            for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
                  Definition definition = (Definition) iterator.next();
                  for (Iterator iterator1 = definition.getAspectIncludePatterns().iterator(); iterator1.hasNext();) {
                        String include = (String) iterator1.next();
                        TypePattern includePattern = new PatternParser(include).parseTypePattern();
                        m_aspectIncludeTypePattern.add(includePattern);
                        fastMatchInfo = looksLikeStartsWith(include);
                        if (fastMatchInfo != null) {
                              m_aspectIncludeStartsWith.add(fastMatchInfo);
                        }
                  }
            }
      }

      protected void lint(String name, String[] infos) {
            Lint lint = bcelWorld.getLint();
            Kind kind = lint.getLintKind(name);
            kind.signal(infos, null, null);
      }

      @Override
      public String getContextId() {
            return weavingContext.getId();
      }

      /**
       * Register the aspect, following include / exclude rules
       * 
       * @param weaver
       * @param loader
       * @param definitions
       */
00415       private boolean registerAspects(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
            if (trace.isTraceEnabled())
                  trace.enter("registerAspects", this, new Object[] { weaver, loader, definitions });
            boolean success = true;

            // TODO: the exclude aspect allow to exclude aspect defined upper in the CL hierarchy - is it what we want ??
            // if not, review the getResource so that we track which resource is defined by which CL

            // iterate aspectClassNames
            // exclude if in any of the exclude list
            for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
                  Definition definition = (Definition) iterator.next();
                  for (Iterator aspects = definition.getAspectClassNames().iterator(); aspects.hasNext();) {
                        String aspectClassName = (String) aspects.next();
                        if (acceptAspect(aspectClassName)) {
                              info("register aspect " + aspectClassName);
                              // System.err.println("? ClassLoaderWeavingAdaptor.registerAspects() aspectName=" + aspectClassName +
                              // ", loader=" + loader + ", bundle=" + weavingContext.getClassLoaderName());
                              /* ResolvedType aspect = */weaver.addLibraryAspect(aspectClassName);

                              // generate key for SC
                              if (namespace == null) {
                                    namespace = new StringBuffer(aspectClassName);
                              } else {
                                    namespace = namespace.append(";" + aspectClassName);
                              }
                        } else {
                              // warn("aspect excluded: " + aspectClassName);
                              lint("aspectExcludedByConfiguration", new String[] { aspectClassName, getClassLoaderName(loader) });
                        }
                  }
            }

            // iterate concreteAspects
            // exclude if in any of the exclude list - note that the user defined name matters for that to happen
            for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
                  Definition definition = (Definition) iterator.next();
                  for (Definition.ConcreteAspect concreteAspect : definition.getConcreteAspects()) {
                        if (acceptAspect(concreteAspect.name)) {
                              info("define aspect " + concreteAspect.name);
                              ConcreteAspectCodeGen gen = new ConcreteAspectCodeGen(concreteAspect, weaver.getWorld());
                              if (!gen.validate()) {
                                    error("Concrete-aspect '" + concreteAspect.name + "' could not be registered");
                                    success = false;
                                    break;
                              }

                              ((BcelWorld) weaver.getWorld()).addSourceObjectType(Utility.makeJavaClass(concreteAspect.name, gen.getBytes()));

                              concreteAspects.add(gen);

                              weaver.addLibraryAspect(concreteAspect.name);

                              // generate key for SC
                              if (namespace == null) {
                                    namespace = new StringBuffer(concreteAspect.name);
                              } else {
                                    namespace = namespace.append(";" + concreteAspect.name);
                              }
                        }
                  }
            }

            /* We couldn't register one or more aspects so disable the adaptor */
            if (!success) {
                  warn("failure(s) registering aspects. Disabling weaver for class loader " + getClassLoaderName(loader));
            }

            /* We didn't register any aspects so disable the adaptor */
            else if (namespace == null) {
                  success = false;
                  info("no aspects registered. Disabling weaver for class loader " + getClassLoaderName(loader));
            }

            if (trace.isTraceEnabled())
                  trace.exit("registerAspects", success);
            return success;
      }

      private boolean weaveAndDefineConceteAspects() {
            if (trace.isTraceEnabled())
                  trace.enter("weaveAndDefineConceteAspects", this, concreteAspects);
            boolean success = true;

            for (Iterator iterator = concreteAspects.iterator(); iterator.hasNext();) {
                  ConcreteAspectCodeGen gen = (ConcreteAspectCodeGen) iterator.next();
                  String name = gen.getClassName();
                  byte[] bytes = gen.getBytes();

                  try {
                        byte[] newBytes = weaveClass(name, bytes, true);
                        this.generatedClassHandler.acceptClass(name, newBytes);
                  } catch (IOException ex) {
                        trace.error("weaveAndDefineConceteAspects", ex);
                        error("exception weaving aspect '" + name + "'", ex);
                  }
            }

            if (trace.isTraceEnabled())
                  trace.exit("weaveAndDefineConceteAspects", success);
            return success;
      }

      /**
       * Register the include / exclude filters We duplicate simple patterns in startWith filters that will allow faster matching
       * without ResolvedType
       * 
       * @param weaver
       * @param loader
       * @param definitions
       */
00526       private void registerIncludeExclude(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
            String fastMatchInfo = null;
            for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
                  Definition definition = (Definition) iterator.next();
                  for (Iterator iterator1 = definition.getIncludePatterns().iterator(); iterator1.hasNext();) {
                        String include = (String) iterator1.next();
                        TypePattern includePattern = new PatternParser(include).parseTypePattern();
                        m_includeTypePattern.add(includePattern);
                        fastMatchInfo = looksLikeStartsWith(include);
                        if (fastMatchInfo != null) {
                              m_includeStartsWith.add(fastMatchInfo);
                        }
                  }
                  for (Iterator iterator1 = definition.getExcludePatterns().iterator(); iterator1.hasNext();) {
                        String exclude = (String) iterator1.next();
                        TypePattern excludePattern = new PatternParser(exclude).parseTypePattern();
                        m_excludeTypePattern.add(excludePattern);
                        fastMatchInfo = looksLikeStartsWith(exclude);
                        if (fastMatchInfo != null) {
                              m_excludeStartsWith.add(fastMatchInfo);
                        }
                  }
            }
      }

      /**
       * Checks if the type pattern can be handled as a startswith check
       * 
       * TODO AV - enhance to support "char.sss" ie FQN direclty (match iff equals) we could also add support for "*..*charss"
       * endsWith style?
       * 
       * @param typePattern
       * @return null if not possible, or the startWith sequence to test against
       */
00560       private String looksLikeStartsWith(String typePattern) {
            if (typePattern.indexOf('@') >= 0 || typePattern.indexOf('+') >= 0 || typePattern.indexOf(' ') >= 0
                        || typePattern.charAt(typePattern.length() - 1) != '*') {
                  return null;
            }
            // now must looks like with "charsss..*" or "cha.rss..*" etc
            // note that "*" and "*..*" won't be fast matched
            // and that "charsss.*" will not neither
            int length = typePattern.length();
            if (typePattern.endsWith("..*") && length > 3) {
                  if (typePattern.indexOf("..") == length - 3 // no ".." before last sequence
                              && typePattern.indexOf('*') == length - 1) { // no "*" before last sequence
                        return typePattern.substring(0, length - 2).replace('$', '.');
                        // ie "charsss." or "char.rss." etc
                  }
            }
            return null;
      }

      /**
       * Register the dump filter
       * 
       * @param weaver
       * @param loader
       * @param definitions
       */
00586       private void registerDump(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
            for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
                  Definition definition = (Definition) iterator.next();
                  for (Iterator iterator1 = definition.getDumpPatterns().iterator(); iterator1.hasNext();) {
                        String dump = (String) iterator1.next();
                        TypePattern pattern = new PatternParser(dump).parseTypePattern();
                        m_dumpTypePattern.add(pattern);
                  }
                  if (definition.shouldDumpBefore()) {
                        m_dumpBefore = true;
                  }
                  if (definition.createDumpDirPerClassloader()) {
                        dumpDirPerClassloader = true;
                  }
            }
      }

      @Override
      protected boolean accept(String className, byte[] bytes) {
            // avoid ResolvedType if not needed
            if (m_excludeTypePattern.isEmpty() && m_includeTypePattern.isEmpty()) {
                  return true;
            }

            // still try to avoid ResolvedType if we have simple patterns
            String fastClassName = className.replace('/', '.').replace('$', '.');
            for (int i = 0; i < m_excludeStartsWith.size(); i++) {
                  if (fastClassName.startsWith((String) m_excludeStartsWith.get(i))) {
                        return false;
                  }
            }

            /*
             * Bug 120363 If we have an exclude pattern that cannot be matched using "starts with" then we cannot fast accept
             */
            if (m_excludeTypePattern.isEmpty()) {
                  boolean fastAccept = false;// defaults to false if no fast include
                  for (int i = 0; i < m_includeStartsWith.size(); i++) {
                        fastAccept = fastClassName.startsWith((String) m_includeStartsWith.get(i));
                        if (fastAccept) {
                              break;
                        }
                  }
            }

            // needs further analysis
            // TODO AV - needs refactoring
            // during LTW this calling resolve at that stage is BAD as we do have the bytecode from the classloader hook
            // but still go thru resolve that will do a getResourcesAsStream on disk
            // this is also problematic for jit stub which are not on disk - as often underlying infra
            // does returns null or some other info for getResourceAsStream (f.e. WLS 9 CR248491)
            // Instead I parse the given bytecode. But this also means it will be parsed again in
            // new WeavingClassFileProvider() from WeavingAdaptor.getWovenBytes()...

            ensureDelegateInitialized(className, bytes);
            ResolvedType classInfo = delegateForCurrentClass.getResolvedTypeX();// BAD:
            // weaver.getWorld().resolve(UnresolvedType.forName(
            // className), true);

            // exclude are "AND"ed
            for (Iterator iterator = m_excludeTypePattern.iterator(); iterator.hasNext();) {
                  TypePattern typePattern = (TypePattern) iterator.next();
                  if (typePattern.matchesStatically(classInfo)) {
                        // exclude match - skip
                        return false;
                  }
            }
            // include are "OR"ed
            boolean accept = true;// defaults to true if no include
            for (Iterator iterator = m_includeTypePattern.iterator(); iterator.hasNext();) {
                  TypePattern typePattern = (TypePattern) iterator.next();
                  accept = typePattern.matchesStatically(classInfo);
                  if (accept) {
                        break;
                  }
                  // goes on if this include did not match ("OR"ed)
            }
            return accept;
      }

      // FIXME we don't use include/exclude of others aop.xml
      // this can be nice but very dangerous as well to change that
      private boolean acceptAspect(String aspectClassName) {
            // avoid ResolvedType if not needed
            if (m_aspectExcludeTypePattern.isEmpty() && m_aspectIncludeTypePattern.isEmpty()) {
                  return true;
            }

            // still try to avoid ResolvedType if we have simple patterns
            // EXCLUDE: if one match then reject
            String fastClassName = aspectClassName.replace('/', '.').replace('.', '$');
            for (int i = 0; i < m_aspectExcludeStartsWith.size(); i++) {
                  if (fastClassName.startsWith((String) m_aspectExcludeStartsWith.get(i))) {
                        return false;
                  }
            }
            // INCLUDE: if one match then accept
            for (int i = 0; i < m_aspectIncludeStartsWith.size(); i++) {
                  if (fastClassName.startsWith((String) m_aspectIncludeStartsWith.get(i))) {
                        return true;
                  }
            }

            // needs further analysis
            ResolvedType classInfo = weaver.getWorld().resolve(UnresolvedType.forName(aspectClassName), true);
            // exclude are "AND"ed
            for (Iterator iterator = m_aspectExcludeTypePattern.iterator(); iterator.hasNext();) {
                  TypePattern typePattern = (TypePattern) iterator.next();
                  if (typePattern.matchesStatically(classInfo)) {
                        // exclude match - skip
                        return false;
                  }
            }
            // include are "OR"ed
            boolean accept = true;// defaults to true if no include
            for (Iterator iterator = m_aspectIncludeTypePattern.iterator(); iterator.hasNext();) {
                  TypePattern typePattern = (TypePattern) iterator.next();
                  accept = typePattern.matchesStatically(classInfo);
                  if (accept) {
                        break;
                  }
                  // goes on if this include did not match ("OR"ed)
            }
            return accept;
      }

      @Override
      protected boolean shouldDump(String className, boolean before) {
            // Don't dump before weaving unless asked to
            if (before && !m_dumpBefore) {
                  return false;
            }

            // avoid ResolvedType if not needed
            if (m_dumpTypePattern.isEmpty()) {
                  return false;
            }

            // TODO AV - optimize for className.startWith only
            ResolvedType classInfo = weaver.getWorld().resolve(UnresolvedType.forName(className), true);
            // dump
            for (Iterator iterator = m_dumpTypePattern.iterator(); iterator.hasNext();) {
                  TypePattern typePattern = (TypePattern) iterator.next();
                  if (typePattern.matchesStatically(classInfo)) {
                        // dump match
                        return true;
                  }
            }
            return false;
      }

      @Override
00738       protected String getDumpDir() {
            if (dumpDirPerClassloader) {
                  StringBuffer dir = new StringBuffer();
                  dir.append("_ajdump").append(File.separator).append(weavingContext.getId());
                  return dir.toString();
            } else {
                  return super.getDumpDir();
            }
      }

      /*
       * shared classes methods
       */

      /**
       * @return Returns the key.
       */
00755       public String getNamespace() {
            // System.out.println("ClassLoaderWeavingAdaptor.getNamespace() classloader=" + weavingContext.getClassLoaderName() +
            // ", namespace=" + namespace);
            if (namespace == null)
                  return "";
            else
                  return new String(namespace);
      }

      /**
       * Check to see if any classes are stored in the generated classes cache. Then flush the cache if it is not empty
       * 
       * @param className TODO
       * @return true if a class has been generated and is stored in the cache
       */
00770       public boolean generatedClassesExistFor(String className) {
            // System.err.println("? ClassLoaderWeavingAdaptor.generatedClassesExist() classname=" + className + ", size=" +
            // generatedClasses);
            if (className == null)
                  return !generatedClasses.isEmpty();
            else
                  return generatedClasses.containsKey(className);
      }

      /**
       * Flush the generated classes cache
       */
00782       public void flushGeneratedClasses() {
            // System.err.println("? ClassLoaderWeavingAdaptor.flushGeneratedClasses() generatedClasses=" + generatedClasses);
            generatedClasses = new HashMap();
      }

      private void defineClass(ClassLoader loader, String name, byte[] bytes) {
            if (trace.isTraceEnabled())
                  trace.enter("defineClass", this, new Object[] { loader, name, bytes });
            Object clazz = null;
            debug("generating class '" + name + "'");

            try {
                  // TODO av protection domain, and optimize
                  Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", new Class[] { String.class, bytes.getClass(),
                              int.class, int.class });
                  defineClass.setAccessible(true);
                  clazz = defineClass.invoke(loader, new Object[] { name, bytes, new Integer(0), new Integer(bytes.length) });
            } catch (InvocationTargetException e) {
                  if (e.getTargetException() instanceof LinkageError) {
                        warn("define generated class failed", e.getTargetException());
                        // is already defined (happens for X$ajcMightHaveAspect interfaces since aspects are reweaved)
                        // TODO maw I don't think this is OK and
                  } else {
                        warn("define generated class failed", e.getTargetException());
                  }
            } catch (Exception e) {
                  warn("define generated class failed", e);
            }

            if (trace.isTraceEnabled())
                  trace.exit("defineClass", clazz);
      }
}

Generated by  Doxygen 1.6.0   Back to index