You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by be...@apache.org on 2008/10/03 21:29:32 UTC

svn commit: r701503 - in /maven/core-integration-testing/trunk/core-it-support/core-it-plugins: ./ maven-it-plugin-expression/ maven-it-plugin-expression/src/ maven-it-plugin-expression/src/main/ maven-it-plugin-expression/src/main/java/ maven-it-plugi...

Author: bentmann
Date: Fri Oct  3 12:29:31 2008
New Revision: 701503

URL: http://svn.apache.org/viewvc?rev=701503&view=rev
Log:
o Added new IT plugin to inspect the runtime state of the POM and things like by dumping expression values into a properties file

Added:
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/   (with props)
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/pom.xml   (with props)
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/EvalMojo.java   (with props)
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/ExpressionUtil.java   (with props)
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/PropertyUtil.java   (with props)
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/ExpressionUtilTest.java   (with props)
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/PropertyUtilTest.java   (with props)
Modified:
    maven/core-integration-testing/trunk/core-it-support/core-it-plugins/pom.xml

Propchange: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Fri Oct  3 12:29:31 2008
@@ -0,0 +1,7 @@
+target
+*.iml
+.classpath
+.project
+.settings
+target-eclipse
+bin

Added: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/pom.xml
URL: http://svn.apache.org/viewvc/maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/pom.xml?rev=701503&view=auto
==============================================================================
--- maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/pom.xml (added)
+++ maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/pom.xml Fri Oct  3 12:29:31 2008
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <artifactId>maven-it-plugins</artifactId>
+    <groupId>org.apache.maven.its.plugins</groupId>
+    <version>2.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-it-plugin-expression</artifactId>
+  <packaging>maven-plugin</packaging>
+
+  <name>Maven Integration Test Plugin :: Expression</name>
+  <description>
+    A test plugin that creates a properties file with the effective values of some user-defined expressions. As such it
+    allows to analyze the runtime state of the POM similar to the Help Plugin.
+  </description>
+  <inceptionYear>2008</inceptionYear>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-plugin-api</artifactId>
+      <version>2.0</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.2</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>

