maven-m2-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jvan...@apache.org
Subject cvs commit: maven-components/maven-core/src/test/resources pom.xml
Date Sun, 05 Dec 2004 21:45:36 GMT
jvanzyl     2004/12/05 13:45:36

  Modified:    maven-core pom.xml
               maven-core/src/main/java/org/apache/maven/lifecycle/goal/phase
                        GoalAttainmentPhase.java
               maven-core/src/main/java/org/apache/maven/plugin
                        DefaultPluginManager.java
               maven-core/src/test/resources pom.xml
  Added:       maven-core/src/main/java/org/apache/maven/plugin
                        PluginParameterExpressionEvaluator.java
                        ReflectionProjectValueExtractor.java
               maven-core/src/main/java/org/apache/maven/util/introspection
                        ClassMap.java MethodMap.java
               maven-core/src/test/java/org/apache/maven/plugin
                        PluginParameterExpressionEvaluatorTest.java
                        ReflectionProjectValueExtractorTest.java
  Removed:     maven-core/src/main/java/org/apache/maven/plugin
                        OgnlProjectValueExtractor.java
               maven-core/src/test/java/org/apache/maven/plugin
                        OgnlProjectValueExtractorTest.java
  Log:
  o removing the use of OGNL, snagged some classes from velocity to do
    the plugin parameter expression evaluation.
  
  Revision  Changes    Path
  1.14      +0 -5      maven-components/maven-core/pom.xml
  
  Index: pom.xml
  ===================================================================
  RCS file: /home/cvs/maven-components/maven-core/pom.xml,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- pom.xml	5 Dec 2004 04:16:07 -0000	1.13
  +++ pom.xml	5 Dec 2004 21:45:35 -0000	1.14
  @@ -48,11 +48,6 @@
         <version>1.0-beta-3</version>
       </dependency>
       <dependency>
  -      <groupId>ognl</groupId>
  -      <artifactId>ognl</artifactId>
  -      <version>2.5.1</version>
  -    </dependency>
  -    <dependency>
         <groupId>maven</groupId>
         <artifactId>wagon-provider-api</artifactId>
         <version>1.0-alpha-2-SNAPSHOT</version>
  
  
  
  1.7       +3 -3      maven-components/maven-core/src/main/java/org/apache/maven/lifecycle/goal/phase/GoalAttainmentPhase.java
  
  Index: GoalAttainmentPhase.java
  ===================================================================
  RCS file: /home/cvs/maven-components/maven-core/src/main/java/org/apache/maven/lifecycle/goal/phase/GoalAttainmentPhase.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- GoalAttainmentPhase.java	5 Dec 2004 04:16:03 -0000	1.6
  +++ GoalAttainmentPhase.java	5 Dec 2004 21:45:35 -0000	1.7
  @@ -19,7 +19,7 @@
   import org.apache.maven.lifecycle.goal.AbstractMavenGoalPhase;
   import org.apache.maven.lifecycle.goal.GoalExecutionException;
   import org.apache.maven.lifecycle.goal.MavenGoalExecutionContext;
  -import org.apache.maven.plugin.OgnlProjectValueExtractor;
  +import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
   import org.apache.maven.plugin.Plugin;
   import org.apache.maven.plugin.PluginExecutionRequest;
   import org.apache.maven.plugin.PluginExecutionResponse;
  @@ -121,7 +121,7 @@
   
                   String expression = parameter.getExpression();
   
  -                Object value = OgnlProjectValueExtractor.evaluate( expression, context );
  +                Object value = PluginParameterExpressionEvaluator.evaluate( expression, context );
   
                   map.put( key, value );
               }
  
  
  
  1.20      +1 -3      maven-components/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginManager.java
  
  Index: DefaultPluginManager.java
  ===================================================================
  RCS file: /home/cvs/maven-components/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginManager.java,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- DefaultPluginManager.java	5 Dec 2004 04:16:04 -0000	1.19
  +++ DefaultPluginManager.java	5 Dec 2004 21:45:35 -0000	1.20
  @@ -234,9 +234,7 @@
               "plexus-container-default",
               "plexus-artifact-container",
               "plexus-utils",
  -            "xpp3",
  -            "classworlds",
  -            "ognl"
  +            "classworlds"
           } );
   
           // TODO: move this to be configurable from the Maven component
  
  
  
  1.1                  maven-components/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterExpressionEvaluator.java
  
  Index: PluginParameterExpressionEvaluator.java
  ===================================================================
  package org.apache.maven.plugin;
  
  /*
   * Copyright 2001-2004 The Apache Software Foundation.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  import org.apache.maven.lifecycle.goal.MavenGoalExecutionContext;
  import org.apache.maven.project.MavenProject;
  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
  
  /**
   * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
   * @version $Id: PluginParameterExpressionEvaluator.java,v 1.1 2004/12/05 21:45:35 jvanzyl Exp $
   */
  public class PluginParameterExpressionEvaluator
  {
      public static Object evaluate( String expression, MavenGoalExecutionContext context )
          throws PluginConfigurationException
      {
          Object value = null;
  
          if ( expression.startsWith( "#component" ) )
          {
              String role = expression.substring( 11 );
  
              try
              {
                  value = context.lookup( role );
              }
              catch ( ComponentLookupException e )
              {
                  // do nothing
              }
          }
          else if ( expression.equals( "#localRepository" ) )
          {
              value = context.getSession().getLocalRepository();
          }
          else if ( expression.equals( "#maven.repo.local" ) )
          {
              // TODO: remove this alias: but note that it is a string instead of an ArtifactRepository
              value = context.getSession().getLocalRepository().getUrl().substring( "file://".length() );
          }
          else if ( expression.equals( "#maven.final.name" ) )
          {
              // TODO: remove this alias
              value = context.getProject().getModel().getBuild().getFinalName();
          }
          else if ( expression.equals( "#project" ) )
          {
              value = context.getProject();
          }
          else if ( expression.startsWith( "#project" ) )
          {
              try
              {
                  int pathSeparator = expression.indexOf( "/" );
  
                  if ( pathSeparator > 0 )
                  {
                      value = getValue( expression.substring( 9, pathSeparator ), context.getProject() )
                          + expression.substring( pathSeparator );
                  }
                  else
                  {
                      value = getValue( expression.substring( 9 ), context.getProject() );
                  }
              }
              catch ( Exception e )
              {
                  throw new PluginConfigurationException( "Error evaluating plugin parameter expression: " + expression, e );
              }
          }
          else if ( expression.equals( "#basedir" ) )
          {
              value = context.getProject().getFile().getParentFile().getAbsolutePath();
          }
          else if ( expression.startsWith( "#basedir" ) )
          {
              int pathSeparator = expression.indexOf( "/" );
  
              if ( pathSeparator > 0 )
              {
                  value = context.getProject().getFile().getParentFile().getAbsolutePath()
                      + expression.substring( pathSeparator );
              }
              else
              {
                  new Exception( "Got expression '" + expression + "' that was not recognised" ).printStackTrace();
              }
          }
          else if ( expression.startsWith( "#" ) )
          {
              // We will attempt to get nab a system property as a way to specify a
              // parameter to a plugins. My particular case here is allowing the surefire
              // plugin to run a single test so I want to specify that class on the cli
              // as a parameter.
  
              value = System.getProperty( expression.substring( 1 ) );
          }
  
          // ----------------------------------------------------------------------              
          // If we strike and we are not dealing with an expression then we will
          // will let the value pass through unaltered so that users can hardcode
          // literal values. Expressions that evaluate to null will be passed
          // through as null so that the validator can see the null value and
          // act in accordance with the requirements laid out in the
          // mojo descriptor.
          // ----------------------------------------------------------------------
  
          if ( value == null && !expression.startsWith( "#" ) )
          {
              value = expression;
          }
  
          return value;
      }
  
      private static Object getValue( String expression, MavenProject project )
          throws Exception
      {
  
          expression = "project." + expression;
  
          System.out.println( "expression = " + expression );
  
          return ReflectionProjectValueExtractor.evaluate( expression, project );
      }
  }
  
  
  
  
  1.1                  maven-components/maven-core/src/main/java/org/apache/maven/plugin/ReflectionProjectValueExtractor.java
  
  Index: ReflectionProjectValueExtractor.java
  ===================================================================
  package org.apache.maven.plugin;
  
  import org.apache.maven.util.introspection.ClassMap;
  import org.apache.maven.project.MavenProject;
  import org.codehaus.plexus.util.StringUtils;
  
  import java.util.StringTokenizer;
  import java.util.Map;
  import java.util.HashMap;
  import java.lang.reflect.Method;
  
  /**
   * Using simple dotted expressions extract the values from a MavenProject
   * instance, For example we might want to extract a value like:
   *
   * project.build.sourceDirectory
   *
   * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
   * @version $Id: ReflectionProjectValueExtractor.java,v 1.1 2004/12/05 21:45:35 jvanzyl Exp $
   */
  public class ReflectionProjectValueExtractor
  {
      private static Class[] args = new Class[0];
  
      private static Object[] params = new Object[0];
  
      private static ClassMap classMap;
      
      private static Map classMaps = new HashMap();
  
      public static Object evaluate( String expression, MavenProject project )
          throws Exception
      {
          // ----------------------------------------------------------------------
          // Remove the leading "project" token
          // ----------------------------------------------------------------------
  
          expression = expression.substring( expression.indexOf( '.' ) + 1 );
  
          Object value = project;
  
          // ----------------------------------------------------------------------
          // Walk the dots and retrieve the ultimate value desired from the
          // MavenProject instance.
          // ----------------------------------------------------------------------
  
          StringTokenizer parser = new StringTokenizer( expression, "." );
  
          while( parser.hasMoreTokens() )
          {
              classMap = getClassMap( value.getClass() );
  
              String token = parser.nextToken();
  
              String methodName = "get" + StringUtils.capitalise( token );
  
              Method method = classMap.findMethod( methodName, args );
  
              value = method.invoke( value, params );
          }
  
          return value;
      }
  
      private static ClassMap getClassMap( Class clazz )
      {
          classMap = (ClassMap) classMaps.get( clazz );
  
          if ( classMap == null )
          {
              classMap = new ClassMap( clazz );
          }
  
          return classMap;
      }
  }
  
  
  
  1.1                  maven-components/maven-core/src/main/java/org/apache/maven/util/introspection/ClassMap.java
  
  Index: ClassMap.java
  ===================================================================
  package org.apache.maven.util.introspection;
  
  /*
   * Copyright 2001-2004 The Apache Software Foundation.
   *
   * Licensed under the Apache License, Version 2.0 (the "License")
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  import java.lang.reflect.Method;
  import java.lang.reflect.Modifier;
  import java.util.Hashtable;
  import java.util.Map;
  
  /**
   * A cache of introspection information for a specific class instance.
   * Keys {@link java.lang.Method} objects by a concatenation of the
   * method name and the names of classes that make up the parameters.
   *
   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
   * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
   * @author <a href="mailto:szegedia@freemail.hu">Attila Szegedi</a>
   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
   * @version $Id: ClassMap.java,v 1.1 2004/12/05 21:45:35 jvanzyl Exp $
   */
  public class ClassMap
  {
      private static final class CacheMiss
      {
      }
  
      private static final CacheMiss CACHE_MISS = new CacheMiss();
      private static final Object OBJECT = new Object();
  
      /**
       * Class passed into the constructor used to as
       * the basis for the Method map.
       */
  
      private Class clazz;
  
      /**
       * Cache of Methods, or CACHE_MISS, keyed by method
       * name and actual arguments used to find it.
       */
      private Map methodCache = new Hashtable();
  
      private MethodMap methodMap = new MethodMap();
  
      /**
       * Standard constructor
       */
      public ClassMap( Class clazz )
      {
          this.clazz = clazz;
          populateMethodCache();
      }
  
      /**
       * @return the class object whose methods are cached by this map.
       */
      Class getCachedClass()
      {
          return clazz;
      }
  
      /**
       * Find a Method using the methodKey
       * provided.
       * <p/>
       * Look in the methodMap for an entry.  If found,
       * it'll either be a CACHE_MISS, in which case we
       * simply give up, or it'll be a Method, in which
       * case, we return it.
       * <p/>
       * If nothing is found, then we must actually go
       * and introspect the method from the MethodMap.
       */
      public Method findMethod( String name, Object[] params )
          throws MethodMap.AmbiguousException
      {
          String methodKey = makeMethodKey( name, params );
          Object cacheEntry = methodCache.get( methodKey );
  
          if ( cacheEntry == CACHE_MISS )
          {
              return null;
          }
  
          if ( cacheEntry == null )
          {
              try
              {
                  cacheEntry = methodMap.find( name,
                                               params );
              }
              catch ( MethodMap.AmbiguousException ae )
              {
                  /*
                   *  that's a miss :)
                   */
  
                  methodCache.put( methodKey,
                                   CACHE_MISS );
  
                  throw ae;
              }
  
              if ( cacheEntry == null )
              {
                  methodCache.put( methodKey,
                                   CACHE_MISS );
              }
              else
              {
                  methodCache.put( methodKey,
                                   cacheEntry );
              }
          }
  
          // Yes, this might just be null.
          
          return (Method) cacheEntry;
      }
  
      /**
       * Populate the Map of direct hits. These
       * are taken from all the public methods
       * that our class provides.
       */
      private void populateMethodCache()
      {
          StringBuffer methodKey;
  
          /*
           *  get all publicly accessible methods
           */
  
          Method[] methods = getAccessibleMethods( clazz );
  
          /*
           * map and cache them
           */
  
          for ( int i = 0; i < methods.length; i++ )
          {
              Method method = methods[i];
  
              /*
               *  now get the 'public method', the method declared by a 
               *  public interface or class. (because the actual implementing
               *  class may be a facade...
               */
  
              Method publicMethod = getPublicMethod( method );
  
              /*
               *  it is entirely possible that there is no public method for
               *  the methods of this class (i.e. in the facade, a method
               *  that isn't on any of the interfaces or superclass
               *  in which case, ignore it.  Otherwise, map and cache
               */
  
              if ( publicMethod != null )
              {
                  methodMap.add( publicMethod );
                  methodCache.put( makeMethodKey( publicMethod ), publicMethod );
              }
          }
      }
  
      /**
       * Make a methodKey for the given method using
       * the concatenation of the name and the
       * types of the method parameters.
       */
      private String makeMethodKey( Method method )
      {
          Class[] parameterTypes = method.getParameterTypes();
  
          StringBuffer methodKey = new StringBuffer( method.getName() );
  
          for ( int j = 0; j < parameterTypes.length; j++ )
          {
              /*
               * If the argument type is primitive then we want
               * to convert our primitive type signature to the 
               * corresponding Object type so introspection for
               * methods with primitive types will work correctly.
               */
              if ( parameterTypes[j].isPrimitive() )
              {
                  if ( parameterTypes[j].equals( Boolean.TYPE ) )
                      methodKey.append( "java.lang.Boolean" );
                  else if ( parameterTypes[j].equals( Byte.TYPE ) )
                      methodKey.append( "java.lang.Byte" );
                  else if ( parameterTypes[j].equals( Character.TYPE ) )
                      methodKey.append( "java.lang.Character" );
                  else if ( parameterTypes[j].equals( Double.TYPE ) )
                      methodKey.append( "java.lang.Double" );
                  else if ( parameterTypes[j].equals( Float.TYPE ) )
                      methodKey.append( "java.lang.Float" );
                  else if ( parameterTypes[j].equals( Integer.TYPE ) )
                      methodKey.append( "java.lang.Integer" );
                  else if ( parameterTypes[j].equals( Long.TYPE ) )
                      methodKey.append( "java.lang.Long" );
                  else if ( parameterTypes[j].equals( Short.TYPE ) )
                      methodKey.append( "java.lang.Short" );
              }
              else
              {
                  methodKey.append( parameterTypes[j].getName() );
              }
          }
  
          return methodKey.toString();
      }
  
      private static String makeMethodKey( String method, Object[] params )
      {
          StringBuffer methodKey = new StringBuffer().append( method );
  
          for ( int j = 0; j < params.length; j++ )
          {
              Object arg = params[j];
  
              if ( arg == null )
              {
                  arg = OBJECT;
              }
  
              methodKey.append( arg.getClass().getName() );
          }
  
          return methodKey.toString();
      }
  
      /**
       * Retrieves public methods for a class. In case the class is not
       * public, retrieves methods with same signature as its public methods
       * from public superclasses and interfaces (if they exist). Basically
       * upcasts every method to the nearest acccessible method.
       */
      private static Method[] getAccessibleMethods( Class clazz )
      {
          Method[] methods = clazz.getMethods();
          
          /*
           *  Short circuit for the (hopefully) majority of cases where the
           *  clazz is public
           */
          
          if ( Modifier.isPublic( clazz.getModifiers() ) )
          {
              return methods;
          }
  
          /*
           *  No luck - the class is not public, so we're going the longer way.
           */
  
          MethodInfo[] methodInfos = new MethodInfo[methods.length];
  
          for ( int i = methods.length; i-- > 0; )
          {
              methodInfos[i] = new MethodInfo( methods[i] );
          }
  
          int upcastCount = getAccessibleMethods( clazz, methodInfos, 0 );
  
          /*
           *  Reallocate array in case some method had no accessible counterpart.
           */
  
          if ( upcastCount < methods.length )
          {
              methods = new Method[upcastCount];
          }
  
          int j = 0;
          for ( int i = 0; i < methodInfos.length; ++i )
          {
              MethodInfo methodInfo = methodInfos[i];
              if ( methodInfo.upcast )
              {
                  methods[j++] = methodInfo.method;
              }
          }
          return methods;
      }
  
      /**
       * Recursively finds a match for each method, starting with the class, and then
       * searching the superclass and interfaces.
       *
       * @param clazz       Class to check
       * @param methodInfos array of methods we are searching to match
       * @param upcastCount current number of methods we have matched
       * @return count of matched methods
       */
      private static int getAccessibleMethods( Class clazz, MethodInfo[] methodInfos, int upcastCount )
      {
          int l = methodInfos.length;
          
          /*
           *  if this class is public, then check each of the currently
           *  'non-upcasted' methods to see if we have a match
           */
  
          if ( Modifier.isPublic( clazz.getModifiers() ) )
          {
              for ( int i = 0; i < l && upcastCount < l; ++i )
              {
                  try
                  {
                      MethodInfo methodInfo = methodInfos[i];
  
                      if ( !methodInfo.upcast )
                      {
                          methodInfo.tryUpcasting( clazz );
                          upcastCount++;
                      }
                  }
                  catch ( NoSuchMethodException e )
                  {
                      /*
                       *  Intentionally ignored - it means
                       *  it wasn't found in the current class
                       */
                  }
              }
  
              /*
               *  Short circuit if all methods were upcast
               */
  
              if ( upcastCount == l )
              {
                  return upcastCount;
              }
          }
  
          /*
           *   Examine superclass
           */
  
          Class superclazz = clazz.getSuperclass();
  
          if ( superclazz != null )
          {
              upcastCount = getAccessibleMethods( superclazz, methodInfos, upcastCount );
  
              /*
               *  Short circuit if all methods were upcast
               */
  
              if ( upcastCount == l )
              {
                  return upcastCount;
              }
          }
  
          /*
           *  Examine interfaces. Note we do it even if superclazz == null.
           *  This is redundant as currently java.lang.Object does not implement
           *  any interfaces, however nothing guarantees it will not in future.
           */
  
          Class[] interfaces = clazz.getInterfaces();
  
          for ( int i = interfaces.length; i-- > 0; )
          {
              upcastCount = getAccessibleMethods( interfaces[i], methodInfos, upcastCount );
  
              /*
               *  Short circuit if all methods were upcast
               */
  
              if ( upcastCount == l )
              {
                  return upcastCount;
              }
          }
  
          return upcastCount;
      }
  
      /**
       * For a given method, retrieves its publicly accessible counterpart.
       * This method will look for a method with same name
       * and signature declared in a public superclass or implemented interface of this
       * method's declaring class. This counterpart method is publicly callable.
       *
       * @param method a method whose publicly callable counterpart is requested.
       * @return the publicly callable counterpart method. Note that if the parameter
       *         method is itself declared by a public class, this method is an identity
       *         function.
       */
      public static Method getPublicMethod( Method method )
      {
          Class clazz = method.getDeclaringClass();
          
          /*
           *   Short circuit for (hopefully the majority of) cases where the declaring
           *   class is public.
           */
  
          if ( ( clazz.getModifiers() & Modifier.PUBLIC ) != 0 )
          {
              return method;
          }
  
          return getPublicMethod( clazz, method.getName(), method.getParameterTypes() );
      }
  
      /**
       * Looks up the method with specified name and signature in the first public
       * superclass or implemented interface of the class.
       *
       * @param class      the class whose method is sought
       * @param name       the name of the method
       * @param paramTypes the classes of method parameters
       */
      private static Method getPublicMethod( Class clazz, String name, Class[] paramTypes )
      {
          /*
           *  if this class is public, then try to get it
           */
  
          if ( ( clazz.getModifiers() & Modifier.PUBLIC ) != 0 )
          {
              try
              {
                  return clazz.getMethod( name, paramTypes );
              }
              catch ( NoSuchMethodException e )
              {
                  /*
                   *  If the class does not have the method, then neither its
                   *  superclass nor any of its interfaces has it so quickly return
                   *  null.
                   */
                  return null;
              }
          }
  
          /*
           *  try the superclass
           */
  
   
          Class superclazz = clazz.getSuperclass();
  
          if ( superclazz != null )
          {
              Method superclazzMethod = getPublicMethod( superclazz, name, paramTypes );
  
              if ( superclazzMethod != null )
              {
                  return superclazzMethod;
              }
          }
  
          /*
           *  and interfaces
           */
  
          Class[] interfaces = clazz.getInterfaces();
  
          for ( int i = 0; i < interfaces.length; ++i )
          {
              Method interfaceMethod = getPublicMethod( interfaces[i], name, paramTypes );
  
              if ( interfaceMethod != null )
              {
                  return interfaceMethod;
              }
          }
  
          return null;
      }
  
      /**
       * Used for the iterative discovery process for public methods.
       */
      private static final class MethodInfo
      {
          Method method;
          String name;
          Class[] parameterTypes;
          boolean upcast;
  
          MethodInfo( Method method )
          {
              this.method = null;
              name = method.getName();
              parameterTypes = method.getParameterTypes();
              upcast = false;
          }
  
          void tryUpcasting( Class clazz )
              throws NoSuchMethodException
          {
              method = clazz.getMethod( name, parameterTypes );
              name = null;
              parameterTypes = null;
              upcast = true;
          }
      }
  }
  
  
  
  1.1                  maven-components/maven-core/src/main/java/org/apache/maven/util/introspection/MethodMap.java
  
  Index: MethodMap.java
  ===================================================================
  package org.apache.maven.util.introspection;
  
  /*
   * Copyright 2001-2004 The Apache Software Foundation.
   *
   * Licensed under the Apache License, Version 2.0 (the "License")
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  import java.util.Iterator;
  import java.util.List;
  import java.util.ArrayList;
  import java.util.LinkedList;
  import java.util.Set;
  import java.util.HashSet;
  import java.util.Map;
  import java.util.Hashtable;
  
  import java.lang.reflect.Method;
  
  /**
   *
   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
   * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
   * @author <a href="mailto:Christoph.Reck@dlr.de">Christoph Reck</a>
   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
   * @author <a href="mailto:szegedia@freemail.hu">Attila Szegedi</a>
   * @version $Id: MethodMap.java,v 1.1 2004/12/05 21:45:35 jvanzyl Exp $
   */
  public class MethodMap
  {
      private static final int MORE_SPECIFIC = 0;
      private static final int LESS_SPECIFIC = 1;
      private static final int INCOMPARABLE = 2;
  
      /**
       * Keep track of all methods with the same name.
       */
      Map methodByNameMap = new Hashtable();
  
      /**
       * Add a method to a list of methods by name.
       * For a particular class we are keeping track
       * of all the methods with the same name.
       */
      public void add(Method method)
      {
          String methodName = method.getName();
  
          List l = get( methodName );
  
          if ( l == null)
          {
              l = new ArrayList();
              methodByNameMap.put(methodName, l);
          }
  
          l.add(method);
  
          return;
      }
  
      /**
       * Return a list of methods with the same name.
       *
       * @param String key
       * @return List list of methods
       */
      public List get(String key)
      {
          return (List) methodByNameMap.get(key);
      }
  
      /**
       *  <p>
       *  Find a method.  Attempts to find the
       *  most specific applicable method using the
       *  algorithm described in the JLS section
       *  15.12.2 (with the exception that it can't
       *  distinguish a primitive type argument from
       *  an object type argument, since in reflection
       *  primitive type arguments are represented by
       *  their object counterparts, so for an argument of
       *  type (say) java.lang.Integer, it will not be able
       *  to decide between a method that takes int and a
       *  method that takes java.lang.Integer as a parameter.
       *  </p>
       *
       *  <p>
       *  This turns out to be a relatively rare case
       *  where this is needed - however, functionality
       *  like this is needed.
       *  </p>
       *
       *  @param methodName name of method
       *  @param args the actual arguments with which the method is called
       *  @return the most specific applicable method, or null if no
       *  method is applicable.
       *  @throws AmbiguousException if there is more than one maximally
       *  specific applicable method
       */
      public Method find(String methodName, Object[] args)
          throws AmbiguousException
      {
          List methodList = get(methodName);
  
          if (methodList == null)
          {
              return null;
          }
  
          int l = args.length;
          Class[] classes = new Class[l];
  
          for(int i = 0; i < l; ++i)
          {
              Object arg = args[i];
  
              /*
               * if we are careful down below, a null argument goes in there
               * so we can know that the null was passed to the method
               */
              classes[i] =
                      arg == null ? null : arg.getClass();
          }
  
          return getMostSpecific(methodList, classes);
      }
  
      /**
       *  simple distinguishable exception, used when
       *  we run across ambiguous overloading
       */
      public static class AmbiguousException extends Exception
      {
      }
  
  
      private static Method getMostSpecific(List methods, Class[] classes)
          throws AmbiguousException
      {
          LinkedList applicables = getApplicables(methods, classes);
  
          if(applicables.isEmpty())
          {
              return null;
          }
  
          if(applicables.size() == 1)
          {
              return (Method)applicables.getFirst();
          }
  
          /*
           * This list will contain the maximally specific methods. Hopefully at
           * the end of the below loop, the list will contain exactly one method,
           * (the most specific method) otherwise we have ambiguity.
           */
  
          LinkedList maximals = new LinkedList();
  
          for (Iterator applicable = applicables.iterator();
               applicable.hasNext();)
          {
              Method app = (Method) applicable.next();
              Class[] appArgs = app.getParameterTypes();
              boolean lessSpecific = false;
  
              for (Iterator maximal = maximals.iterator();
                   !lessSpecific && maximal.hasNext();)
              {
                  Method max = (Method) maximal.next();
  
                  switch(moreSpecific(appArgs, max.getParameterTypes()))
                  {
                      case MORE_SPECIFIC:
                      {
                          /*
                           * This method is more specific than the previously
                           * known maximally specific, so remove the old maximum.
                           */
  
                          maximal.remove();
                          break;
                      }
  
                      case LESS_SPECIFIC:
                      {
                          /*
                           * This method is less specific than some of the
                           * currently known maximally specific methods, so we
                           * won't add it into the set of maximally specific
                           * methods
                           */
  
                          lessSpecific = true;
                          break;
                      }
                  }
              }
  
              if(!lessSpecific)
              {
                  maximals.addLast(app);
              }
          }
  
          if(maximals.size() > 1)
          {
              // We have more than one maximally specific method
              throw new AmbiguousException();
          }
  
          return (Method)maximals.getFirst();
      }
  
      /**
       * Determines which method signature (represented by a class array) is more
       * specific. This defines a partial ordering on the method signatures.
       * @param c1 first signature to compare
       * @param c2 second signature to compare
       * @return MORE_SPECIFIC if c1 is more specific than c2, LESS_SPECIFIC if
       * c1 is less specific than c2, INCOMPARABLE if they are incomparable.
       */
      private static int moreSpecific(Class[] c1, Class[] c2)
      {
          boolean c1MoreSpecific = false;
          boolean c2MoreSpecific = false;
  
          for(int i = 0; i < c1.length; ++i)
          {
              if(c1[i] != c2[i])
              {
                  c1MoreSpecific =
                      c1MoreSpecific ||
                      isStrictMethodInvocationConvertible(c2[i], c1[i]);
                  c2MoreSpecific =
                      c2MoreSpecific ||
                      isStrictMethodInvocationConvertible(c1[i], c2[i]);
              }
          }
  
          if(c1MoreSpecific)
          {
              if(c2MoreSpecific)
              {
                  /*
                   *  Incomparable due to cross-assignable arguments (i.e.
                   * foo(String, Object) vs. foo(Object, String))
                   */
  
                  return INCOMPARABLE;
              }
  
              return MORE_SPECIFIC;
          }
  
          if(c2MoreSpecific)
          {
              return LESS_SPECIFIC;
          }
  
          /*
           * Incomparable due to non-related arguments (i.e.
           * foo(Runnable) vs. foo(Serializable))
           */
  
          return INCOMPARABLE;
      }
  
      /**
       * Returns all methods that are applicable to actual argument types.
       * @param methods list of all candidate methods
       * @param classes the actual types of the arguments
       * @return a list that contains only applicable methods (number of
       * formal and actual arguments matches, and argument types are assignable
       * to formal types through a method invocation conversion).
       */
      private static LinkedList getApplicables(List methods, Class[] classes)
      {
          LinkedList list = new LinkedList();
  
          for (Iterator imethod = methods.iterator(); imethod.hasNext();)
          {
              Method method = (Method) imethod.next();
  
              if(isApplicable(method, classes))
              {
                  list.add(method);
              }
  
          }
          return list;
      }
  
      /**
       * Returns true if the supplied method is applicable to actual
       * argument types.
       */
      private static boolean isApplicable(Method method, Class[] classes)
      {
          Class[] methodArgs = method.getParameterTypes();
  
          if(methodArgs.length != classes.length)
          {
              return false;
          }
  
          for(int i = 0; i < classes.length; ++i)
          {
              if(!isMethodInvocationConvertible(methodArgs[i], classes[i]))
              {
                  return false;
              }
          }
  
          return true;
      }
  
      /**
       * Determines whether a type represented by a class object is
       * convertible to another type represented by a class object using a
       * method invocation conversion, treating object types of primitive
       * types as if they were primitive types (that is, a Boolean actual
       * parameter type matches boolean primitive formal type). This behavior
       * is because this method is used to determine applicable methods for
       * an actual parameter list, and primitive types are represented by
       * their object duals in reflective method calls.
       *
       * @param formal the formal parameter type to which the actual
       * parameter type should be convertible
       * @param actual the actual parameter type.
       * @return true if either formal type is assignable from actual type,
       * or formal is a primitive type and actual is its corresponding object
       * type or an object type of a primitive type that can be converted to
       * the formal type.
       */
      private static boolean isMethodInvocationConvertible(Class formal,
                                                           Class actual)
      {
          /*
           * if it's a null, it means the arg was null
           */
          if (actual == null && !formal.isPrimitive())
          {
              return true;
          }
  
          /*
           *  Check for identity or widening reference conversion
           */
  
          if (actual != null && formal.isAssignableFrom(actual))
          {
              return true;
          }
  
          /*
           * Check for boxing with widening primitive conversion. Note that
           * actual parameters are never primitives.
           */
  
          if (formal.isPrimitive())
          {
              if(formal == Boolean.TYPE && actual == Boolean.class)
                  return true;
              if(formal == Character.TYPE && actual == Character.class)
                  return true;
              if(formal == Byte.TYPE && actual == Byte.class)
                  return true;
              if(formal == Short.TYPE &&
                 (actual == Short.class || actual == Byte.class))
                  return true;
              if(formal == Integer.TYPE &&
                 (actual == Integer.class || actual == Short.class ||
                  actual == Byte.class))
                  return true;
              if(formal == Long.TYPE &&
                 (actual == Long.class || actual == Integer.class ||
                  actual == Short.class || actual == Byte.class))
                  return true;
              if(formal == Float.TYPE &&
                 (actual == Float.class || actual == Long.class ||
                  actual == Integer.class || actual == Short.class ||
                  actual == Byte.class))
                  return true;
              if(formal == Double.TYPE &&
                 (actual == Double.class || actual == Float.class ||
                  actual == Long.class || actual == Integer.class ||
                  actual == Short.class || actual == Byte.class))
                  return true;
          }
  
          return false;
      }
  
      /**
       * Determines whether a type represented by a class object is
       * convertible to another type represented by a class object using a
       * method invocation conversion, without matching object and primitive
       * types. This method is used to determine the more specific type when
       * comparing signatures of methods.
       *
       * @param formal the formal parameter type to which the actual
       * parameter type should be convertible
       * @param actual the actual parameter type.
       * @return true if either formal type is assignable from actual type,
       * or formal and actual are both primitive types and actual can be
       * subject to widening conversion to formal.
       */
      private static boolean isStrictMethodInvocationConvertible(Class formal,
                                                                 Class actual)
      {
          /*
           * we shouldn't get a null into, but if so
           */
          if (actual == null && !formal.isPrimitive())
          {
              return true;
          }
  
          /*
           *  Check for identity or widening reference conversion
           */
  
          if(formal.isAssignableFrom(actual))
          {
              return true;
          }
  
          /*
           *  Check for widening primitive conversion.
           */
  
          if(formal.isPrimitive())
          {
              if(formal == Short.TYPE && (actual == Byte.TYPE))
                  return true;
              if(formal == Integer.TYPE &&
                 (actual == Short.TYPE || actual == Byte.TYPE))
                  return true;
              if(formal == Long.TYPE &&
                 (actual == Integer.TYPE || actual == Short.TYPE ||
                  actual == Byte.TYPE))
                  return true;
              if(formal == Float.TYPE &&
                 (actual == Long.TYPE || actual == Integer.TYPE ||
                  actual == Short.TYPE || actual == Byte.TYPE))
                  return true;
              if(formal == Double.TYPE &&
                 (actual == Float.TYPE || actual == Long.TYPE ||
                  actual == Integer.TYPE || actual == Short.TYPE ||
                  actual == Byte.TYPE))
                  return true;
          }
          return false;
      }
  }
  
  
  
  1.1                  maven-components/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorTest.java
  
  Index: PluginParameterExpressionEvaluatorTest.java
  ===================================================================
  package org.apache.maven.plugin;
  
  import java.io.File;
  
  import org.apache.maven.MavenTestCase;
  import org.apache.maven.artifact.repository.ArtifactRepository;
  import org.apache.maven.lifecycle.goal.MavenGoalExecutionContext;
  import org.apache.maven.project.MavenProject;
  import org.apache.maven.project.MavenProjectBuilder;
  
  /**
   * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
   * @version $Id: PluginParameterExpressionEvaluatorTest.java,v 1.1 2004/12/05 21:45:35 jvanzyl Exp $
   */
  public class PluginParameterExpressionEvaluatorTest
      extends MavenTestCase
  {
      private MavenProject project;
  
      private MavenProjectBuilder builder;
  
      private MavenGoalExecutionContext context;
  
      protected void setUp()
          throws Exception
      {
          super.setUp();
  
          builder = (MavenProjectBuilder) lookup( MavenProjectBuilder.ROLE );
  
          File f =  getTestFile( "src/test/resources/pom.xml" );
  
          project = builder.build( getMavenLocalHome(), f );
  
          context = createGoalExecutionContext();
      }
  
      public void testValueExtractionWithAPomValueContainingAPath()
          throws Exception
      {
          Object value = PluginParameterExpressionEvaluator.evaluate( "#project.build.directory/classes", context );
  
          String expected = getTestFile( "target/test-classes/target/classes" ).getCanonicalPath();
  
          String actual = new File( value.toString() ).getCanonicalPath();
  
          assertEquals( expected, actual );
      }
  
      public void testParameterThatIsAComponent()
          throws Exception
      {
          String role = "#component.org.apache.maven.project.MavenProjectBuilder";
  
          Object value = PluginParameterExpressionEvaluator.evaluate( role, context );
  
          assertNotNull( value );
      }
  
      public void testLocalRepositoryExtraction()
          throws Exception
      {
          Object value = PluginParameterExpressionEvaluator.evaluate( "#localRepository", context );
  
          assertEquals( "local", ((ArtifactRepository)value).getId() );
      }
  }
  
  
  
  1.1                  maven-components/maven-core/src/test/java/org/apache/maven/plugin/ReflectionProjectValueExtractorTest.java
  
  Index: ReflectionProjectValueExtractorTest.java
  ===================================================================
  /*
   * Copyright (c) 2004 Your Corporation. All Rights Reserved.
   */
  package org.apache.maven.plugin;
  
  import java.io.File;
  import java.util.List;
  
  import org.apache.maven.MavenTestCase;
  import org.apache.maven.model.Build;
  import org.apache.maven.artifact.repository.ArtifactRepository;
  import org.apache.maven.lifecycle.goal.MavenGoalExecutionContext;
  import org.apache.maven.project.MavenProject;
  import org.apache.maven.project.MavenProjectBuilder;
  
  /**
   * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
   * @version $Id: ReflectionProjectValueExtractorTest.java,v 1.1 2004/12/05 21:45:35 jvanzyl Exp $
   */
  public class ReflectionProjectValueExtractorTest
      extends MavenTestCase
  {
      private MavenProject project;
  
      private MavenProjectBuilder builder;
  
      protected void setUp()
          throws Exception
      {
          super.setUp();
  
          builder = (MavenProjectBuilder) lookup( MavenProjectBuilder.ROLE );
  
          File f =  getTestFile( "src/test/resources/pom.xml" );
  
          project = builder.build( getMavenLocalHome(), f );
      }
  
      public void testValueExtraction()
          throws Exception
      {
          // ----------------------------------------------------------------------
          // Top level values
          // ----------------------------------------------------------------------
  
          assertEquals( "4.0.0", ReflectionProjectValueExtractor.evaluate( "project.modelVersion", project ) );
  
          assertEquals( "maven", ReflectionProjectValueExtractor.evaluate( "project.groupId", project ) );
  
          assertEquals( "maven-core", ReflectionProjectValueExtractor.evaluate( "project.artifactId", project ) );
  
          assertEquals( "Maven", ReflectionProjectValueExtractor.evaluate( "project.name", project ) );
  
          assertEquals( "2.0-SNAPSHOT", ReflectionProjectValueExtractor.evaluate( "project.version", project ) );
  
          // ----------------------------------------------------------------------
          // SCM
          // ----------------------------------------------------------------------
  
          assertEquals( "scm-connection", ReflectionProjectValueExtractor.evaluate( "project.scm.connection", project ) );
  
          // ----------------------------------------------------------------------
          // Dependencies
          // ----------------------------------------------------------------------
  
          List dependencies = (List) ReflectionProjectValueExtractor.evaluate( "project.dependencies", project );
  
          assertNotNull( dependencies );
  
          assertEquals( 2, dependencies.size() );
  
          // ----------------------------------------------------------------------
          // Build
          // ----------------------------------------------------------------------
  
          Build build = (Build) ReflectionProjectValueExtractor.evaluate( "project.build", project );
  
          assertNotNull( build );
      }
  }
  
  
  
  1.3       +3 -71     maven-components/maven-core/src/test/resources/pom.xml
  
  Index: pom.xml
  ===================================================================
  RCS file: /home/cvs/maven-components/maven-core/src/test/resources/pom.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- pom.xml	5 Dec 2004 04:16:07 -0000	1.2
  +++ pom.xml	5 Dec 2004 21:45:36 -0000	1.3
  @@ -9,8 +9,10 @@
     <inceptionYear>2001</inceptionYear>
     <package>org.apache.maven</package>
     <logo>/images/maven.gif</logo>
  +  <scm>
  +    <connection>scm-connection</connection>
  +  </scm>
     <dependencies>
  -    <!-- maven component -->
       <dependency>
         <groupId>maven</groupId>
         <artifactId>maven-model</artifactId>
  @@ -20,76 +22,6 @@
         <groupId>maven</groupId>
         <artifactId>maven-plugin</artifactId>
         <version>2.0-SNAPSHOT</version>
  -    </dependency>
  -    <!-- -->
  -    <dependency>
  -      <groupId>commons-cli</groupId>
  -      <artifactId>commons-cli</artifactId>
  -      <version>1.0-beta-2</version>
  -    </dependency>
  -    <dependency>
  -      <groupId>plexus</groupId>
  -      <artifactId>plexus-i18n</artifactId>
  -      <version>1.0-beta-2-SNAPSHOT</version>
  -    </dependency>
  -    <dependency>
  -      <groupId>ognl</groupId>
  -      <artifactId>ognl</artifactId>
  -      <version>2.5.1</version>
  -    </dependency>
  -    <!-- Used to support maven.xml script and goal decorating in general. -->
  -    <dependency>
  -      <groupId>marmalade</groupId>
  -      <artifactId>marmalade-core</artifactId>
  -      <version>0.1</version>
  -    </dependency>
  -    <dependency>
  -      <groupId>marmalade</groupId>
  -      <artifactId>marmalade-el-ognl</artifactId>
  -      <version>0.1</version>
  -    </dependency>
  -    <!-- This will eventually be removed -->
  -    <dependency>
  -      <groupId>plexus</groupId>
  -      <artifactId>plexus-compiler-api</artifactId>
  -      <version>1.0</version>
  -    </dependency>
  -    <dependency>
  -      <groupId>plexus</groupId>
  -      <artifactId>plexus-compiler-javac</artifactId>
  -      <version>1.0</version>
  -    </dependency>
  -    <dependency>
  -      <groupId>surefire</groupId>
  -      <artifactId>surefire-booter</artifactId>
  -      <version>1.1</version>
  -    </dependency>
  -    <!-- Wagon -->
  -    <dependency>
  -      <groupId>maven</groupId>
  -      <artifactId>wagon-api</artifactId>
  -      <version>0.9-SNAPSHOT</version>
  -    </dependency>
  -    <dependency>
  -      <groupId>maven</groupId>
  -      <artifactId>wagon-http-lightweight</artifactId>
  -      <version>0.9-SNAPSHOT</version>
  -    </dependency>    
  -    <dependency>
  -      <groupId>maven</groupId>
  -      <artifactId>wagon-ssh</artifactId>
  -      <version>0.9-SNAPSHOT</version>
  -    </dependency>
  -    <dependency>
  -      <groupId>jsch</groupId>
  -      <artifactId>jsch</artifactId>
  -      <version>0.1.14</version>      
  -    </dependency>
  -    <!-- plugin plugin -->
  -    <dependency>
  -      <groupId>qdox</groupId>
  -      <artifactId>qdox</artifactId>
  -      <version>1.2</version>
       </dependency>
     </dependencies>
   </project>
  
  
  

Mime
View raw message