Package org.aspectj.weaver.tools

Source Code of org.aspectj.weaver.tools.PointcutParser

/*******************************************************************************
* Copyright (c) 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.aspectj.weaver.tools;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;

import org.aspectj.bridge.IMessageHandler;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.SourceLocation;
import org.aspectj.weaver.IHasPosition;
import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.IntMap;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.Shadow;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.World;
import org.aspectj.weaver.bcel.AtAjAttributes;
import org.aspectj.weaver.internal.tools.PointcutExpressionImpl;
import org.aspectj.weaver.internal.tools.TypePatternMatcherImpl;
import org.aspectj.weaver.patterns.AndPointcut;
import org.aspectj.weaver.patterns.CflowPointcut;
import org.aspectj.weaver.patterns.FormalBinding;
import org.aspectj.weaver.patterns.IScope;
import org.aspectj.weaver.patterns.KindedPointcut;
import org.aspectj.weaver.patterns.NotPointcut;
import org.aspectj.weaver.patterns.OrPointcut;
import org.aspectj.weaver.patterns.ParserException;
import org.aspectj.weaver.patterns.PatternParser;
import org.aspectj.weaver.patterns.Pointcut;
import org.aspectj.weaver.patterns.SimpleScope;
import org.aspectj.weaver.patterns.ThisOrTargetAnnotationPointcut;
import org.aspectj.weaver.patterns.ThisOrTargetPointcut;
import org.aspectj.weaver.patterns.TypePattern;
import org.aspectj.weaver.reflect.PointcutParameterImpl;
import org.aspectj.weaver.reflect.ReflectionWorld;

/**
* A PointcutParser can be used to build PointcutExpressions for a
* user-defined subset of AspectJ's pointcut language
*/
public class PointcutParser {
   
  private ReflectionWorld world;
  private ClassLoader classLoader;
    private Set supportedPrimitives;
    private Set pointcutDesignators = new HashSet();
   
    /**
     * @return a Set containing every PointcutPrimitive except
     * if, cflow, and cflowbelow (useful for passing to
     * PointcutParser constructor).
     */
    public static Set getAllSupportedPointcutPrimitives() {
        Set primitives = new HashSet();
        primitives.add(PointcutPrimitive.ADVICE_EXECUTION);
        primitives.add(PointcutPrimitive.ARGS);
        primitives.add(PointcutPrimitive.CALL);
        primitives.add(PointcutPrimitive.EXECUTION);
        primitives.add(PointcutPrimitive.GET);
        primitives.add(PointcutPrimitive.HANDLER);
        primitives.add(PointcutPrimitive.INITIALIZATION);
        primitives.add(PointcutPrimitive.PRE_INITIALIZATION);
        primitives.add(PointcutPrimitive.SET);
        primitives.add(PointcutPrimitive.STATIC_INITIALIZATION);
        primitives.add(PointcutPrimitive.TARGET);
        primitives.add(PointcutPrimitive.THIS);
        primitives.add(PointcutPrimitive.WITHIN);
        primitives.add(PointcutPrimitive.WITHIN_CODE);
        primitives.add(PointcutPrimitive.AT_ANNOTATION);
        primitives.add(PointcutPrimitive.AT_THIS);
        primitives.add(PointcutPrimitive.AT_TARGET);
        primitives.add(PointcutPrimitive.AT_ARGS);
        primitives.add(PointcutPrimitive.AT_WITHIN);
        primitives.add(PointcutPrimitive.AT_WITHINCODE);
        primitives.add(PointcutPrimitive.REFERENCE);
       
        return primitives;
    }
   
    /**
     * Returns a pointcut parser that can parse the full AspectJ pointcut
     * language with the following exceptions:
     * <ul>
     * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
     * <li>Pointcut expressions must be self-contained :- they cannot contain references
     * to other named pointcuts
     * <li>The pointcut expression must be anonymous with no formals allowed.
     * </ul>
     * <p>When resolving types in pointcut expressions, the context classloader is used to find types.</p>
     */
    public static PointcutParser getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution() {
        PointcutParser p =  new PointcutParser();
        p.setClassLoader(Thread.currentThread().getContextClassLoader());
        return p;
    }
   