Propchange: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/pom.xml
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/EvalMojo.java
URL: http://svn.apache.org/viewvc/maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/EvalMojo.java?rev=701503&view=auto
==============================================================================
--- maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/EvalMojo.java (added)
+++ maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/EvalMojo.java Fri Oct  3 12:29:31 2008
@@ -0,0 +1,171 @@
+package org.apache.maven.plugin.coreit;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Creates a properties file with the effective values of some user-defined expressions. Unlike Maven's built-in
+ * expression syntax for interpolation, these expressions use forward slashes to navigate down the object graph and
+ * support access to individual collection/array elements. Furthermore, the result of an expression need not be a scalar
+ * value but can also be a collection/array or a bean-like object (from the Maven model). For example, the expression
+ * "project/dependencies/0" would extract the first project dependency. In more detail, this example expression could
+ * output the following keys to the properties file:
+ * 
+ * <pre>
+ * project.dependencies.0.groupId = org.apache.maven
+ * project.dependencies.0.artifactId = maven-project
+ * project.dependencies.0.type = jar
+ * project.dependencies.0.version = 2.0
+ * project.dependencies.0.optional = false
+ * project.dependencies.0.exclusions = 2
+ * project.dependencies.0.exclusions.0.groupId = plexus
+ * project.dependencies.0.exclusions.0.artifactId = plexus-utils
+ * project.dependencies.0.exclusions.1.groupId = plexus
+ * project.dependencies.0.exclusions.1.artifactId = plexus-container-default
+ * </pre>
+ * 
+ * Expressions that reference non-existing objects or use invalid collection/array indices silently resolve to
+ * <code>null</code>.
+ * 
+ * @goal eval
+ * @phase initialize
+ * 
+ * @author Benjamin Bentmann
+ * @version $Id$
+ */
+public class EvalMojo
+    extends AbstractMojo
+{
+
+    /**
+     * The path to the output file for the properties with the expression values. For each expression given by the
+     * parameter {@link #expressions} an similar named properties key will be used to save the expression value. If an
+     * expression evaluated to <code>null</code>, there will be no corresponding key in the properties file.
+     * 
+     * @parameter expression="${expression.outputFile}" default-value="${project.build.directory}/expression.properties"
+     */
+    private File outputFile;
+
+    /**
+     * The set of expressions to evaluate.
+     * 
+     * @parameter
+     */
+    private String[] expressions;
+
+    /**
+     * The comma separated set of expressions to evaluate.
+     * 
+     * @parameter expression="${expression.expressions}"
+     */
+    private String expressionList;
+
+    /**
+     * The current Maven project against which expressions are evaluated.
+     * 
+     * @parameter default-value="${project}"
+     * @readonly
+     */
+    private Object project;
+
+    /**
+     * The merged user/global settings of the current build against which expressions are evaluated.
+     * 
+     * @parameter default-value="${settings}"
+     * @readonly
+     */
+    private Object settings;
+
+    /**
+     * The session context of the current build against which expressions are evaluated.
+     * 
+     * @parameter default-value="${session}"
+     * @readonly
+     */
+    private Object session;
+
+    /**
+     * The local repository of the current build against which expressions are evaluated.
+     * 
+     * @parameter default-value="${localRepository}"
+     * @readonly
+     */
+    private Object localRepository;
+
+    /**
+     * Runs this mojo.
+     * 
+     * @throws MojoExecutionException If the output file could not be created.
+     * @throws MojoFailureException If the output file has not been set.
+     */
+    public void execute()
+        throws MojoExecutionException, MojoFailureException
+    {
+        if ( outputFile == null )
+        {
+            throw new MojoFailureException( "Path name for output file has not been specified" );
+        }
+
+        getLog().info( "[MAVEN-CORE-IT-LOG] Creating output file: " + outputFile );
+
+        Properties expressionProperties = new Properties();
+
+        if ( expressionList != null && expressionList.length() > 0 )
+        {
+            expressions = expressionList.split( "," );
+        }
+        if ( expressions != null && expressions.length > 0 )
+        {
+            Map contexts = new HashMap();
+            contexts.put( "project", project );
+            contexts.put( "pom", project );
+            contexts.put( "settings", settings );
+            contexts.put( "session", session );
+            contexts.put( "localRepository", localRepository );
+
+            for ( int i = 0; i < expressions.length; i++ )
+            {
+                Object value = ExpressionUtil.evaluate( expressions[i], contexts );
+                PropertyUtil.store( expressionProperties, expressions[i].replace( '/', '.' ), value );
+            }
+        }
+
+        try
+        {
+            PropertyUtil.write( expressionProperties, outputFile );
+        }
+        catch ( IOException e )
+        {
+            throw new MojoExecutionException( "Output file could not be created: " + outputFile, e );
+        }
+
+        getLog().info( "[MAVEN-CORE-IT-LOG] Created output file: " + outputFile );
+    }
+
+}

