[ARCHETYPE-487] Add regex input validation for required properties defined in artifact descriptor
This closes #7
diff --git a/archetype-models/archetype-descriptor/src/main/mdo/archetype-descriptor.mdo b/archetype-models/archetype-descriptor/src/main/mdo/archetype-descriptor.mdo
index e18fdb6..c689716 100644
--- a/archetype-models/archetype-descriptor/src/main/mdo/archetype-descriptor.mdo
+++ b/archetype-models/archetype-descriptor/src/main/mdo/archetype-descriptor.mdo
@@ -209,6 +209,12 @@
<required>false</required>
<description>Default value of the property.</description>
</field>
+ <field>
+ <name>validationRegex</name>
+ <type>String</type>
+ <required>false</required>
+ <description>A regular expression used to validate the property.</description>
+ </field>
</fields>
</class>
</classes>
diff --git a/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/ArchetypeConfiguration.java b/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/ArchetypeConfiguration.java
index 08b52bd..a17935f 100644
--- a/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/ArchetypeConfiguration.java
+++ b/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/ArchetypeConfiguration.java
@@ -20,8 +20,11 @@
*/
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Properties;
+import java.util.regex.Pattern;
import org.apache.maven.archetype.common.Constants;
import org.codehaus.plexus.util.StringUtils;
@@ -214,4 +217,27 @@
{
return defaultProperties;
}
+
+ Map<String, Pattern> propertiesValidationPatterns = new HashMap<String, Pattern>();
+
+ public void setPropertyValidationRegex( String requiredProperty, String regex )
+ {
+ propertiesValidationPatterns.put( requiredProperty, Pattern.compile( regex ) );
+ }
+
+ public Pattern getPropertyValidationRegex( String requiredProperty )
+ {
+ return propertiesValidationPatterns.get( requiredProperty );
+ }
+
+ public boolean validatePropertyValue( String property, String value )
+ {
+ Pattern pattern = propertiesValidationPatterns.get( property );
+ if ( pattern == null )
+ {
+ return true;
+ }
+ return pattern.matcher( value ).matches();
+ }
+
}
diff --git a/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/DefaultArchetypeFactory.java b/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/DefaultArchetypeFactory.java
index 0d0f13b..98f6bb9 100644
--- a/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/DefaultArchetypeFactory.java
+++ b/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/DefaultArchetypeFactory.java
@@ -22,7 +22,6 @@
import org.apache.maven.archetype.common.Constants;
import org.apache.maven.archetype.metadata.RequiredProperty;
import org.apache.maven.project.MavenProject;
-
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.logging.AbstractLogEnabled;
@@ -128,6 +127,7 @@
configuration.addRequiredProperty( key );
String defaultValue = requiredProperty.getDefaultValue();
+ String validationRegex = requiredProperty.getValidationRegex();
if ( properties.getProperty( key ) != null )
{
@@ -148,6 +148,12 @@
configuration.setDefaultProperty( key, defaultValue );
getLogger().debug( "Setting defaultProperty " + key + "=" + defaultValue );
}
+
+ if ( validationRegex != null )
+ {
+ configuration.setPropertyValidationRegex( key, validationRegex );
+ getLogger().debug( "Setting validation regular expression " + key + "=" + defaultValue );
+ }
}
addRequiredProperty( configuration, properties, Constants.GROUP_ID, null, false );
@@ -269,7 +275,7 @@
/**
* Check if the given value references a property, ie contains <code>${...}</code>.
- *
+ *
* @param defaultValue the value to check
* @return <code>true</code> if the value contains <code>${</code> followed by <code>}</code>
*/
diff --git a/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/generation/ArchetypeGenerationQueryer.java b/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/generation/ArchetypeGenerationQueryer.java
index 9f46f69..a432df6 100644
--- a/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/generation/ArchetypeGenerationQueryer.java
+++ b/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/generation/ArchetypeGenerationQueryer.java
@@ -22,6 +22,8 @@
import org.apache.maven.archetype.ui.ArchetypeConfiguration;
import org.codehaus.plexus.components.interactivity.PrompterException;
+import java.util.regex.Pattern;
+
/**
* User interaction component to query informations necessary for a project generation from an archetype.
*
@@ -32,6 +34,6 @@
boolean confirmConfiguration( ArchetypeConfiguration archetypeConfiguration )
throws PrompterException;
- String getPropertyValue( String requiredProperty, String defaultValue )
+ String getPropertyValue( String requiredProperty, String defaultValue, Pattern validationRegex )
throws PrompterException;
}
diff --git a/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/generation/DefaultArchetypeGenerationConfigurator.java b/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/generation/DefaultArchetypeGenerationConfigurator.java
index 88f8fd1..cb0fb3a 100644
--- a/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/generation/DefaultArchetypeGenerationConfigurator.java
+++ b/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/generation/DefaultArchetypeGenerationConfigurator.java
@@ -184,7 +184,7 @@
getTransitiveDefaultValue( packageDefault, archetypeConfiguration, requiredProperty,
context );
- value = archetypeGenerationQueryer.getPropertyValue( requiredProperty, value );
+ value = archetypeGenerationQueryer.getPropertyValue( requiredProperty, value, null );
archetypeConfiguration.setProperty( requiredProperty, value );
@@ -197,7 +197,8 @@
value = getTransitiveDefaultValue( value, archetypeConfiguration, requiredProperty,
context );
- value = archetypeGenerationQueryer.getPropertyValue( requiredProperty, value );
+ value = archetypeGenerationQueryer.getPropertyValue( requiredProperty, value,
+ archetypeConfiguration.getPropertyValidationRegex( requiredProperty ) );
archetypeConfiguration.setProperty( requiredProperty, value );
diff --git a/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/generation/DefaultArchetypeGenerationQueryer.java b/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/generation/DefaultArchetypeGenerationQueryer.java
index 80c8f1e..5b8f5ae 100644
--- a/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/generation/DefaultArchetypeGenerationQueryer.java
+++ b/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/generation/DefaultArchetypeGenerationQueryer.java
@@ -26,6 +26,8 @@
import org.codehaus.plexus.components.interactivity.PrompterException;
import org.codehaus.plexus.logging.AbstractLogEnabled;
+import java.util.regex.Pattern;
+
@Component( role = ArchetypeGenerationQueryer.class, hint = "default" )
public class DefaultArchetypeGenerationQueryer
extends AbstractLogEnabled
@@ -49,20 +51,53 @@
return "Y".equalsIgnoreCase( answer );
}
- public String getPropertyValue( String requiredProperty, String defaultValue )
+ public String getPropertyValue( String requiredProperty, String defaultValue, Pattern validationRegex )
throws PrompterException
{
- String query = "Define value for property '" + requiredProperty + "': ";
- String answer;
+ StringBuilder queryBuilder = new StringBuilder();
+ queryBuilder.append( "Define value for property '" );
+ queryBuilder.append( requiredProperty );
+ queryBuilder.append( '\'' );
- if ( ( defaultValue != null ) && !defaultValue.equals( "null" ) )
+ if ( validationRegex != null )
{
- answer = prompter.prompt( query, defaultValue );
+ queryBuilder.append( " (should match expression '" );
+ queryBuilder.append( validationRegex );
+ queryBuilder.append( "')" );
}
- else
+
+ String query = queryBuilder.toString();
+ String answer;
+ boolean validAnswer = false;
+
+ do
{
- answer = prompter.prompt( query );
+ if ( ( defaultValue != null ) && !defaultValue.equals( "null" ) )
+ {
+ answer = prompter.prompt( query, defaultValue );
+ }
+ else
+ {
+ answer = prompter.prompt( query );
+ }
+
+ if ( validationRegex == null || validationRegex.matcher( answer ).matches() )
+ {
+ validAnswer = true;
+ }
+ else
+ {
+ query = "Value does not match the expression, please try again";
+ }
+
}
+ while ( !validAnswer );
+
return answer;
}
+
+ public void setPrompter( Prompter prompter )
+ {
+ this.prompter = prompter;
+ }
}
diff --git a/maven-archetype-plugin/src/test/java/org/apache/maven/archetype/ui/generation/DefaultArchetypeGenerationQueryerTest.java b/maven-archetype-plugin/src/test/java/org/apache/maven/archetype/ui/generation/DefaultArchetypeGenerationQueryerTest.java
new file mode 100644
index 0000000..13adad9
--- /dev/null
+++ b/maven-archetype-plugin/src/test/java/org/apache/maven/archetype/ui/generation/DefaultArchetypeGenerationQueryerTest.java
@@ -0,0 +1,83 @@
+package org.apache.maven.archetype.ui.generation;
+
+/*
+ * 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.codehaus.plexus.PlexusTestCase;
+import org.codehaus.plexus.components.interactivity.Prompter;
+import org.codehaus.plexus.components.interactivity.PrompterException;
+import org.easymock.AbstractMatcher;
+import org.easymock.ArgumentsMatcher;
+import org.easymock.MockControl;
+
+import java.util.regex.Pattern;
+
+public class DefaultArchetypeGenerationQueryerTest
+ extends PlexusTestCase
+{
+
+ private DefaultArchetypeGenerationQueryer queryer;
+
+ public void setUp()
+ throws Exception
+ {
+ super.setUp();
+
+ queryer = (DefaultArchetypeGenerationQueryer) lookup( ArchetypeGenerationQueryer.class.getName() );
+ }
+
+ public void testPropertyRegexValidationRetry()
+ throws PrompterException
+ {
+
+ MockControl control = MockControl.createControl( Prompter.class );
+
+ Prompter prompter = (Prompter) control.getMock();
+ prompter.prompt( "" );
+ control.setMatcher( createArgumentMatcher() );
+ control.setReturnValue( "invalid-answer" );
+ queryer.setPrompter( prompter );
+ prompter.prompt( "" );
+ control.setReturnValue( "valid-answer" );
+ queryer.setPrompter( prompter );
+ control.replay();
+
+ String value = queryer.getPropertyValue( "custom-property", null, Pattern.compile( "^valid-.*" ) );
+
+ assertEquals( "valid-answer", value );
+
+ }
+
+ private static ArgumentsMatcher createArgumentMatcher()
+ {
+ return new AbstractMatcher()
+ {
+ protected boolean argumentMatches( Object o, Object o1 )
+ {
+ return true;
+ }
+
+ protected String argumentToString( Object o )
+ {
+ return "...";
+ }
+ };
+ }
+
+}