package org.apache.maven.tools.plugin.annotations.scanner;
/*
* 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.artifact.Artifact;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Execute;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.tools.plugin.annotations.datamodel.ComponentAnnotationContent;
import org.apache.maven.tools.plugin.annotations.datamodel.ExecuteAnnotationContent;
import org.apache.maven.tools.plugin.annotations.datamodel.MojoAnnotationContent;
import org.apache.maven.tools.plugin.annotations.datamodel.ParameterAnnotationContent;
import org.apache.maven.tools.plugin.annotations.scanner.visitors.MojoAnnotationVisitor;
import org.apache.maven.tools.plugin.annotations.scanner.visitors.MojoClassVisitor;
import org.apache.maven.tools.plugin.annotations.scanner.visitors.MojoFieldVisitor;
import org.apache.maven.tools.plugin.extractor.ExtractionException;
import org.codehaus.plexus.logging.AbstractLogEnabled;
import org.codehaus.plexus.util.DirectoryScanner;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.reflection.Reflector;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Type;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
* @author Olivier Lamy
* @since 3.0
*/
@org.codehaus.plexus.component.annotations.Component( role = MojoAnnotationsScanner.class )
public class DefaultMojoAnnotationsScanner
extends AbstractLogEnabled
implements MojoAnnotationsScanner
{
private Reflector reflector = new Reflector();
public Map<String, MojoAnnotatedClass> scan( MojoAnnotationsScannerRequest request )
throws ExtractionException
{
Map<String, MojoAnnotatedClass> mojoAnnotatedClasses = new HashMap<String, MojoAnnotatedClass>();
try
{
for ( Artifact dependency : request.getDependencies() )
{
File dependencyFile = dependency.getFile();
if ( dependencyFile != null && dependencyFile.exists() )
{
if ( dependencyFile.isDirectory() )
{
mojoAnnotatedClasses.putAll(
scanDirectory( dependencyFile, request.getIncludePatterns(), dependency, true ) );
}
else
{
mojoAnnotatedClasses.putAll(
scanFile( dependencyFile, request.getIncludePatterns(), dependency, true ) );
}
}
}
for ( File classDirectory : request.getClassesDirectories() )
{
if ( classDirectory.exists() && classDirectory.isDirectory() )
{
mojoAnnotatedClasses.putAll(
scanDirectory( classDirectory, request.getIncludePatterns(), request.getProject().getArtifact(),
false ) );
}
}
return mojoAnnotatedClasses;
}
catch ( IOException e )
{
throw new ExtractionException( e.getMessage(), e );
}
}
/**
* @param archiveFile
* @param includePatterns
* @param artifact
* @param excludeMojo for dependencies we exclude Mojo annotations found
* @return
* @throws IOException
* @throws ExtractionException
*/
protected Map<String, MojoAnnotatedClass> scanFile( File archiveFile, List<String> includePatterns,
Artifact artifact, boolean excludeMojo )
throws IOException, ExtractionException
{
if ( !archiveFile.exists() )
{
return Collections.emptyMap();
}
Map<String, MojoAnnotatedClass> mojoAnnotatedClasses = new HashMap<String, MojoAnnotatedClass>();
ZipInputStream archiveStream = new ZipInputStream( new FileInputStream( archiveFile ) );
try
{
for ( ZipEntry zipEntry = archiveStream.getNextEntry(); zipEntry != null;
zipEntry = archiveStream.getNextEntry() )
{
if ( zipEntry.getName().endsWith( ".class" ) )
{
MojoClassVisitor mojoClassVisitor = new MojoClassVisitor( getLogger() );
ClassReader rdr = new ClassReader( archiveStream );
rdr.accept( mojoClassVisitor,
ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG );
analyzeVisitors( mojoClassVisitor );
if ( excludeMojo )
{
mojoClassVisitor.getMojoAnnotatedClass().setMojo( null );
}
if ( isStoreClass( mojoClassVisitor.getMojoAnnotatedClass() ) != null )
{
getLogger().debug(
"found MojoAnnotatedClass:" + mojoClassVisitor.getMojoAnnotatedClass().getClassName() + ":"
+ mojoClassVisitor.getMojoAnnotatedClass() );
mojoClassVisitor.getMojoAnnotatedClass().setArtifact( artifact );
mojoAnnotatedClasses.put( mojoClassVisitor.getMojoAnnotatedClass().getClassName(),
mojoClassVisitor.getMojoAnnotatedClass() );
}
}
}
}
finally
{
IOUtil.close( archiveStream );
}
return mojoAnnotatedClasses;
}
/**
* @param classDirectory
* @param includePatterns
* @param artifact
* @param excludeMojo for dependencies we exclude Mojo annotations found
* @return
* @throws IOException
* @throws ExtractionException
*/
protected Map<String, MojoAnnotatedClass> scanDirectory( File classDirectory, List<String> includePatterns,
Artifact artifact, boolean excludeMojo )
throws IOException, ExtractionException
{
if ( !classDirectory.exists() )
{
return Collections.emptyMap();
}
Map<String, MojoAnnotatedClass> mojoAnnotatedClasses = new HashMap<String, MojoAnnotatedClass>();
DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir( classDirectory );
scanner.addDefaultExcludes();
if ( includePatterns != null )
{
scanner.setIncludes( includePatterns.toArray( new String[includePatterns.size()] ) );
}
scanner.scan();
String[] classFiles = scanner.getIncludedFiles();
for ( String classFile : classFiles )
{
if ( !classFile.endsWith( ".class" ) )
{
continue;
}
InputStream is = new BufferedInputStream( new FileInputStream( new File( classDirectory, classFile ) ) );
try
{
MojoClassVisitor mojoClassVisitor = new MojoClassVisitor( getLogger() );
ClassReader rdr = new ClassReader( is );
rdr.accept( mojoClassVisitor,
ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG );
analyzeVisitors( mojoClassVisitor );
MojoAnnotatedClass mojoAnnotatedClass = mojoClassVisitor.getMojoAnnotatedClass();
if ( excludeMojo )
{
mojoAnnotatedClass.setMojo( null );
}
if ( isStoreClass( mojoAnnotatedClass ) != null )
{
getLogger().debug( "found MojoAnnotatedClass:" + mojoAnnotatedClass.getClassName() + ":"
+ mojoAnnotatedClass );
mojoAnnotatedClass.setArtifact( artifact );
mojoAnnotatedClasses.put( mojoAnnotatedClass.getClassName(), mojoAnnotatedClass );
}
}
finally
{
IOUtil.close( is );
}
}
return mojoAnnotatedClasses;
}
private MojoAnnotatedClass isStoreClass( MojoAnnotatedClass mojoAnnotatedClass )
{
// see MPLUGIN-206 we can have intermediate classes without annotations
if ( mojoAnnotatedClass == null )
{
return null;
}
return mojoAnnotatedClass;
/**
if ( !mojoAnnotatedClass.getComponents().isEmpty() || !mojoAnnotatedClass.getParameters().isEmpty()
|| mojoAnnotatedClass.getExecute() != null || mojoAnnotatedClass.getMojo() != null )
{
return mojoAnnotatedClass;
}
return null;
**/
}
protected void analyzeVisitors( MojoClassVisitor mojoClassVisitor )
throws ExtractionException
{
try
{
MojoAnnotationVisitor mojoAnnotationVisitor =
mojoClassVisitor.getAnnotationVisitorMap().get( Mojo.class.getName() );
if ( mojoAnnotationVisitor != null )
{
MojoAnnotationContent mojoAnnotationContent = new MojoAnnotationContent();
for ( Map.Entry<String, Object> entry : mojoAnnotationVisitor.getAnnotationValues().entrySet() )
{
reflector.invoke( mojoAnnotationContent, entry.getKey(), new Object[]{ entry.getValue() } );
}
mojoClassVisitor.getMojoAnnotatedClass().setMojo( mojoAnnotationContent );
}
mojoAnnotationVisitor = mojoClassVisitor.getAnnotationVisitorMap().get( Execute.class.getName() );
if ( mojoAnnotationVisitor != null )
{
ExecuteAnnotationContent executeAnnotationContent = new ExecuteAnnotationContent();
for ( Map.Entry<String, Object> entry : mojoAnnotationVisitor.getAnnotationValues().entrySet() )
{
reflector.invoke( executeAnnotationContent, entry.getKey(), new Object[]{ entry.getValue() } );
}
mojoClassVisitor.getMojoAnnotatedClass().setExecute( executeAnnotationContent );
}
List<MojoFieldVisitor> mojoFieldVisitors =
mojoClassVisitor.findFieldWithAnnotationClass( Parameter.class.getName() );
for ( MojoFieldVisitor mojoFieldVisitor : mojoFieldVisitors )
{
ParameterAnnotationContent parameterAnnotationContent =
new ParameterAnnotationContent( mojoFieldVisitor.getFieldName(), mojoFieldVisitor.getClassName() );
if ( mojoFieldVisitor.getMojoAnnotationVisitor() != null )
{
for ( Map.Entry<String, Object> entry : mojoFieldVisitor.getMojoAnnotationVisitor().getAnnotationValues().entrySet() )
{
reflector.invoke( parameterAnnotationContent, entry.getKey(),
new Object[]{ entry.getValue() } );
}
}
mojoClassVisitor.getMojoAnnotatedClass().getParameters().put( parameterAnnotationContent.getFieldName(),
parameterAnnotationContent );
}
mojoFieldVisitors = mojoClassVisitor.findFieldWithAnnotationClass( Component.class.getName() );
for ( MojoFieldVisitor mojoFieldVisitor : mojoFieldVisitors )
{
ComponentAnnotationContent componentAnnotationContent =
new ComponentAnnotationContent( mojoFieldVisitor.getFieldName() );
if ( mojoFieldVisitor.getMojoAnnotationVisitor() != null )
{
for ( Map.Entry<String, Object> entry : mojoFieldVisitor.getMojoAnnotationVisitor().getAnnotationValues().entrySet() )
{
String methodName = entry.getKey();
if ( StringUtils.equals( "role", methodName ) )
{
Type type = (Type) entry.getValue();
componentAnnotationContent.setRoleClassName( type.getClassName() );
}
else
{
reflector.invoke( componentAnnotationContent, entry.getKey(),
new Object[]{ entry.getValue() } );
}
}
if ( StringUtils.isEmpty( componentAnnotationContent.getRoleClassName() ) )
{
componentAnnotationContent.setRoleClassName( mojoFieldVisitor.getClassName() );
}
}
mojoClassVisitor.getMojoAnnotatedClass().getComponents().put( componentAnnotationContent.getFieldName(),
componentAnnotationContent );
}
}
catch ( Exception e )
{
throw new ExtractionException( e.getMessage(), e );
}
}
}