Package de.petris.dynamicaspects

Source Code of de.petris.dynamicaspects.AspectAgent$OnLoadAspectWeaver

/*
* Copyright (c) 2004, Marco Petris
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*     - Redistributions of source code must retain the above copyright notice,
*       this list of conditions and the following disclaimer.
*     - Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     - Neither the name of Marco Petris nor the names of its
*       contributors may be used to endorse or promote products derived from
*       this software without specific prior written permission.
*      
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/

package de.petris.dynamicaspects;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.lang.instrument.ClassDefinition;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.regex.Pattern;

import org.apache.bcel.Repository;
import org.apache.bcel.classfile.JavaClass;

import de.petris.dynamicaspects.classhandler.ClassHandler;
import de.petris.dynamicaspects.util.ClassPatcher;
import de.petris.dynamicaspects.util.Reflection;

/**
* The agent which installs/deinstalls aspects.
*
* @author Marco Petris
* @see de.petris.dynamicaspects.Advice
* @see de.petris.dynamicaspects.PointcutFactory
* @see de.petris.dynamicaspects.AdviceFactory
*/
public class AspectAgent {

  // singleton instance
  final static AspectAgent AGENT = new AspectAgent();

  // the instrumentation instance for redefining classes 
  private static Instrumentation instrumentation;

    // a mapping package name -> List of PackageAspects
    static Map<String,List<PackageAspect>> targetPackages;
   
    // a mapping name of class of an advice -> list of its weave types 
    private static Map<String, List<WeaveType>> adviceClassWeaveTypeMapping;
   
    // a mapping target class ->  List of MixIns for the target class
    private static Map<String, List<MixIn>> targetclassMixInMapping;
   
    // flag: true indicates that the mixIns have already been installed
    private static boolean mixInsInstalled;
   
    // todo: not in use yet
    private static List<String> packageList;
  private static boolean onErrorAbort;
   

  public static void setOnErrorAbort(boolean onErrorAbort) {
    AspectAgent.onErrorAbort = onErrorAbort;
  }

    /*
     * todo: not in use yet
     * 
     * @param packageList
     */
  public static void setPackageList(List<String> packageList) {
    AspectAgent.packageList = packageList;
  }

  /**
   * The entry point for the java agent
   *
   * @param options
   * @param i
   */
  public static void premain(
      String options, Instrumentation i ) {
   
    AspectAgent.instrumentation = i;
    AspectAgent.packageList = null;
    AspectAgent.onErrorAbort = false;
        AspectAgent.mixInsInstalled = false;
       
        AspectAgent.targetPackages =
            new HashMap<String,List<PackageAspect>>();
        AspectAgent.adviceClassWeaveTypeMapping =
            new HashMap<String,List<WeaveType>>();
        AspectAgent.targetclassMixInMapping =
            new HashMap<String,List<MixIn>>();
           
        AspectAgent.instrumentation.addTransformer(
                new OnLoadAspectWeaver( targetclassMixInMapping ) );
  }

    /**
     * Installs advices to the given class to all class in the target package at at
     * the given pointcut.
     *
     * @param targetPackage the target package
     * @param adviceClass the class of the advices to be installed
     * @param joinPointPattern the pointcut
     * @param weaveType the weave type for the advices
     */
    public static void install(
            Package targetPackage,
            Class<? extends Advice> adviceClass,
            Pattern joinPointPattern,
            WeaveType weaveType ) {
       
        String packageName = targetPackage.getName().replace( '.', '/' );
        PackageAspect pa = new PackageAspect(
                adviceClass, joinPointPattern, weaveType );
       
        // remember the package for all classes which will be loaded in the future
        if( !targetPackages.containsKey( packageName ) ) {
            Vector<PackageAspect> v = new Vector<PackageAspect>();
            v.add( pa );
            targetPackages.put( packageName, v );
        }
        else {
            targetPackages.get( packageName ).add( pa );
        }
       
        for( Class c : AspectAgent.instrumentation.getAllLoadedClasses() ) {
            if( ( c.getPackage() != null )
                    && ( c.getPackage().equals( targetPackage ) ) ) {
                pa.addWovenClassname( c.getName() );
                install( c, adviceClass, joinPointPattern, weaveType );
            }
        }
       
    }