    /**
     * Returns a pointcut parser that can parse pointcut expressions built
     * from a user-defined subset of AspectJ's supported pointcut primitives.
     * The following restrictions apply:
     * <ul>
     * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
     * <li>Pointcut expressions must be self-contained :- they cannot contain references
     * to other named pointcuts
     * <li>The pointcut expression must be anonymous with no formals allowed.
     * </ul>
     * <p>When resolving types in pointcut expressions, the context classloader is used to find types.</p>
     * @param supportedPointcutKinds a set of PointcutPrimitives this parser
     * should support
     * @throws UnsupportedOperationException if the set contains if, cflow, or
     * cflow below
     */
    public static PointcutParser getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(Set supportedPointcutKinds) {
        PointcutParser p = new PointcutParser(supportedPointcutKinds);
        p.setClassLoader(Thread.currentThread().getContextClassLoader());
        return p;
    }
   
    /**
     * Returns a pointcut parser that can parse the full AspectJ pointcut
     * language with the following exceptions:
     * <ul>
     * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
     * <li>Pointcut expressions must be self-contained :- they cannot contain references
     * to other named pointcuts
     * <li>The pointcut expression must be anonymous with no formals allowed.
     * </ul>
     * <p>When resolving types in pointcut expressions, the given classloader is used to find types.</p>
     */
    public static PointcutParser getPointcutParserSupportingAllPrimitivesAndUsingSpecifiedClassloaderForResolution(ClassLoader classLoader) {
       PointcutParser p =  new PointcutParser();
    p.setClassLoader(classLoader);
    return p;
    }
   
    /**
     * Returns a pointcut parser that can parse pointcut expressions built
     * from a user-defined subset of AspectJ's supported pointcut primitives.
     * The following restrictions apply:
     * <ul>
     * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
     * <li>Pointcut expressions must be self-contained :- they cannot contain references
     * to other named pointcuts
     * <li>The pointcut expression must be anonymous with no formals allowed.
     * </ul>
     * <p>When resolving types in pointcut expressions, the given classloader is used to find types.</p>
     * @param supportedPointcutKinds a set of PointcutPrimitives this parser
     * should support
     * @throws UnsupportedOperationException if the set contains if, cflow, or
     * cflow below
     */
    public static PointcutParser getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(Set supportedPointcutKinds, ClassLoader classLoader) {
       PointcutParser p = new PointcutParser(supportedPointcutKinds);
    p.setClassLoader(classLoader);
    return p;    
    }
   
    /**
     * Create a pointcut parser that can parse the full AspectJ pointcut
     * language with the following exceptions:
     * <ul>
     * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
     * <li>Pointcut expressions must be self-contained :- they cannot contain references
     * to other named pointcuts
     * <li>The pointcut expression must be anonymous with no formals allowed.
     * </ul>
     */
    private PointcutParser() {
        supportedPrimitives = getAllSupportedPointcutPrimitives();
        setClassLoader(PointcutParser.class.getClassLoader());
    }
   
    /**
     * Create a pointcut parser that can parse pointcut expressions built
     * from a user-defined subset of AspectJ's supported pointcut primitives.
     * The following restrictions apply:
     * <ul>
     * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
     * <li>Pointcut expressions must be self-contained :- they cannot contain references
     * to other named pointcuts
     * <li>The pointcut expression must be anonymous with no formals allowed.
     * </ul>
     * @param supportedPointcutKinds a set of PointcutPrimitives this parser
     * should support
     * @throws UnsupportedOperationException if the set contains if, cflow, or
     * cflow below
     */
    private PointcutParser(Set/*<PointcutPrimitives>*/ supportedPointcutKinds) {
        supportedPrimitives = supportedPointcutKinds;
        for (Iterator iter = supportedPointcutKinds.iterator(); iter.hasNext();) {
            PointcutPrimitive element = (PointcutPrimitive) iter.next();
            if ((element == PointcutPrimitive.IF) ||
                (element == PointcutPrimitive.CFLOW) ||
                (element == PointcutPrimitive.CFLOW_BELOW)) {
                throw new UnsupportedOperationException("Cannot handle if, cflow, and cflowbelow primitives");
            }
        }
        setClassLoader(PointcutParser.class.getClassLoader());
    }
   
    /**
     * Set the classloader that this parser should use for
     * type resolution.
     * @param aLoader
     */
    private void setClassLoader(ClassLoader aLoader) {
      this.classLoader = aLoader;
      world = new ReflectionWorld(this.classLoader);
    }

