diff --git a/maven-plugin-tools/.cvsignore b/maven-plugin-tools/.cvsignore
new file mode 100644
index 0000000000..f27d66ad10
--- /dev/null
+++ b/maven-plugin-tools/.cvsignore
@@ -0,0 +1,6 @@
+*~
+*.log
+target
+*.ipr
+*.iws
+*.iml
diff --git a/maven-plugin-tools/pom.xml b/maven-plugin-tools/pom.xml
new file mode 100644
index 0000000000..61c3b378ab
--- /dev/null
+++ b/maven-plugin-tools/pom.xml
@@ -0,0 +1,31 @@
+
+
+
+ 4.0.0
+
+ maven
+ maven-component
+ 2.0-SNAPSHOT
+
+ maven
+ maven-plugin-tools
+ Maven Plugin Tools
+ 2.0-SNAPSHOT
+
+
+ maven
+ maven-plugin
+ 2.0-SNAPSHOT
+
+
+ qdox
+ qdox
+ 1.2
+
+
+ modello
+ modello
+ 1.0-SNAPSHOT
+
+
+
diff --git a/maven-plugin-tools/src/.cvsignore b/maven-plugin-tools/src/.cvsignore
new file mode 100644
index 0000000000..0366c1565c
--- /dev/null
+++ b/maven-plugin-tools/src/.cvsignore
@@ -0,0 +1,4 @@
+maven.log
+target
+.classpath
+.project
diff --git a/maven-plugin-tools/src/main/java/org/apache/maven/plugin/generator/AbstractGenerator.java b/maven-plugin-tools/src/main/java/org/apache/maven/plugin/generator/AbstractGenerator.java
new file mode 100644
index 0000000000..cdc07581a7
--- /dev/null
+++ b/maven-plugin-tools/src/main/java/org/apache/maven/plugin/generator/AbstractGenerator.java
@@ -0,0 +1,296 @@
+package org.apache.maven.plugin.generator;
+
+/*
+ * 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 com.thoughtworks.qdox.JavaDocBuilder;
+import com.thoughtworks.qdox.model.DocletTag;
+import com.thoughtworks.qdox.model.JavaClass;
+import com.thoughtworks.qdox.model.JavaSource;
+import com.thoughtworks.xstream.xml.xpp3.Xpp3Dom;
+import com.thoughtworks.xstream.xml.xpp3.Xpp3DomBuilder;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.descriptor.Parameter;
+
+import java.io.File;
+import java.io.FileReader;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @todo add example usage tag that can be shown in the doco
+ * @todo need to add validation directives so that systems embedding
+ * maven2 can get validation directives to help users in IDEs.
+ */
+public abstract class AbstractGenerator
+ implements Generator
+{
+ public static final String MAVEN_PLUGIN_ID = "maven.plugin.id";
+
+ public static final String MAVEN_PLUGIN_DESCRIPTION = "maven.plugin.description";
+
+ public static final String MAVEN_PLUGIN_INSTANTIATION = "maven.plugin.instantiation";
+
+ public static final String MAVEN_PLUGIN_MODE = "maven.plugin.mode";
+
+ public static final String PARAMETER = "parameter";
+
+ public static final String GOAL = "goal";
+
+ public static final String DISPATCH = "dispatch";
+
+ public static final String GOAL_DESCRIPTION = "description";
+
+ public static final String GOAL_PREREQ = "prereq";
+
+ public static final String GOAL_REQUIRES_DEPENDENCY_RESOLUTION = "requiresDependencyResolution";
+
+ public static final String GOAL_MULTI_EXECUTION_STRATEGY = "attainAlways";
+
+ protected abstract void processPluginDescriptors( MojoDescriptor[] pluginDescriptors, String destinationDirectory, Xpp3Dom pomDom )
+ throws Exception;
+
+ protected Xpp3Dom readModel( String pom )
+ throws Exception
+ {
+ return Xpp3DomBuilder.build( new FileReader( pom ) );
+ }
+
+ public void execute( String sourceDirectory, String destinationDirectory, String pom )
+ throws Exception
+ {
+ Xpp3Dom pomDom = readModel( pom );
+
+ JavaDocBuilder builder = new JavaDocBuilder();
+
+ File sourceDirectoryFile = new File( sourceDirectory );
+
+ builder.addSourceTree( sourceDirectoryFile );
+
+ JavaSource[] javaSources = builder.getSources();
+
+ List mojoDescriptors = new ArrayList();
+
+ for ( int i = 0; i < javaSources.length; i++ )
+ {
+ DocletTag tag = getJavaClass( javaSources[i] ).getTagByName( GOAL );
+
+ if ( tag != null )
+ {
+ MojoDescriptor mojoDescriptor = createMojoDescriptor( javaSources[i], pomDom );
+
+ // ----------------------------------------------------------------------
+ // Validate the descriptor as best we can before allowing it
+ // to be processed.
+ // ----------------------------------------------------------------------
+
+ List parameters = mojoDescriptor.getParameters();
+
+ for ( int j = 0; j < parameters.size(); j++ )
+ {
+ validateParameter( (Parameter) parameters.get( j ), j );
+ }
+
+ mojoDescriptors.add( mojoDescriptor );
+ }
+ }
+
+ MojoDescriptor[] mojos = (MojoDescriptor[]) mojoDescriptors.toArray( new MojoDescriptor[mojoDescriptors.size()] );
+
+ processPluginDescriptors( mojos, destinationDirectory, pomDom );
+ }
+
+ protected void validateParameter( Parameter parameter, int i )
+ throws InvalidParameterException
+ {
+ String name = parameter.getName();
+
+ if ( name == null )
+ {
+ throw new InvalidParameterException( "name", i );
+ }
+
+ String type = parameter.getType();
+
+ if ( type == null )
+ {
+ throw new InvalidParameterException( "type", i );
+ }
+
+ boolean required = parameter.isRequired();
+
+ String validator = parameter.getValidator();
+
+ if ( validator == null )
+ {
+ throw new InvalidParameterException( "validator", i );
+ }
+
+ String expression = parameter.getExpression();
+
+ if ( expression == null )
+ {
+ throw new InvalidParameterException( "expression", i );
+ }
+
+ String description = parameter.getDescription();
+
+ if ( description == null )
+ {
+ throw new InvalidParameterException( "description", i );
+ }
+ }
+
+ protected String pluginId( Xpp3Dom pomDom )
+ {
+ // ----------------------------------------------------------------------
+ // We will take the id from the artifactId of the POM. The artifactId is
+ // always of the form maven--plugin so we can extract the
+ // pluginId from the artifactId.
+ // ----------------------------------------------------------------------
+
+ String artifactId = pomDom.getChild( "artifactId" ).getValue();
+
+ int firstHyphen = artifactId.indexOf( "-" );
+
+ int lastHyphen = artifactId.lastIndexOf( "-" );
+
+ String pluginId = artifactId.substring( firstHyphen + 1, lastHyphen );
+
+ return pluginId;
+ }
+
+ // ----------------------------------------------------------------------
+ // Plugin descriptor creation from @tags
+ // ----------------------------------------------------------------------
+
+ private MojoDescriptor createMojoDescriptor( JavaSource javaSource, Xpp3Dom pomDom )
+ {
+ MojoDescriptor mojoDescriptor = new MojoDescriptor();
+
+ JavaClass javaClass = getJavaClass( javaSource );
+
+ mojoDescriptor.setImplementation( javaClass.getFullyQualifiedName() );
+
+ DocletTag tag;
+
+ String pluginId = pluginId( pomDom );
+
+ mojoDescriptor.setId( pluginId );
+
+ tag = javaClass.getTagByName( MAVEN_PLUGIN_DESCRIPTION );
+
+ if ( tag != null )
+ {
+ mojoDescriptor.setDescription( tag.getValue() );
+ }
+
+ tag = javaClass.getTagByName( MAVEN_PLUGIN_INSTANTIATION );
+
+ if ( tag != null )
+ {
+ mojoDescriptor.setInstantiationStrategy( tag.getValue() );
+ }
+
+ tag = javaClass.getTagByName( GOAL_MULTI_EXECUTION_STRATEGY );
+
+ if ( tag != null )
+ {
+ mojoDescriptor.setExecutionStrategy( MojoDescriptor.MULTI_PASS_EXEC_STRATEGY );
+ }
+ else
+ {
+ mojoDescriptor.setExecutionStrategy( MojoDescriptor.SINGLE_PASS_EXEC_STRATEGY );
+ }
+
+ // ----------------------------------------------------------------------
+ // Goal name
+ // ----------------------------------------------------------------------
+
+ DocletTag goal = javaClass.getTagByName( GOAL );
+
+ if ( goal != null )
+ {
+ mojoDescriptor.setGoal( goal.getValue() );
+ }
+
+ // ----------------------------------------------------------------------
+ // Dependency resolution flag
+ // ----------------------------------------------------------------------
+
+ DocletTag requiresDependencyResolution = javaClass.getTagByName( GOAL_REQUIRES_DEPENDENCY_RESOLUTION );
+
+ if ( requiresDependencyResolution != null )
+ {
+ mojoDescriptor.setRequiresDependencyResolution( true );
+ }
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ DocletTag[] parameterTags = javaClass.getTagsByName( PARAMETER );
+
+ List parameters = new ArrayList();
+
+ for ( int j = 0; j < parameterTags.length; j++ )
+ {
+ DocletTag parameter = parameterTags[j];
+
+ Parameter pd = new Parameter();
+
+ pd.setName( parameter.getNamedParameter( "name" ) );
+
+ pd.setType( parameter.getNamedParameter( "type" ) );
+
+ pd.setRequired( Boolean.getBoolean( parameter.getNamedParameter( "required" ) ) );
+
+ pd.setValidator( parameter.getNamedParameter( "validator" ) );
+
+ pd.setExpression( parameter.getNamedParameter( "expression" ) );
+
+ pd.setDescription( parameter.getNamedParameter( "description" ) );
+
+ parameters.add( pd );
+ }
+
+ mojoDescriptor.setParameters( parameters );
+
+ // ----------------------------------------------------------------------
+ // Prereqs must in the form pluginId:goalName
+ // ----------------------------------------------------------------------
+
+ DocletTag[] goalPrereqTags = javaClass.getTagsByName( GOAL_PREREQ );
+
+ List goalPrereqs = new ArrayList();
+
+ for ( int j = 0; j < goalPrereqTags.length; j++ )
+ {
+ DocletTag goalPrereq = goalPrereqTags[j];
+
+ goalPrereqs.add( goalPrereq.getValue() );
+ }
+
+ mojoDescriptor.setPrereqs( goalPrereqs );
+
+ return mojoDescriptor;
+ }
+
+ private JavaClass getJavaClass( JavaSource javaSource )
+ {
+ return javaSource.getClasses()[0];
+ }
+}
\ No newline at end of file
diff --git a/maven-plugin-tools/src/main/java/org/apache/maven/plugin/generator/BeanGenerator.java b/maven-plugin-tools/src/main/java/org/apache/maven/plugin/generator/BeanGenerator.java
new file mode 100644
index 0000000000..f06e2beda5
--- /dev/null
+++ b/maven-plugin-tools/src/main/java/org/apache/maven/plugin/generator/BeanGenerator.java
@@ -0,0 +1,186 @@
+package org.apache.maven.plugin.generator;
+
+/*
+ * 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 com.thoughtworks.xstream.xml.xpp3.Xpp3Dom;
+import org.apache.maven.plugin.descriptor.Parameter;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.codehaus.modello.generator.java.javasource.JClass;
+import org.codehaus.modello.generator.java.javasource.JConstructor;
+import org.codehaus.modello.generator.java.javasource.JMethod;
+import org.codehaus.modello.generator.java.javasource.JParameter;
+import org.codehaus.modello.generator.java.javasource.JSourceWriter;
+import org.codehaus.modello.generator.java.javasource.JType;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.util.List;
+
+/**
+ * @todo use the descriptions in the descriptor for the javadoc pushed into
+ * the source code.
+ */
+public class BeanGenerator
+ extends AbstractGenerator
+{
+ protected void processPluginDescriptors( MojoDescriptor[] pluginDescriptors, String destinationDirectory, Xpp3Dom pomDom )
+ throws Exception
+ {
+ for ( int i = 0; i < pluginDescriptors.length; i++ )
+ {
+ processPluginDescriptor( pluginDescriptors[i], destinationDirectory );
+ }
+ }
+
+ protected void processPluginDescriptor( MojoDescriptor pluginDescriptor, String destinationDirectory )
+ throws Exception
+ {
+ String implementation = pluginDescriptor.getImplementation();
+
+ String className = implementation.substring( implementation.lastIndexOf( "." ) + 1 ) + "Bean";
+
+ JClass jClass = new JClass( className );
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ jClass.setSuperClass( "org.apache.maven.plugin.BeanPluginAdapter" );
+
+ jClass.addImport( "java.util.*" );
+
+ // ----------------------------------------------------------------------
+ // Use the same package as the plugin we are wrapping.
+ // ----------------------------------------------------------------------
+
+ String packageName = implementation.substring( 0, implementation.lastIndexOf( "." ) );
+
+ jClass.setPackageName( packageName );
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ JConstructor constructor = new JConstructor( jClass );
+
+ constructor.getSourceCode().add( "super( new " + implementation + "() );" );
+
+ jClass.addConstructor( constructor );
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ List parameters = pluginDescriptor.getParameters();
+
+ for ( int i = 0; i < parameters.size(); i++ )
+ {
+ Parameter parameter = (Parameter) parameters.get( i );
+
+ jClass.addMethod( createSetter( parameter, jClass ) );
+ }
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ String packageDirectory = replace( packageName, ".", "/", -1 );
+
+ File destination = new File( destinationDirectory, packageDirectory + "/" + className + ".java" );
+
+ if ( !destination.getParentFile().exists() )
+ {
+ destination.getParentFile().mkdirs();
+ }
+
+ FileWriter writer = new FileWriter( destination );
+
+ JSourceWriter sourceWriter = new JSourceWriter( writer );
+
+ jClass.print( sourceWriter );
+
+ writer.flush();
+
+ writer.close();
+ }
+
+ private JMethod createSetter( Parameter parameter, JClass jClass )
+ {
+ String propertyName = capitalise( parameter.getName() );
+
+ JMethod setter = new JMethod( null, "set" + propertyName );
+
+ String type = parameter.getType();
+
+ JType parameterType;
+
+ int arrayLocation = type.indexOf( "[]" );
+
+ if ( arrayLocation > 0 )
+ {
+ type = type.substring( 0, arrayLocation );
+
+ parameterType = new JClass( type ).createArray();
+ }
+ else
+ {
+ parameterType = new JClass( type );
+ }
+
+ setter.addParameter( new JParameter( parameterType, parameter.getName() ) );
+
+ setter.getSourceCode().add( "addParameter( " + "\"" + parameter.getName() + "\", " + parameter.getName() + " );" );
+
+ return setter;
+ }
+
+ protected String capitalise( String str )
+ {
+ if ( str == null || str.length() == 0 )
+ {
+ return str;
+ }
+
+ return new StringBuffer( str.length() )
+ .append( Character.toTitleCase( str.charAt( 0 ) ) )
+ .append( str.substring( 1 ) )
+ .toString();
+ }
+
+ protected String replace( String text, String repl, String with, int max )
+ {
+ if ( text == null || repl == null || with == null || repl.length() == 0 )
+ {
+ return text;
+ }
+
+ StringBuffer buf = new StringBuffer( text.length() );
+ int start = 0, end = 0;
+ while ( ( end = text.indexOf( repl, start ) ) != -1 )
+ {
+ buf.append( text.substring( start, end ) ).append( with );
+ start = end + repl.length();
+
+ if ( --max == 0 )
+ {
+ break;
+ }
+ }
+ buf.append( text.substring( start ) );
+ return buf.toString();
+ }
+}
\ No newline at end of file
diff --git a/maven-plugin-tools/src/main/java/org/apache/maven/plugin/generator/Generator.java b/maven-plugin-tools/src/main/java/org/apache/maven/plugin/generator/Generator.java
new file mode 100644
index 0000000000..784ac71145
--- /dev/null
+++ b/maven-plugin-tools/src/main/java/org/apache/maven/plugin/generator/Generator.java
@@ -0,0 +1,27 @@
+package org.apache.maven.plugin.generator;
+
+/*
+ * 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.
+ */
+
+/**
+ * @author Jason van Zyl
+ * @version $Id$
+ */
+public interface Generator
+{
+ void execute( String sourceDirectory, String destinationDirectory, String pom )
+ throws Exception;
+}
diff --git a/maven-plugin-tools/src/main/java/org/apache/maven/plugin/generator/InvalidParameterException.java b/maven-plugin-tools/src/main/java/org/apache/maven/plugin/generator/InvalidParameterException.java
new file mode 100644
index 0000000000..c382017f1e
--- /dev/null
+++ b/maven-plugin-tools/src/main/java/org/apache/maven/plugin/generator/InvalidParameterException.java
@@ -0,0 +1,44 @@
+package org.apache.maven.plugin.generator;
+
+/*
+ * 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.
+ */
+
+/**
+ * @author Jason van Zyl
+ * @version $Id$
+ */
+public class InvalidParameterException
+ extends Exception
+{
+ public InvalidParameterException()
+ {
+ }
+
+ public InvalidParameterException( String element, int i )
+ {
+ super( "The " + element + " element in parameter # " + i + " is invalid. It cannot be null." );
+ }
+
+ public InvalidParameterException( Throwable cause )
+ {
+ super( cause );
+ }
+
+ public InvalidParameterException( String message, Throwable cause )
+ {
+ super( message, cause );
+ }
+}
diff --git a/maven-plugin-tools/src/main/java/org/apache/maven/plugin/generator/Main.java b/maven-plugin-tools/src/main/java/org/apache/maven/plugin/generator/Main.java
new file mode 100644
index 0000000000..4bc7337ae8
--- /dev/null
+++ b/maven-plugin-tools/src/main/java/org/apache/maven/plugin/generator/Main.java
@@ -0,0 +1,66 @@
+package org.apache.maven.plugin.generator;
+
+/*
+ * 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.plugin.generator.jelly.JellyHarnessGenerator;
+
+/**
+ * @author Jason van Zyl
+ * @version $Id$
+ */
+public class Main
+{
+ public static void main( String[] args )
+ throws Exception
+ {
+ if ( args.length != 4 )
+ {
+ System.err.println( "Usage: pluggy