    /**
     * Installs the given advice to the given class to all class in the target package at at
     * the given pointcut.
     *
     * @param targetPackage the target package
     * @param advice the advice to be installed
     * @param joinPointPattern the pointcut
     * @param weaveType the weave type for the advices
     */
    public static void install(Package targetPackage, Advice advice,
            Pattern joinPointPattern, WeaveType weaveType ) {

        String packageName = targetPackage.getName().replace('.', '/');

        PackageAspect pa = new PackageAspect(
                advice, joinPointPattern, weaveType );
       
        // remember the package for all classes which will be loaded in the future
        if (!targetPackages.containsKey(packageName)) {
            Vector<PackageAspect> v = new Vector<PackageAspect>();
            v.add(pa);
            targetPackages.put(packageName, v);
        } else {
            targetPackages.get(packageName).add( pa );
        }

        for (Class c : AspectAgent.instrumentation.getAllLoadedClasses()) {
            if ((c.getPackage() != null)
                    && (c.getPackage().equals(targetPackage))) {
                pa.addWovenClassname( c.getName() );
                install(c, advice, joinPointPattern, weaveType );
            }
        }

    }

    /**
     * Installs advices to the given class to all class in the target package at at
     * the given pointcut using the given factory.
     *
     * @param targetPackage the target package
     * @param factory
     * @param joinPointPattern
     * @param weaveType
     */
    public static void install(Package targetPackage,
           AdviceFactory factory, Pattern joinPointPattern, WeaveType weaveType ) {

        String packageName = targetPackage.getName().replace('.', '/');

        PackageAspect pa = new PackageAspect(
                factory, joinPointPattern, weaveType );
       
        if (!targetPackages.containsKey(packageName)) {
            Vector<PackageAspect> v = new Vector<PackageAspect>();
            v.add( pa );
            targetPackages.put(packageName, v);
        } else {
            targetPackages.get(packageName).add( pa );
        }

        for (Class c : AspectAgent.instrumentation.getAllLoadedClasses()) {
            if ((c.getPackage() != null)
                    && (c.getPackage().equals(targetPackage))) {
                pa.addWovenClassname( c.getName() );
                install(c, factory, joinPointPattern, weaveType );
            }
        }

    }
   
  /**
     * Installs an aspect of the given aspectClass to the given target class using the
     * given joinpoint pattern and the standard constructor of the aspect.
     * <br>For pattern creation see:
     * {@link de.petris.dynamicaspects.PointcutFactory PointcutFactory} and
     * {@link de.petris.dynamicaspects.util.Reflection Reflection}
     *
   * @param targetClass the target class
   * @param aspectClass the class of the aspect
   * @param joinPointPattern the joinpoint pattern
     * @throws AspectException in case any exception occurrs
     * @see de.petris.dynamicaspects.PointcutFactory
   */
  public static void install(
    Class targetClass, Class<? extends Advice> aspectClass,
        Pattern joinPointPattern, WeaveType weaveType )
      throws AspectException {
    install(
            targetClass, null, aspectClass,
            null, joinPointPattern, weaveType );
  }
 
  /**
     * Installs an aspect returned by the given factory to the given target class using the
     * given joinpoint pattern.
     * <br>For pattern creation see:
     * {@link de.petris.dynamicaspects.PointcutFactory PointcutFactory} and
     * {@link de.petris.dynamicaspects.util.Reflection Reflection}
     *
   * @param targetClass the target class
   * @param factory a factory for the aspect
   * @param joinPointPattern the joinpoint pattern
     * @throws AspectException in case any exception occurrs
     * @see de.petris.dynamicaspects.PointcutFactory
   */
  public static void install(
    Class targetClass, AdviceFactory factory,
        Pattern joinPointPattern, WeaveType weaveType )
      throws AspectException {
    install(
            targetClass, null, null,
            factory, joinPointPattern, weaveType );
  }
 