    /**
     * Set the lint properties for this parser from the
     * given resource on the classpath.
     * @param resourcePath path to a file containing aspectj
     * lint properties
     */
    public void setLintProperties(String resourcePath)throws IOException {
      URL url = this.classLoader.getResource(resourcePath);
      InputStream is = url.openStream();
      Properties p = new Properties();
    p.load(is);
    setLintProperties(p);
    }
   
    /**
     * Set the lint properties for this parser from the
     * given properties set.
     * @param properties
     */
    public void setLintProperties(Properties properties) {
      getWorld().getLint().setFromProperties(properties);
    }
   
    /**
     * Register a new pointcut designator handler with this parser.
     * This provides an extension mechansim for the integration of
     * domain-specific pointcut designators with the AspectJ
     * pointcut language.
     * @param designatorHandler
     */
    public void registerPointcutDesignatorHandler(PointcutDesignatorHandler designatorHandler) {
      this.pointcutDesignators.add(designatorHandler);
    }
   
    /**
     * Create a pointcut parameter of the given name and type.
     * @param name
     * @param type
     * @return
     */
    public PointcutParameter createPointcutParameter(String name, Class type) {
      return new PointcutParameterImpl(name,type);
    }

    /**
     * Parse the given pointcut expression.
     * A global scope is assumed for resolving any type references, and the pointcut
     * must contain no formals (variables to be bound).
     * @throws UnsupportedPointcutPrimitiveException if the parser encounters a
     * primitive pointcut expression of a kind not supported by this PointcutParser.
     * @throws IllegalArgumentException if the expression is not a well-formed
     * pointcut expression
     */
    public PointcutExpression parsePointcutExpression(String expression)
    throws UnsupportedPointcutPrimitiveException, IllegalArgumentException {
       return parsePointcutExpression(expression,null,new PointcutParameter[0]);
    }
   
    /**
     * Parse the given pointcut expression.
     * The pointcut is resolved as if it had been declared inside the inScope class
     * (this allows the pointcut to contain unqualified references to other pointcuts
     * declared in the same type for example).
     * The pointcut may contain zero or more formal parameters to be bound at matched
     * join points.
     * @throws UnsupportedPointcutPrimitiveException if the parser encounters a
     * primitive pointcut expression of a kind not supported by this PointcutParser.
     * @throws IllegalArgumentException if the expression is not a well-formed
     * pointcut expression
     */
    public PointcutExpression parsePointcutExpression(
        String expression,
        Class inScope,
        PointcutParameter[] formalParameters)
    throws UnsupportedPointcutPrimitiveException, IllegalArgumentException {
       PointcutExpressionImpl pcExpr = null;
         try {
           PatternParser parser = new PatternParser(expression);
           parser.setPointcutDesignatorHandlers(pointcutDesignators, world);
             Pointcut pc = parser.parsePointcut();
             validateAgainstSupportedPrimitives(pc,expression);
             IScope resolutionScope = buildResolutionScope((inScope == null ? Object.class : inScope),formalParameters);
             pc = pc.resolve(resolutionScope);
             ResolvedType declaringTypeForResolution = null;
             if (inScope != null) {
               declaringTypeForResolution = getWorld().resolve(inScope.getName());
             } else {
               declaringTypeForResolution = ResolvedType.OBJECT.resolve(getWorld());
             }
             IntMap arity = new IntMap(formalParameters.length);
             for (int i = 0; i < formalParameters.length; i++) {
               arity.put(i, i);
             }            
             pc = pc.concretize(declaringTypeForResolution, declaringTypeForResolution, arity);
             validateAgainstSupportedPrimitives(pc,expression); // again, because we have now followed any ref'd pcuts
             pcExpr = new PointcutExpressionImpl(pc,expression,formalParameters,getWorld());
         } catch (ParserException pEx) {
             throw new IllegalArgumentException(buildUserMessageFromParserException(expression,pEx));
         } catch (ReflectionWorld.ReflectionWorldException rwEx) {
             throw new IllegalArgumentException(rwEx.getMessage());
         }
         return pcExpr;
    }
   
