Repository: maven-archetype Updated Branches: refs/heads/master e188f8fd0 -> 147ff3dc6
[ARCHETYPE-487] Add regex input validation for required properties defined in artifact descriptor This closes #7 Project: http://git-wip-us.apache.org/repos/asf/maven-archetype/repo Commit: http://git-wip-us.apache.org/repos/asf/maven-archetype/commit/147ff3dc Tree: http://git-wip-us.apache.org/repos/asf/maven-archetype/tree/147ff3dc Diff: http://git-wip-us.apache.org/repos/asf/maven-archetype/diff/147ff3dc Branch: refs/heads/master Commit: 147ff3dc6086e947faf8bead6b8ee70c584da1b5 Parents: e188f8f Author: Manuel Ryan <r...@shamu.ch> Authored: Fri Sep 4 13:47:43 2015 +0200 Committer: Michael Osipov <micha...@apache.org> Committed: Fri Jun 24 19:49:50 2016 +0200 ---------------------------------------------------------------------- .../src/main/mdo/archetype-descriptor.mdo | 6 ++ .../archetype/ui/ArchetypeConfiguration.java | 26 ++++++ .../archetype/ui/DefaultArchetypeFactory.java | 10 ++- .../generation/ArchetypeGenerationQueryer.java | 4 +- .../DefaultArchetypeGenerationConfigurator.java | 5 +- .../DefaultArchetypeGenerationQueryer.java | 49 ++++++++++-- .../DefaultArchetypeGenerationQueryerTest.java | 83 ++++++++++++++++++++ 7 files changed, 171 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/maven-archetype/blob/147ff3dc/archetype-models/archetype-descriptor/src/main/mdo/archetype-descriptor.mdo ---------------------------------------------------------------------- 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> http://git-wip-us.apache.org/repos/asf/maven-archetype/blob/147ff3dc/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/ArchetypeConfiguration.java ---------------------------------------------------------------------- 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 @@ package org.apache.maven.archetype.ui; */ 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 @@ public class ArchetypeConfiguration { 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(); + } + } http://git-wip-us.apache.org/repos/asf/maven-archetype/blob/147ff3dc/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/DefaultArchetypeFactory.java ---------------------------------------------------------------------- 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 @@ package org.apache.maven.archetype.ui; 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 @@ public class DefaultArchetypeFactory configuration.addRequiredProperty( key ); String defaultValue = requiredProperty.getDefaultValue(); + String validationRegex = requiredProperty.getValidationRegex(); if ( properties.getProperty( key ) != null ) { @@ -148,6 +148,12 @@ public class DefaultArchetypeFactory 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 @@ public class DefaultArchetypeFactory /** * 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> */ http://git-wip-us.apache.org/repos/asf/maven-archetype/blob/147ff3dc/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/generation/ArchetypeGenerationQueryer.java ---------------------------------------------------------------------- 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 @@ package org.apache.maven.archetype.ui.generation; 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 @@ public interface ArchetypeGenerationQueryer boolean confirmConfiguration( ArchetypeConfiguration archetypeConfiguration ) throws PrompterException; - String getPropertyValue( String requiredProperty, String defaultValue ) + String getPropertyValue( String requiredProperty, String defaultValue, Pattern validationRegex ) throws PrompterException; } http://git-wip-us.apache.org/repos/asf/maven-archetype/blob/147ff3dc/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/generation/DefaultArchetypeGenerationConfigurator.java ---------------------------------------------------------------------- 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 @@ public class DefaultArchetypeGenerationConfigurator getTransitiveDefaultValue( packageDefault, archetypeConfiguration, requiredProperty, context ); - value = archetypeGenerationQueryer.getPropertyValue( requiredProperty, value ); + value = archetypeGenerationQueryer.getPropertyValue( requiredProperty, value, null ); archetypeConfiguration.setProperty( requiredProperty, value ); @@ -197,7 +197,8 @@ public class DefaultArchetypeGenerationConfigurator value = getTransitiveDefaultValue( value, archetypeConfiguration, requiredProperty, context ); - value = archetypeGenerationQueryer.getPropertyValue( requiredProperty, value ); + value = archetypeGenerationQueryer.getPropertyValue( requiredProperty, value, + archetypeConfiguration.getPropertyValidationRegex( requiredProperty ) ); archetypeConfiguration.setProperty( requiredProperty, value ); http://git-wip-us.apache.org/repos/asf/maven-archetype/blob/147ff3dc/maven-archetype-plugin/src/main/java/org/apache/maven/archetype/ui/generation/DefaultArchetypeGenerationQueryer.java ---------------------------------------------------------------------- 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.Prompter; 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 @@ public class DefaultArchetypeGenerationQueryer 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; + } } http://git-wip-us.apache.org/repos/asf/maven-archetype/blob/147ff3dc/maven-archetype-plugin/src/test/java/org/apache/maven/archetype/ui/generation/DefaultArchetypeGenerationQueryerTest.java ---------------------------------------------------------------------- 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 "..."; + } + }; + } + +}