  /**
     * Installs the given aspect to the given target class using the given
     * joinpoint pattern.
     * <br>For pattern creation see:
     * {@link de.petris.dynamicaspects.PointcutFactory PointcutFactory} and
     * {@link de.petris.dynamicaspects.util.Reflection Reflection}
     *
   * @param targetClass the target class
   * @param aspect the aspect to be installed
   * @param joinPointPattern the joinpoint pattern
     * @see de.petris.dynamicaspects.PointcutFactory
     * @throws AspectException in case any exception occurrs
   */
  static void install(
      Class targetClass, Advice aspect,
            Pattern joinPointPattern, WeaveType weaveType )
      throws AspectException {
    install(
            targetClass, aspect, null,
            null, joinPointPattern, weaveType );
  }
 
  /**
     * Installs an aspect of the given aspectClass to the given target class using the
     * given joinpoint pattern and the standard constructor of the aspect.
     * <br>For pattern creation see:
     * {@link de.petris.dynamicaspects.PointcutFactory PointcutFactory} and
     * {@link de.petris.dynamicaspects.util.Reflection Reflection}
     *
     * @param targetClass the target class
     * @param aspectClass the class of the aspect
     * @param joinPointPattern the joinpoint pattern
     * @see de.petris.dynamicaspects.PointcutFactory
     * @throws AspectException in case any exception occurrs
   */
  public static void install(
      Class targetClass, Class<? extends Advice> aspectClass,
            String joinPointPattern, WeaveType weaveType )
      throws AspectException {
    Pattern p = Pattern.compile( joinPointPattern );
    install(
            targetClass, null, aspectClass,
            null, p, weaveType );
  }
 
    /**
     * Installs an aspect returned by the given factory to the given target class using the
     * given joinpoint pattern.
     * <br>For pattern creation see:
     * {@link de.petris.dynamicaspects.PointcutFactory PointcutFactory} and
     * {@link de.petris.dynamicaspects.util.Reflection Reflection}
     *
     * @param targetClass the target class
     * @param factory a factory for the aspect
     * @param joinPointPattern the joinpoint pattern
     * @see de.petris.dynamicaspects.PointcutFactory
     * @throws AspectException in case any exception occurrs
     */
  public static void install(
      Class targetClass, AdviceFactory factory,
            String joinPointPattern, WeaveType weaveType )
      throws AspectException {
    Pattern p = Pattern.compile(joinPointPattern);
    install(
            targetClass, null,
            null, factory, p, weaveType );
  }
 
    /**
     * Installs the given aspect to the given target class using the given
     * joinpoint pattern.
     *
     * @param targetClass the target class
     * @param aspect the aspect to be installed
     * @param joinPointPattern the joinpoint pattern
     * @throws AspectException in case any exception occurrs
     */
  static void install(
      Class targetClass, Advice aspect,
            String joinPointPattern, WeaveType weaveType )
      throws AspectException {
    Pattern p = Pattern.compile( joinPointPattern );
    install(
            targetClass, aspect, null,
            null, p, weaveType );
  }

 
  /**
     * Installs an aspect to the given targetclass using the given joinpoint pattern.
     * The aspect to be installed can be given by argument directly or is created either
     * by the given class or by the given factory. One of the three
     * ( aspect instance, aspect class or aspect factory ) must not be null.
     *
   * @param targetClass the target class
   * @param aspect the instance of the aspect or null
   * @param aspectClass the class of the aspect or null
   * @param factory the factory for the aspect or null
   * @param joinPointPattern the joinpoint pattern
     * @throws AspectException in case any exception occurrs
   */
  private static void install(
    Class targetClass, Advice aspect, Class<? extends Advice> aspectClass,
    AdviceFactory factory, Pattern joinPointPattern, WeaveType weaveType )
      throws AspectException {

    if( checkPackage( aspectClass ) ) {
      try {
        // JDK1.5 BUG ID: 6191049 ( fixed as 5092850 )
        // link class before redefinition:
        targetClass.getDeclaredFields();
       
        JavaClass jc = Repository.lookupClass(targetClass.getName());
        if( aspect != null ) {
          AGENT.applyAspect(
                            jc, aspect, joinPointPattern, weaveType );
        }
        else if( aspectClass != null ) {
          AGENT.applyAspect(
                            jc, aspectClass, joinPointPattern, weaveType );
        }
        else {
          AGENT.applyAspect(
                            jc, factory, joinPointPattern, weaveType );
        }
        AGENT.redefine(targetClass, jc);
      } catch( Exception exc ) {
        throw new AspectException( exc );
      }
    }
  }

