/* * 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 bsh.*; import java.util.regex.Pattern; import java.io.FileInputStream; import java.io.InputStreamReader; import org.codehaus.plexus.util.StringUtils; import org.apache.maven.plugin.descriptor.Parameter; import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException; // only on start of line this.tag = "\\r?\\n\\s*\\*?\\s*@(\\w+)"; // zero width lookahead to next tag or end of comment this.tagOrEndComment = "(?=" + tag + "|\\*/)"; this.commentTextPattern = Pattern.compile( "(?s)/\\*\\*(.*?)" + tagOrEndComment ); this.tagsPattern = Pattern.compile( "(?s)" + tag + "\\s*(.*?)" + tagOrEndComment ); this.descriptionPattern = Pattern.compile( "(?s)\\r?\\n\\s*\\*" ); this.typePattern = Pattern.compile( "type\\s*=\\s*\"(.*?)\"" ); this.expressionPattern = Pattern.compile( "expression\\s*=\\s*\"(.*?)\"" ); this.defaultValuePattern = Pattern.compile( "default-value\\s*=\\s*\"(.*?)\"" ); this.phasePattern = Pattern.compile( "phase\\s*=\\s*\"(.*?)\"" ); this.goalPattern = Pattern.compile( "goal\\s*=\\s*\"(.*?)\"" ); this.lifecyclePattern = Pattern.compile( "lifecycle\\s*=\\s*\"(.*?)\"" ); this.rolePattern = Pattern.compile( "role\\s*=\\s*\"(.*?)\"" ); this.roleHintPattern = Pattern.compile( "roleHint\\s*=\\s*\"(.*?)\"" ); setAccessibility( true ); createParameter( text, method ) { if ( method.startsWith( "set" ) ) { this.name = StringUtils.uncapitalise( method.substring( 3 ) ); this.desc = getDescription( text ); this.tags = getTags( text ); this.parameter = new Parameter(); parameter.setName( name ); parameter.setDescription( desc ); parameter.setRequired( tags.containsKey( "required" ) ); parameter.setEditable( !tags.containsKey( "readonly" ) ); this.deprecation = tags.get( "deprecated" ); if ( deprecation != null ) { parameter.setDeprecated( deprecation ); } this.alias = tags.get( "alias" ); if ( alias != null ) { parameter.setAlias( alias ); } this.value = tags.get( "parameter" ); if ( value != null ) { m = typePattern.matcher( value ); if ( m.find() ) { parameter.setType( m.group( 1 ) ); } else { parameter.setType( "java.lang.Object" ); } m = expressionPattern.matcher( value ); if ( m.find() ) { parameter.setExpression( m.group( 1 ) ); } m = defaultValuePattern.matcher( value ); if ( m.find() ) { parameter.setDefaultValue( m.group( 1 ) ); } } value = tags.get( "component" ); if ( value != null ) { m = rolePattern.matcher( value ); if ( m.find() ) { role = m.group( 1 ); } m = roleHintPattern.matcher( value ); if ( m.find() ) { roleHint = m.group( 1 ); } else { roleHint = null; } parameter.setRequirement( new Requirement( role, roleHint ) ); } return parameter; } return null; } getTags( text ) { this.matcher = tagsPattern.matcher( text ); this.tags = new HashMap(); while ( matcher.find() ) { this.tagname = matcher.group( 1 ); this.tagvalue = matcher.group( 2 ); tags.put( tagname, tagvalue.trim() ); } return tags; } getDescription( text ) { this.matcher = commentTextPattern.matcher( text ); if ( matcher.find() ) { this.input = matcher.group( 1 ); return descriptionPattern.matcher( input ).replaceAll( "" ).trim(); } else { return ""; } } extract( file, encoding, mojoDescriptor ) { this.parser = new Parser( new InputStreamReader( new FileInputStream( file ), encoding ) ); parser.setRetainComments( true ); this.lastNode = null; this.firstComment = null; while ( !parser.Line() ) { this.node = parser.popNode(); if ( node instanceof BSHFormalComment && firstComment == null ) { firstComment = node; } if ( node instanceof BSHMethodDeclaration ) { if ( lastNode instanceof BSHFormalComment ) { this.text = lastNode.text; this.method = node.name; this.parameter = createParameter( text, method ); if ( parameter != null ) { if ( "${reports}".equals( parameter.getExpression() ) ) { mojoDescriptor.setRequiresReports( true ); } mojoDescriptor.addParameter( parameter ); } if ( firstComment == lastNode ) { firstComment = null; } } } lastNode = node; } if ( firstComment != null ) { this.text = firstComment.text; mojoDescriptor.setDescription( getDescription( text ) ); this.tags = getTags( text ); mojoDescriptor.setGoal( tags.get( "goal" ) ); mojoDescriptor.setPhase( tags.get( "phase" ) ); this.value = tags.get( "requiresDependencyResolution" ); // TODO: share with java extractor if ( value == null || value.length() == 0 ) { value = "runtime"; } mojoDescriptor.setDependencyResolutionRequired( value ); mojoDescriptor.setProjectRequired( tags.containsKey( "requiresProject" ) ); mojoDescriptor.setOnlineRequired( tags.containsKey( "requiresOnline" ) ); this.value = tags.get( "execute" ); if ( value != null ) { m = phasePattern.matcher( value ); if ( m.find() ) { mojoDescriptor.setExecutePhase( m.group( 1 ) ); } m = goalPattern.matcher( value ); if ( m.find() ) { mojoDescriptor.setExecuteGoal( m.group( 1 ) ); } if ( mojoDescriptor.getExecutePhase() == null || mojoDescriptor.getExecuteGoal() == null ) { throw new InvalidPluginDescriptorException( "@execute must have a phase or goal" ); } if ( mojoDescriptor.getExecutePhase() != null && mojoDescriptor.getExecuteGoal() != null ) { throw new InvalidPluginDescriptorException( "@execute must have only one of a phase or goal" ); } m = lifecyclePattern.matcher( value ); if ( m.find() ) { mojoDescriptor.setExecuteLifecycle( m.group( 1 ) ); if ( mojoDescriptor.getExecuteGoal() != null ) { throw new InvalidPluginDescriptorException( "@execute lifecycle requires a phase instead of a goal" ); } } } } } extract( file, encoding, mojoDescriptor );