    /**
     * Parse the given aspectj type pattern, and return a
     * matcher that can be used to match types using it.
     * @param typePattern an aspectj type pattern
     * @return a type pattern matcher that matches using the given
     * pattern
     * @throws IllegalArgumentException if the type pattern cannot
     * be successfully parsed.
     */
    public TypePatternMatcher parseTypePattern(String typePattern)
    throws IllegalArgumentException {
        try {
          TypePattern tp = new PatternParser(typePattern).parseTypePattern();
          tp.resolve(world);
          return new TypePatternMatcherImpl(tp,world);
        } catch (ParserException pEx) {
            throw new IllegalArgumentException(buildUserMessageFromParserException(typePattern,pEx));
        } catch (ReflectionWorld.ReflectionWorldException rwEx) {
            throw new IllegalArgumentException(rwEx.getMessage());
        }
    }
   
    private World getWorld() {
      return world;
    }
   
    /* for testing */
    Set getSupportedPrimitives() {
      return supportedPrimitives;
    }
   
    /* for testing */
    IMessageHandler setCustomMessageHandler(IMessageHandler aHandler) {
      IMessageHandler current = getWorld().getMessageHandler();
      getWorld().setMessageHandler(aHandler);
      return current;
    }
   
    private IScope buildResolutionScope(Class inScope, PointcutParameter[] formalParameters) {
      if (formalParameters == null) formalParameters = new PointcutParameter[0];
      FormalBinding[] formalBindings = new FormalBinding[formalParameters.length];
      for (int i = 0; i < formalBindings.length; i++) {
      formalBindings[i] = new FormalBinding(UnresolvedType.forName(formalParameters[i].getType().getName()),formalParameters[i].getName(),i);     
    }
      if (inScope == null) {
        return new SimpleScope(getWorld(),formalBindings);
      } else {
        ResolvedType inType = getWorld().resolve(inScope.getName());
        ISourceContext sourceContext = new ISourceContext() {
          public ISourceLocation makeSourceLocation(IHasPosition position) {
            return new SourceLocation(new File(""),0);
          }
          public ISourceLocation makeSourceLocation(int line, int offset) {
            return new SourceLocation(new File(""),line);
          }
          public int getOffset() {
            return 0;
          }
        };
        return new AtAjAttributes.BindingScope(inType,sourceContext,formalBindings);
      }
    }
   