    /**
     * Deinstalls all advices of the given class from all target classes of the given package.
     *
     * @param p the package the target classes
     * @param adviceClass the class of the advices
     */
    public static void deinstall( Package p , Class<? extends Advice> adviceClass ) {
       
        String packageName = p.getName().replace( '.', '/' );
       
        List<PackageAspect> list = targetPackages.get( packageName );
       
        if( list != null ) {
            for( PackageAspect pa : list ) {
                if( ( ( pa.getAdviceClass() != null )
                        && ( pa.getAdviceClass().getName().equals( adviceClass.getName() ) ) )
                    ||
                    ( pa.getAdvice() != null )
                        && ( pa.getAdvice().getClass().getName().equals(
                                adviceClass.getName() ) ) ) {
                    pa.removeAspect();
                }
            }
        }
       
    }
   
    /**
     * Deinstalls the advice from all target classes of the given package.
     *
     * @param p the package the target classes
     * @param advice the advice to be deinstalled
     */
    public static void deinstall( Package p , Advice advice ) {
        String packageName = p.getName().replace( '.', '/' );
       
        List<PackageAspect> list = targetPackages.get( packageName );
       
        if( list != null ) {
            for( PackageAspect pa : list ) {
                if( ( pa.getAdvice() != null )
                        && ( pa.getAdvice().equals( advice ) ) ) {
                    pa.removeAspect();
                }
            }
        }
    }

   
  /**
   * Deinstalls the aspect instance from the targetClass.
   *
   * @param targetClass the target class
   * @param advice the aspect instance to be installed
     * @throws AspectException in case any exception occurrs
   */
  public static void deinstall(Class targetClass, Advice advice)
      throws AspectException {
   
    try {
      JavaClass jc = Repository.lookupClass(targetClass.getName());
      AGENT.removeAspect(jc, advice);
      AGENT.redefine(targetClass, jc);
    } catch( Exception exc ) {
      throw new AspectException( exc );
    }
  }

  /**
   * Deinstalls aspects of the given aspectClass from the targetClass.
   *
   * @param targetClass the target class
   * @param adviceClass the advice class
     * @throws AspectException in case any exception occurrs
   */
  public static void deinstall(Class targetClass, Class<? extends Advice> adviceClass )
        throws AspectException {
       
    try {
      JavaClass jc = Repository.lookupClass(targetClass.getName());
      AGENT.removeAspect(jc, adviceClass);
      AGENT.redefine(targetClass, jc);
    } catch( Exception exc ) {
      throw new AspectException( exc );
    }
  }
 
 
  /**
   * Redefines the given oldClass using the given newClass.
   *
   * @param oldClass the old class definition
   * @param newClass the new class definition
   * @throws Throwable in case anything goes wrong
   */
  private void redefine( Class oldClass, JavaClass newClass )
    throws Exception {

    ByteArrayOutputStream byteArrayOs = new ByteArrayOutputStream();
    newClass.dump( new DataOutputStream( byteArrayOs ) );
   
//    newClass.dump( oldClass.getName() + "_new.class");
    // todo: debug, maybe save feature
   
    instrumentation.redefineClasses(
      new ClassDefinition[] {
        new ClassDefinition(
            oldClass,
            byteArrayOs.toByteArray() ) } );
  }