Propchange: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/EvalMojo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/EvalMojo.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/ExpressionUtil.java
URL: http://svn.apache.org/viewvc/maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/ExpressionUtil.java?rev=701503&view=auto
==============================================================================
--- maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/ExpressionUtil.java (added)
+++ maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/ExpressionUtil.java Fri Oct  3 12:29:31 2008
@@ -0,0 +1,227 @@
+package org.apache.maven.plugin.coreit;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Assists in evaluating expressions.
+ * 
+ * @author Benjamin Bentmann
+ * @version $Id$
+ */
+class ExpressionUtil
+{
+
+    private static final Object[] NO_ARGS = {};
+
+    private static final Class[] NO_PARAMS = {};
+
+    private static final Class[] OBJECT_PARAM = { Object.class };
+
+    private static final Class[] STRING_PARAM = { String.class };
+
+    /**
+     * Evaluates the specified expression. Expressions are composed of segments which are separated by a forward slash
+     * ('/'). Each segment specifies a (public) bean property of the current object and drives the evaluation further
+     * down the object graph. For lists, arrays and maps segments can additionally specify the index/key of an element.
+     * The initial segment denotes the root object and the parameter <code>contexts</code> is used to specify which
+     * root objects are available. For instance, if <code>contexts</code> maps the token "project" to a Maven project
+     * instance, the expression "project/build/resources/0/directory" specifies the first resource directory of the
+     * project.
+     * 
+     * @param expression The expression to evaluate, may be <code>null</code>.
+     * @param contexts The possible root objects for the expression evaluation, indexed by their identifying token, must
+     *            not be <code>null</code>.
+     * @return The value of the expression or <code>null</code> if the expression could not be evaluated.
+     */
+    public static Object evaluate( String expression, Map contexts )
+    {
+        Object value = null;
+
+        if ( expression != null && expression.length() > 0 )
+        {
+            List segments = Arrays.asList( expression.split( "/", 0 ) );
+            if ( !segments.isEmpty() )
+            {
+                Object context = contexts.get( segments.get( 0 ) );
+                if ( context != null )
+                {
+                    value = evaluate( context, segments.subList( 1, segments.size() ) );
+                }
+            }
+        }
+
+        return value;
+    }
+
+    /**
+     * Evaluates the given expression segments against the specified object.
+     * 
+     * @param context The object to evaluate the segments against, may be <code>null</code>.
+     * @param segments The expression segments to evaluate, must not be <code>null</code>.
+     * @return The value of the evaluation or <code>null</code> if the segments could not be evaluated.
+     */
+    private static Object evaluate( Object context, List segments )
+    {
+        Object value = null;
+
+        if ( segments.isEmpty() )
+        {
+            value = context;
+        }
+        else if ( context != null )
+        {
+            Object target = null;
+            String segment = (String) segments.get( 0 );
+            if ( segment.length() <= 0 )
+            {
+                value = context;
+            }
+            else if ( context.getClass().isArray() && Character.isDigit( segment.charAt( 0 ) ) )
+            {
+                try
+                {
+                    int index = Integer.parseInt( segment );
+                    target = Array.get( context, index );
+                }
+                catch ( RuntimeException e )
+                {
+                    // invalid index, just ignore
+                }
+            }
+            else if ( ( context instanceof List ) && Character.isDigit( segment.charAt( 0 ) ) )
+            {
+                try
+                {
+                    int index = Integer.parseInt( segment );
+                    target = ( (List) context ).get( index );
+                }
+                catch ( RuntimeException e )
+                {
+                    // invalid index, just ignore
+                }
+            }
+            else
+            {
+                target = getProperty( context, segment );
+            }
+            value = evaluate( target, segments.subList( 1, segments.size() ) );
+        }
+
+        return value;
+    }
+
+    /**
+     * Gets the value of a (public) bean property from the specified object.
+     * 
+     * @param context The object whose bean property should be retrieved, must not be <code>null</code>.
+     * @param property The name of the bean property, must not be <code>null</code>.
+     * @return The value of the bean property or <code>null</code> if the property does not exist.
+     */
+    static Object getProperty( Object context, String property )
+    {
+        Object value;
+
+        Class type = context.getClass();
+        if ( context instanceof Collection )
+        {
+            type = Collection.class;
+        }
+        else if ( context instanceof Map )
+        {
+            type = Map.class;
+        }
+
+        try
+        {
+            try
+            {
+                Method method = type.getMethod( property, NO_PARAMS );
+                value = method.invoke( context, NO_ARGS );
+            }
+            catch ( NoSuchMethodException e )
+            {
+                try
+                {
+                    String name = "get" + Character.toUpperCase( property.charAt( 0 ) ) + property.substring( 1 );
+                    Method method = type.getMethod( name, NO_PARAMS );
+                    value = method.invoke( context, NO_ARGS );
+                }
+                catch ( NoSuchMethodException e1 )
+                {
+                    try
+                    {
+                        String name = "is" + Character.toUpperCase( property.charAt( 0 ) ) + property.substring( 1 );
+                        Method method = type.getMethod( name, NO_PARAMS );
+                        value = method.invoke( context, NO_ARGS );
+                    }
+                    catch ( NoSuchMethodException e2 )
+                    {
+                        try
+                        {
+                            Method method;
+                            try
+                            {
+                                method = type.getMethod( "get", STRING_PARAM );
+                            }
+                            catch ( NoSuchMethodException e3 )
+                            {
+                                method = type.getMethod( "get", OBJECT_PARAM );
+                            }
+                            value = method.invoke( context, new Object[] { property } );
+                        }
+                        catch ( NoSuchMethodException e3 )
+                        {
+                            try
+                            {
+                                Field field = type.getField( property );
+                                value = field.get( context );
+                            }
+                            catch ( NoSuchFieldException e4 )
+                            {
+                                if ( "length".equals( property ) && type.isArray() )
+                                {
+                                    value = new Integer( Array.getLength( context ) );
+                                }
+                                else
+                                {
+                                    throw e4;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        catch ( Exception e )
+        {
+            value = null;
+        }
+        return value;
+    }
+
+}

Propchange: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/ExpressionUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/ExpressionUtil.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/PropertyUtil.java
URL: http://svn.apache.org/viewvc/maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/PropertyUtil.java?rev=701503&view=auto
==============================================================================
--- maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/PropertyUtil.java (added)
+++ maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/PropertyUtil.java Fri Oct  3 12:29:31 2008
@@ -0,0 +1,194 @@
+package org.apache.maven.plugin.coreit;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Assists in serializing primitives and beans into properties for later inspection/verification.
+ * 
+ * @author Benjamin Bentmann
+ * @version $Id$
+ */
+class PropertyUtil
+{
+
+    private static final Object[] NO_ARGS = {};
+
+    /**
+     * Serializes the specified object into the given properties, using the provided key. The object may be a scalar
+     * value like a string or some array/collection/map or a bean.
+     * 
+     * @param props The properties to serialize into, must not be <code>null</code>.
+     * @param key The key to use for serialization of the object data, must not be <code>null</code>.
+     * @param obj The object to serialize, may be <code>null</code>.
+     */
+    public static void store( Properties props, String key, Object obj )
+    {
+        store( props, key, obj, new HashSet() );
+    }
+
+    /**
+     * /** Serializes the specified object into the given properties, using the provided key. The object may be a scalar
+     * value like a string or some array/collection/map or a bean.
+     * 
+     * @param props The properties to serialize into, must not be <code>null</code>.
+     * @param key The key to use for serialization of the object data, must not be <code>null</code>.
+     * @param obj The object to serialize, may be <code>null</code>.
+     * @param visited The set/stack of already visited objects, used to detect back references in the object graph, must
+     *            not be <code>null</code>.
+     */
+    private static void store( Properties props, String key, Object obj, Collection visited )
+    {
+        if ( obj != null )
+        {
+            if ( ( obj instanceof String ) || ( obj instanceof Number ) || ( obj instanceof Boolean )
+                || ( obj instanceof File ) )
+            {
+                props.put( key, obj.toString() );
+            }
+            else if ( obj instanceof Collection )
+            {
+                Collection coll = (Collection) obj;
+                props.put( key, Integer.toString( coll.size() ) );
+                int index = 0;
+                for ( Iterator it = coll.iterator(); it.hasNext(); index++ )
+                {
+                    Object elem = it.next();
+                    store( props, key + "." + index, elem );
+                }
+            }
+            else if ( obj instanceof Map )
+            {
+                Map map = (Map) obj;
+                props.put( key, Integer.toString( map.size() ) );
+                int index = 0;
+                for ( Iterator it = map.entrySet().iterator(); it.hasNext(); index++ )
+                {
+                    Map.Entry entry = (Map.Entry) it.next();
+                    store( props, key + "." + entry.getKey(), entry.getValue() );
+                }
+            }
+            else if ( obj.getClass().isArray() )
+            {
+                int length = Array.getLength( obj );
+                props.put( key, Integer.toString( length ) );
+                for ( int index = 0; index < length; index++ )
+                {
+                    Object elem = Array.get( obj, index );
+                    store( props, key + "." + index, elem );
+                }
+            }
+            else if ( obj != null && !visited.contains( obj ) )
+            {
+                visited.add( obj );
+                Class type = obj.getClass();
+                Method[] methods = type.getMethods();
+                for ( int i = 0; i < methods.length; i++ )
+                {
+                    Method method = methods[i];
+                    if ( Modifier.isStatic( method.getModifiers() ) || method.getParameterTypes().length > 0
+                        || !method.getName().matches( "(get|is)\\p{Lu}.*" ) || method.getName().endsWith( "AsMap" )
+                        || Class.class.isAssignableFrom( method.getReturnType() )
+                        || Object.class.equals( method.getReturnType() ) )
+                    {
+                        continue;
+                    }
+
+                    try
+                    {
+                        Object value = method.invoke( obj, NO_ARGS );
+                        store( props, key + "." + getPropertyName( method.getName() ), value, visited );
+                    }
+                    catch ( Exception e )
+                    {
+                        // just ignore
+                    }
+                }
+                visited.remove( obj );
+            }
+        }
+    }
+
+    /**
+     * Derives the bean property name from the specified method for its getter.
+     * 
+     * @param methodName The method name of the property's getter, must not be <code>null</code>.
+     * @return The property name, never <code>null</code>.
+     */
+    static String getPropertyName( String methodName )
+    {
+        String propertyName = methodName;
+        if ( methodName.startsWith( "get" ) && methodName.length() > 3 )
+        {
+            propertyName = Character.toLowerCase( methodName.charAt( 3 ) ) + methodName.substring( 4 );
+        }
+        else if ( methodName.startsWith( "is" ) && methodName.length() > 2 )
+        {
+            propertyName = Character.toLowerCase( methodName.charAt( 2 ) ) + methodName.substring( 3 );
+        }
+        return propertyName;
+    }
+
+    /**
+     * Writes the specified properties to the given file.
+     * 
+     * @param props The properties to write, must not be <code>null</code>.
+     * @param file The output file for the properties, must not be <code>null</code>.
+     * @throws IOException If the properties could not be written to the file.
+     */
+    public static void write( Properties props, File file )
+        throws IOException
+    {
+        OutputStream out = null;
+        try
+        {
+            file.getParentFile().mkdirs();
+            out = new FileOutputStream( file );
+            props.store( out, "MAVEN-CORE-IT-LOG" );
+        }
+        finally
+        {
+            if ( out != null )
+            {
+                try
+                {
+                    out.close();
+                }
+                catch ( IOException e )
+                {
+                    // just ignore
+                }
+            }
+        }
+    }
+
+}

Propchange: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/PropertyUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/PropertyUtil.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/ExpressionUtilTest.java
URL: http://svn.apache.org/viewvc/maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/ExpressionUtilTest.java?rev=701503&view=auto
==============================================================================
--- maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/ExpressionUtilTest.java (added)
+++ maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/ExpressionUtilTest.java Fri Oct  3 12:29:31 2008
@@ -0,0 +1,122 @@
+package org.apache.maven.plugin.coreit;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Benjamin Bentmann
+ * @version $Id$
+ */
+public class ExpressionUtilTest
+    extends TestCase
+{
+
+    public void testEvaluate()
+    {
+        Object array = new String[] { "one", "two", "three" };
+        Object list = Arrays.asList( new String[] { "0", "-1", "-2" } );
+        Object map = Collections.singletonMap( "some.key", "value" );
+        Object bean = new BeanTwo();
+
+        Map contexts = new HashMap();
+        contexts.put( "array", array );
+        contexts.put( "list", list );
+        contexts.put( "map", map );
+        contexts.put( "bean", bean );
+
+        assertSame( array, ExpressionUtil.evaluate( "array", contexts ) );
+        assertSame( array, ExpressionUtil.evaluate( "array/", contexts ) );
+        assertSame( list, ExpressionUtil.evaluate( "list", contexts ) );
+        assertSame( map, ExpressionUtil.evaluate( "map", contexts ) );
+        assertSame( bean, ExpressionUtil.evaluate( "bean", contexts ) );
+        assertNull( ExpressionUtil.evaluate( "no-root", contexts ) );
+
+        assertEquals( new Integer( 3 ), ExpressionUtil.evaluate( "array/length", contexts ) );
+        assertEquals( "three", ExpressionUtil.evaluate( "array/2", contexts ) );
+        assertEquals( new Integer( 5 ), ExpressionUtil.evaluate( "array/2/length", contexts ) );
+        assertNull( ExpressionUtil.evaluate( "array/invalid", contexts ) );
+        assertNull( ExpressionUtil.evaluate( "array/-1", contexts ) );
+        assertNull( ExpressionUtil.evaluate( "array/999", contexts ) );
+
+        assertEquals( new Integer( 3 ), ExpressionUtil.evaluate( "list/size", contexts ) );
+        assertEquals( "-2", ExpressionUtil.evaluate( "list/2", contexts ) );
+        assertNull( ExpressionUtil.evaluate( "list/invalid", contexts ) );
+        assertNull( ExpressionUtil.evaluate( "list/-1", contexts ) );
+        assertNull( ExpressionUtil.evaluate( "list/999", contexts ) );
+
+        assertEquals( new Integer( 1 ), ExpressionUtil.evaluate( "map/size", contexts ) );
+        assertEquals( "value", ExpressionUtil.evaluate( "map/some.key", contexts ) );
+        assertNull( ExpressionUtil.evaluate( "map/invalid", contexts ) );
+
+        assertEquals( "field", ExpressionUtil.evaluate( "bean/field", contexts ) );
+        assertNull( ExpressionUtil.evaluate( "bean/invalid", contexts ) );
+        assertEquals( "prop", ExpressionUtil.evaluate( "bean/bean/prop", contexts ) );
+        assertEquals( "flag", ExpressionUtil.evaluate( "bean/bean/flag", contexts ) );
+        assertEquals( "arg", ExpressionUtil.evaluate( "bean/bean/arg", contexts ) );
+    }
+
+    public void testGetProperty()
+    {
+        BeanOne bean1 = new BeanOne();
+        BeanTwo bean2 = new BeanTwo();
+
+        assertEquals( bean1.isFlag(), ExpressionUtil.getProperty( bean1, "flag" ) );
+        assertEquals( bean1.getProp(), ExpressionUtil.getProperty( bean1, "prop" ) );
+        assertEquals( bean1.get( "get" ), ExpressionUtil.getProperty( bean1, "get" ) );
+
+        assertNull( ExpressionUtil.getProperty( bean2, "invalid" ) );
+        assertEquals( bean2.field, ExpressionUtil.getProperty( bean2, "field" ) );
+        assertSame( bean2.bean, ExpressionUtil.getProperty( bean2, "bean" ) );
+
+        assertEquals( new Integer( 0 ), ExpressionUtil.getProperty( new String[0], "length" ) );
+    }
+
+    public static class BeanOne
+    {
+        public String isFlag()
+        {
+            return "flag";
+        }
+
+        public String getProp()
+        {
+            return "prop";
+        }
+
+        public String get( String arg )
+        {
+            return arg;
+        }
+    }
+
+    public static class BeanTwo
+    {
+        public String field = "field";
+
+        public BeanOne bean = new BeanOne();
+
+    }
+}

Propchange: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/ExpressionUtilTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/ExpressionUtilTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/PropertyUtilTest.java
URL: http://svn.apache.org/viewvc/maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/PropertyUtilTest.java?rev=701503&view=auto
==============================================================================
--- maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/PropertyUtilTest.java (added)
+++ maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/PropertyUtilTest.java Fri Oct  3 12:29:31 2008
@@ -0,0 +1,130 @@
+package org.apache.maven.plugin.coreit;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.io.File;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Properties;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Benjamin Bentmann
+ * @version $Id$
+ */
+public class PropertyUtilTest
+    extends TestCase
+{
+
+    public void testStoreScalar()
+    {
+        Properties props = new Properties();
+        PropertyUtil.store( props, "null", null );
+        PropertyUtil.store( props, "string", "str" );
+        PropertyUtil.store( props, "boolean", Boolean.TRUE );
+        PropertyUtil.store( props, "int", new Integer( 7 ) );
+        PropertyUtil.store( props, "file", new File( "pom.xml" ) );
+
+        assertNull( props.get( "null" ) );
+        assertEquals( "str", props.get( "string" ) );
+        assertEquals( "true", props.get( "boolean" ) );
+        assertEquals( "7", props.get( "int" ) );
+        assertEquals( "pom.xml", props.get( "file" ) );
+        assertEquals( 4, props.size() );
+    }
+
+    public void testStoreArray()
+    {
+        Properties props = new Properties();
+        PropertyUtil.store( props, "arr", new String[] { "one", "two" } );
+
+        assertEquals( "2", props.get( "arr" ) );
+        assertEquals( "one", props.get( "arr.0" ) );
+        assertEquals( "two", props.get( "arr.1" ) );
+        assertEquals( 3, props.size() );
+    }
+
+    public void testStoreList()
+    {
+        Properties props = new Properties();
+        PropertyUtil.store( props, "arr", Arrays.asList( new String[] { "one", "two" } ) );
+
+        assertEquals( "2", props.get( "arr" ) );
+        assertEquals( "one", props.get( "arr.0" ) );
+        assertEquals( "two", props.get( "arr.1" ) );
+        assertEquals( 3, props.size() );
+    }
+
+    public void testStoreMap()
+    {
+        Properties props = new Properties();
+        PropertyUtil.store( props, "map", Collections.singletonMap( "key", "value" ) );
+
+        assertEquals( "1", props.get( "map" ) );
+        assertEquals( "value", props.get( "map.key" ) );
+        assertEquals( 2, props.size() );
+    }
+
+    public void testStoreBean()
+    {
+        Properties props = new Properties();
+        PropertyUtil.store( props, "bean", new Bean() );
+
+        assertEquals( "name", props.get( "bean.name" ) );
+        assertEquals( "false", props.get( "bean.enabled" ) );
+        assertEquals( 2, props.size() );
+    }
+
+    public void testGetPropertyName()
+    {
+        assertEquals( "name", PropertyUtil.getPropertyName( "getName" ) );
+        assertEquals( "enabled", PropertyUtil.getPropertyName( "isEnabled" ) );
+    }
+
+    public static class Bean
+    {
+        public String getName()
+        {
+            return "name";
+        }
+
+        public boolean isEnabled()
+        {
+            return false;
+        }
+
+        public String toString()
+        {
+            return "excluded";
+        }
+
+        public Object getUntypedReturnValue()
+        {
+            return "excluded";
+        }
+
+        public Bean getCyclicReference()
+        {
+            return this;
+        }
+    }
+
+}

Propchange: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/PropertyUtilTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/PropertyUtilTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: maven/core-integration-testing/trunk/core-it-support/core-it-plugins/pom.xml
URL: http://svn.apache.org/viewvc/maven/core-integration-testing/trunk/core-it-support/core-it-plugins/pom.xml?rev=701503&r1=701502&r2=701503&view=diff
==============================================================================
--- maven/core-integration-testing/trunk/core-it-support/core-it-plugins/pom.xml (original)
+++ maven/core-integration-testing/trunk/core-it-support/core-it-plugins/pom.xml Fri Oct  3 12:29:31 2008
@@ -39,6 +39,7 @@
     <module>maven-it-plugin-context-passing</module>
     <module>maven-it-plugin-core-stubs</module>
     <module>maven-it-plugin-dependency-resolution</module>
+    <module>maven-it-plugin-expression</module>
     <module>maven-it-plugin-file</module>
     <module>maven-it-plugin-fork</module>
     <module>maven-it-plugin-generate-envar-properties</module>