    private void validateAgainstSupportedPrimitives(Pointcut pc, String expression) {
        switch(pc.getPointcutKind()) {
          case Pointcut.AND:
             validateAgainstSupportedPrimitives(((AndPointcut)pc).getLeft(),expression);
             validateAgainstSupportedPrimitives(((AndPointcut)pc).getRight(),expression);
             break;
          case Pointcut.ARGS:
              if (!supportedPrimitives.contains(PointcutPrimitive.ARGS))
                  throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.ARGS);
              break;
          case Pointcut.CFLOW:
          CflowPointcut cfp = (CflowPointcut) pc;
          if (cfp.isCflowBelow()) {
                    throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.CFLOW_BELOW);                       
          } else {
                    throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.CFLOW);           
          }
          case Pointcut.HANDLER:
              if (!supportedPrimitives.contains(PointcutPrimitive.HANDLER))
                  throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.HANDLER);
              break;
          case Pointcut.IF:
          case Pointcut.IF_FALSE:
          case Pointcut.IF_TRUE:
              throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.IF);            
          case Pointcut.KINDED:
            validateKindedPointcut(((KindedPointcut)pc),expression);
              break;
          case Pointcut.NOT:
              validateAgainstSupportedPrimitives(((NotPointcut)pc).getNegatedPointcut(),expression);
              break;
          case Pointcut.OR:
               validateAgainstSupportedPrimitives(((OrPointcut)pc).getLeft(),expression);
            validateAgainstSupportedPrimitives(((OrPointcut)pc).getRight(),expression);
              break;
          case Pointcut.THIS_OR_TARGET:
              boolean isThis = ((ThisOrTargetPointcut)pc).isThis();
            if (isThis && !supportedPrimitives.contains(PointcutPrimitive.THIS)) {
                throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.THIS);
            } else if (!supportedPrimitives.contains(PointcutPrimitive.TARGET)) {
                throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.TARGET);
            }
              break;
          case Pointcut.WITHIN:
              if (!supportedPrimitives.contains(PointcutPrimitive.WITHIN))
                  throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.WITHIN);
              break;
          case Pointcut.WITHINCODE:
              if (!supportedPrimitives.contains(PointcutPrimitive.WITHIN_CODE))
                  throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.WITHIN_CODE);
              break;
          case Pointcut.ATTHIS_OR_TARGET:
                 isThis = ((ThisOrTargetAnnotationPointcut)pc).isThis();
            if (isThis && !supportedPrimitives.contains(PointcutPrimitive.AT_THIS)) {
                throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_THIS);
            } else if (!supportedPrimitives.contains(PointcutPrimitive.AT_TARGET)) {
                throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_TARGET);
            }
              break;        
          case Pointcut.ATARGS:
              if (!supportedPrimitives.contains(PointcutPrimitive.AT_ARGS))
                  throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_ARGS);
              break;
          case Pointcut.ANNOTATION:
            if (!supportedPrimitives.contains(PointcutPrimitive.AT_ANNOTATION))
                  throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_ANNOTATION);
              break;             
          case Pointcut.ATWITHIN:
              if (!supportedPrimitives.contains(PointcutPrimitive.AT_WITHIN))
                  throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_WITHIN);
              break;
          case Pointcut.ATWITHINCODE:
              if (!supportedPrimitives.contains(PointcutPrimitive.AT_WITHINCODE))
                  throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_WITHINCODE);
              break;
          case Pointcut.REFERENCE:
              if (!supportedPrimitives.contains(PointcutPrimitive.REFERENCE))
                  throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.REFERENCE);
              break;           
          case Pointcut.USER_EXTENSION:
            // always ok...
            break;
          case Pointcut.NONE:  // deliberate fall-through
          default:
              throw new IllegalArgumentException("Unknown pointcut kind: " + pc.getPointcutKind());
        }
    }
   
    private void validateKindedPointcut(KindedPointcut pc, String expression) {
      Shadow.Kind kind = pc.getKind();
      if ((kind == Shadow.MethodCall) || (kind == Shadow.ConstructorCall)) {
        if (!supportedPrimitives.contains(PointcutPrimitive.CALL))
          throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.CALL);
      } else if ((kind == Shadow.MethodExecution) || (kind == Shadow.ConstructorExecution)) {
        if (!supportedPrimitives.contains(PointcutPrimitive.EXECUTION))
          throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.EXECUTION);       
      } else if (kind == Shadow.AdviceExecution) {
        if (!supportedPrimitives.contains(PointcutPrimitive.ADVICE_EXECUTION))
          throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.ADVICE_EXECUTION);
      } else if (kind == Shadow.FieldGet) {
        if (!supportedPrimitives.contains(PointcutPrimitive.GET))
          throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.GET);
      } else if (kind == Shadow.FieldSet) {
        if (!supportedPrimitives.contains(PointcutPrimitive.SET))
          throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.SET);           
      } else if (kind == Shadow.Initialization) {
        if (!supportedPrimitives.contains(PointcutPrimitive.INITIALIZATION))
          throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.INITIALIZATION);                       
      } else if (kind == Shadow.PreInitialization) {
        if (!supportedPrimitives.contains(PointcutPrimitive.PRE_INITIALIZATION))
          throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.PRE_INITIALIZATION);                               
      } else if (kind == Shadow.StaticInitialization) {
        if (!supportedPrimitives.contains(PointcutPrimitive.STATIC_INITIALIZATION))
          throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.STATIC_INITIALIZATION);                                       
      }
    }
 
  private String buildUserMessageFromParserException(String pc, ParserException ex) {
    StringBuffer msg = new StringBuffer();
    msg.append("Pointcut is not well-formed: expecting '");
    msg.append(ex.getMessage());
    msg.append("'");
    IHasPosition location = ex.getLocation();
    msg.append(" at character position ");
    msg.append(location.getStart());
    msg.append("\n");
    msg.append(pc);
    msg.append("\n");
    for (int i = 0; i < location.getStart(); i++) {
      msg.append(" ");
    }
    for (int j=location.getStart(); j <= location.getEnd(); j++) {
      msg.append("^");
    }
    msg.append("\n");
    return msg.toString();
  }
}
TOP

Related Classes of org.aspectj.weaver.tools.PointcutParser

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.