  /**
     * Applies an aspect to the given target class using the given joinpoint pattern
   * @param targetClass the target class
   * @param factory the factory for the aspect
   * @param joinPointPattern the joinpoint pattern
   */
  void applyAspect(
    JavaClass targetClass, AdviceFactory factory,
    Pattern joinPointPattern, WeaveType weaveType ) {

    ClassHandler cHandler =
            weaveType.getClassHandler( targetClass.getClassName() );
   
    cHandler.setTargetClass(targetClass);
   
    cHandler.install( factory, joinPointPattern );
       
        addAdviceWeaveTypeMapping(
                factory.getAdviceClassName(), weaveType );
  }
 
  /**
     * Applies an aspect to the given target class using the given joinpoint pattern
     * @param targetClass the target class
   * @param aspectClass the class of the aspect
     * @param joinPointPattern the joinpoint pattern
   */
  void applyAspect(
    JavaClass targetClass, Class<? extends Advice> aspectClass,
    Pattern joinPointPattern, WeaveType weaveType ) {

    ClassHandler cHandler =
            weaveType.getClassHandler( targetClass.getClassName() );
   
    cHandler.setTargetClass(targetClass);
   
    cHandler.install( aspectClass, joinPointPattern );
       
        addAdviceWeaveTypeMapping( aspectClass.getName(), weaveType );
  }
   
  /**
     * Applies an aspect to the given target class using the given joinpoint pattern
     * @param targetClass the target class
   * @param aspect the aspect instance
   * @param joinPointPattern the joinpoint pattern
   */
  void applyAspect(
      JavaClass targetClass, Advice aspect,
            Pattern joinPointPattern, WeaveType weaveType ) {

    ClassHandler cHandler =
            weaveType.getClassHandler( targetClass.getClassName()  );
   
    cHandler.setTargetClass(targetClass);
    cHandler.install( aspect, joinPointPattern );
        addAdviceWeaveTypeMapping(
                aspect.getClass().getName(), weaveType );
  }

  /**
   * Removes the aspect from the targetClass.
   *
   * @param targetClass the target class
   * @param aspectClass the aspect class
   * @throws Throwable in case anything goes wrong
   */
  private void removeAspect(
    JavaClass targetClass, Class<? extends Advice> aspectClass ) {

        List<WeaveType> types =
            adviceClassWeaveTypeMapping.get( aspectClass.getName() );

        if( types != null ) {
            for( WeaveType type : types ) {
               
            ClassHandler cHandler =
                    type.getClassHandler( targetClass.getClassName() );
           
            cHandler.setTargetClass( targetClass );
            cHandler.deinstall( aspectClass );
            }
//todo: remove only when all classes have been cleaned           
//            adviceClassWeaveTypeMapping.remove( aspectClass.getName() );
        }
  }

  /**
   * Removes the aspect instance from the targetClass.
   *
   * @param targetClass the target class
   * @param aspect the aspect instance
   * @throws Throwable in case anything goes wrong
   */
  private void removeAspect(
    JavaClass targetClass, Advice aspect ) {

        for( WeaveType type :
            adviceClassWeaveTypeMapping.get( aspect.getClass().getName() ) ) {
           
            ClassHandler cHandler =
                type.getClassHandler( targetClass.getClassName() );
           
            cHandler.setTargetClass( targetClass );
            cHandler.deinstall( aspect );
        }
       
        adviceClassWeaveTypeMapping.remove( aspect.getClass().getName() );

  }

  /**
   * Checks if the package of the aspectClass belongs to
   * the predefined package list.
   *
   * @param aspectClass the aspect class
   * @return true if the package belongs to the list, else false.
   */
  private static boolean checkPackage(Class aspectClass) {
    if ((packageList != null)
      && !packageList.contains(aspectClass.getPackage().getName())) {

      SecurityException se = new SecurityException("the "
          + aspectClass.getPackage()
          + " is not in the predefined package list\n" + " aspect "
          + aspectClass.getName() + " can NOT be installed ");

      if (onErrorAbort) {
        throw se;
      } else {
        se.printStackTrace();
      }

      return false;
    }

    return true;
  }
   
    /**
     * Adds the weave type to the advice class. 
     *
     * @param adviceClassName the name of the advice class
     * @param type the weaveType
     */
    private void addAdviceWeaveTypeMapping(
            String adviceClassName, WeaveType type ) {
       
        if( !adviceClassWeaveTypeMapping.containsKey( adviceClassName ) ) {
            Vector<WeaveType> v = new Vector<WeaveType>();
            v.add( type );
            adviceClassWeaveTypeMapping.put( adviceClassName, v );
        }
        else {
            adviceClassWeaveTypeMapping.get(
                    adviceClassName ).add( type );
        }
    }
   
    /**
     * Adds a MixIn.
     *
     * @param mixIn the mixIn to be added.
     */
    public static void addMixIn( MixIn mixIn ) {
       
        if( mixInsInstalled ) {
            throw new AspectException(
                    "due to restrictions of the " +
                    "Instrumentation class provided by the JDK " +
                    "it is not ( yet ) possible to add a mixin " +
                    "once you have installed MixIns via " +
                    "installMixIns()-Method call, please add all " +
                    "mixins prior to installation " );
        }
       
        MixInTargets targets =
            mixIn.getClass().getAnnotation( MixInTargets.class );
       
        if( targets != null ) {
            for( String target : targets.getTargetClassNames() ) {
                String nonDottedClassname = target.replace('.', '/' );
               
                if( !targetclassMixInMapping.containsKey(
                        nonDottedClassname ) ) {
                   
                    List<MixIn> mixInList = new Vector<MixIn>();
                    mixInList.add( mixIn );

                    targetclassMixInMapping.put(
                            nonDottedClassname, mixInList );
                }
                else {
                    targetclassMixInMapping.get(
                            nonDottedClassname ).add( mixIn );
                }
            }
        }
        else {
            //todo:
            System.out.println( "no targets found" );
        }
                   
       
    }
   
    /**
     * Installs all added MixIns.
     */
    public static void installMixIns() {
        mixInsInstalled = true;
       
        for( String target : targetclassMixInMapping.keySet() ) {
            try {
                Class.forName( target.replace( '/', '.' ) );
            }
            catch( ClassNotFoundException cfe ) {
                throw new AspectException(
                    "stopping mixIn installation. tried to load class "
                    + target,
                    cfe );
            }
        }
    }
   
    /**
     * A onload aspect weaver.
     *
     * @author Marco Petris
     */
    private static class OnLoadAspectWeaver implements ClassFileTransformer {
       
        private Map<String, List<MixIn>> targetclassMixIns;
       
        public OnLoadAspectWeaver( Map<String, List<MixIn>> targetclassMixInMapping ) {
            this.targetclassMixIns = targetclassMixInMapping;
        }
       
       
        public byte[] transform(ClassLoader loader, String className,
                Class< ? > classBeingRedefined,
                ProtectionDomain protectionDomain, byte[] classfileBuffer)
            throws IllegalClassFormatException {
           
            if ( classBeingRedefined == null ) {
               
                byte[] modifiedBuffer = null;
               
                if( targetclassMixIns.containsKey( className ) ) {
                    modifiedBuffer = new ClassPatcher(
                            classfileBuffer, className,
                            targetclassMixIns.get(
                                    className ) ).patchClass();
                }
                           

                // todo: should be a regular expression pattern matching
                if( ( !targetPackages.isEmpty() ) 
                    && ( targetPackages.containsKey( className.substring(
                            0, className.lastIndexOf( '/' ) ) ) ) ) {
                   
                    if( modifiedBuffer == null ) {
                        modifiedBuffer = classfileBuffer;
                    }

                    modifiedBuffer =
                        applyPackageAspect( modifiedBuffer, className );
                }
               
                return modifiedBuffer;
            }
            return null;
        }
       
       
        /**
         * Applies aspects to the class in the buffer with the given name.
         *
         * @param classfileBuffer the original version of the class
         * @param className the name of the class
         * @return the new version of the class
         */
        private byte[] applyPackageAspect( byte[] classfileBuffer, 
                String className ) {
           
                JavaClass jc =
                    Reflection.classForByteArray( classfileBuffer, className );
               
                for( PackageAspect pa :
                    targetPackages.get(
                      className.substring(
                              0, className.lastIndexOf( '/' ) ) ) ) {
                
                    pa.applyAspect( jc );
                }
               
                return jc.getBytes();
        }
       
    }
   
    /**
     * An aspect which has been added to a package.
     *
     * @author Marco Petris
     */
    private static class PackageAspect {

        private Advice advice;
        private Pattern pattern;
        private WeaveType type;
       
        private Class<? extends Advice> adviceClass;
        private AdviceFactory factory;
        private List<String> wovenClasses;
       
        /**
         * @param aspect
         * @param pattern
         */
        public PackageAspect(
                Advice advice, Pattern pattern, WeaveType type ) {
            super();
            this.advice = advice;
            this.pattern = pattern;
            this.type = type;
            this.wovenClasses = new Vector<String>();
        }
       
        /**
         * @param pattern
         * @param aspectClass
         */
        public PackageAspect(
                Class< ? extends Advice> adviceClass,
                Pattern pattern, WeaveType type ) {
           
            super();
            this.pattern = pattern;
            this.adviceClass = adviceClass;
            this.type = type;
            this.wovenClasses = new Vector<String>();
        }
       
        /**
         * @param pattern
         * @param factory
         */
        public PackageAspect(
                AdviceFactory factory,
                Pattern pattern, WeaveType type ) {
            super();
            this.pattern = pattern;
            this.factory = factory;
            this.type = type;
            this.wovenClasses = new Vector<String>();
        }
       
        /**
         * Applies the package aspect to the target class
         * @param jc the target class
         */
        public void applyAspect( JavaClass jc ) {
           
            addWovenClassname( jc.getClassName() );
           
            if( advice != null ) {
                AGENT.applyAspect( jc, advice, pattern, type );
            }
            else if( adviceClass != null ) {
                AGENT.applyAspect(
                        jc, adviceClass, pattern, type );
            }
            else {
                AGENT.applyAspect( jc, factory, pattern, type );
            }
        }
       
        /**
         * @param name the name of a woven class
         */
        public void addWovenClassname( String name ) {
            wovenClasses.add( name );
        }
       
        /**
         * Removes the package aspect.
         */
        public void removeAspect() {
            for( String classname : wovenClasses ) {
                if( advice != null ) {
                    AspectAgent.deinstall(
                        Reflection.classForName( classname ), advice );
                }
                else if( adviceClass != null ) {
                    AspectAgent.deinstall(
                        Reflection.classForName( classname ), adviceClass );
                }
            }
            // todo: this is too simple
            wovenClasses.clear();
        }

        /**
         * @return the inner advice, or null
         */
        public Advice getAdvice() {
            return advice;
        }

        /**
         * @return the class of the advice, or null
         */
        public Class< ? extends Advice> getAdviceClass() {
            return adviceClass;
        }
       
       
    }
           
}
TOP

Related Classes of de.petris.dynamicaspects.AspectAgent$OnLoadAspectWeaver

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.