Coverage Report - org.apache.maven.tools.plugin.annotations.scanner.DefaultMojoAnnotationsScanner
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultMojoAnnotationsScanner
68%
73/107
53%
33/62
8.8
 
 1  
 package org.apache.maven.tools.plugin.annotations.scanner;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import org.apache.maven.artifact.Artifact;
 23  
 import org.apache.maven.plugins.annotations.Component;
 24  
 import org.apache.maven.plugins.annotations.Execute;
 25  
 import org.apache.maven.plugins.annotations.Mojo;
 26  
 import org.apache.maven.plugins.annotations.Parameter;
 27  
 import org.apache.maven.tools.plugin.annotations.datamodel.ComponentAnnotationContent;
 28  
 import org.apache.maven.tools.plugin.annotations.datamodel.ExecuteAnnotationContent;
 29  
 import org.apache.maven.tools.plugin.annotations.datamodel.MojoAnnotationContent;
 30  
 import org.apache.maven.tools.plugin.annotations.datamodel.ParameterAnnotationContent;
 31  
 import org.apache.maven.tools.plugin.annotations.scanner.visitors.MojoAnnotationVisitor;
 32  
 import org.apache.maven.tools.plugin.annotations.scanner.visitors.MojoClassVisitor;
 33  
 import org.apache.maven.tools.plugin.annotations.scanner.visitors.MojoFieldVisitor;
 34  
 import org.apache.maven.tools.plugin.extractor.ExtractionException;
 35  
 import org.codehaus.plexus.logging.AbstractLogEnabled;
 36  
 import org.codehaus.plexus.util.DirectoryScanner;
 37  
 import org.codehaus.plexus.util.IOUtil;
 38  
 import org.codehaus.plexus.util.StringUtils;
 39  
 import org.codehaus.plexus.util.reflection.Reflector;
 40  
 import org.objectweb.asm.ClassReader;
 41  
 import org.objectweb.asm.Type;
 42  
 
 43  
 import java.io.BufferedInputStream;
 44  
 import java.io.File;
 45  
 import java.io.FileInputStream;
 46  
 import java.io.IOException;
 47  
 import java.io.InputStream;
 48  
 import java.util.Collections;
 49  
 import java.util.HashMap;
 50  
 import java.util.List;
 51  
 import java.util.Map;
 52  
 import java.util.zip.ZipEntry;
 53  
 import java.util.zip.ZipInputStream;
 54  
 
 55  
 /**
 56  
  * @author Olivier Lamy
 57  
  * @since 3.0
 58  
  */
 59  
 @org.codehaus.plexus.component.annotations.Component( role = MojoAnnotationsScanner.class )
 60  1
 public class DefaultMojoAnnotationsScanner
 61  
     extends AbstractLogEnabled
 62  
     implements MojoAnnotationsScanner
 63  
 {
 64  1
     private Reflector reflector = new Reflector();
 65  
 
 66  
     public Map<String, MojoAnnotatedClass> scan( MojoAnnotationsScannerRequest request )
 67  
         throws ExtractionException
 68  
     {
 69  1
         Map<String, MojoAnnotatedClass> mojoAnnotatedClasses = new HashMap<String, MojoAnnotatedClass>();
 70  
         try
 71  
         {
 72  
 
 73  1
             for ( Artifact dependency : request.getDependencies() )
 74  
             {
 75  0
                 File dependencyFile = dependency.getFile();
 76  0
                 if ( dependencyFile != null && dependencyFile.exists() )
 77  
                 {
 78  0
                     if ( dependencyFile.isDirectory() )
 79  
                     {
 80  0
                         mojoAnnotatedClasses.putAll(
 81  
                             scanDirectory( dependencyFile, request.getIncludePatterns(), dependency, true ) );
 82  
                     }
 83  
                     else
 84  
                     {
 85  0
                         mojoAnnotatedClasses.putAll(
 86  
                             scanFile( dependencyFile, request.getIncludePatterns(), dependency, true ) );
 87  
                     }
 88  
                 }
 89  0
             }
 90  
 
 91  1
             for ( File classDirectory : request.getClassesDirectories() )
 92  
             {
 93  1
                 if ( classDirectory.exists() && classDirectory.isDirectory() )
 94  
                 {
 95  1
                     mojoAnnotatedClasses.putAll(
 96  
                         scanDirectory( classDirectory, request.getIncludePatterns(), request.getProject().getArtifact(),
 97  
                                        false ) );
 98  
                 }
 99  
             }
 100  
 
 101  1
             return mojoAnnotatedClasses;
 102  
         }
 103  0
         catch ( IOException e )
 104  
         {
 105  0
             throw new ExtractionException( e.getMessage(), e );
 106  
         }
 107  
     }
 108  
 
 109  
     /**
 110  
      * @param archiveFile
 111  
      * @param includePatterns
 112  
      * @param artifact
 113  
      * @param excludeMojo     for dependencies we exclude Mojo annotations found
 114  
      * @return
 115  
      * @throws IOException
 116  
      * @throws ExtractionException
 117  
      */
 118  
     protected Map<String, MojoAnnotatedClass> scanFile( File archiveFile, List<String> includePatterns,
 119  
                                                         Artifact artifact, boolean excludeMojo )
 120  
         throws IOException, ExtractionException
 121  
     {
 122  0
         if ( !archiveFile.exists() )
 123  
         {
 124  0
             return Collections.emptyMap();
 125  
         }
 126  0
         Map<String, MojoAnnotatedClass> mojoAnnotatedClasses = new HashMap<String, MojoAnnotatedClass>();
 127  0
         ZipInputStream archiveStream = new ZipInputStream( new FileInputStream( archiveFile ) );
 128  
 
 129  
         try
 130  
         {
 131  0
             for ( ZipEntry zipEntry = archiveStream.getNextEntry(); zipEntry != null;
 132  0
                   zipEntry = archiveStream.getNextEntry() )
 133  
             {
 134  0
                 if ( zipEntry.getName().endsWith( ".class" ) )
 135  
                 {
 136  0
                     MojoClassVisitor mojoClassVisitor = new MojoClassVisitor( getLogger() );
 137  
 
 138  0
                     ClassReader rdr = new ClassReader( archiveStream );
 139  0
                     rdr.accept( mojoClassVisitor,
 140  
                                 ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG );
 141  0
                     analyzeVisitors( mojoClassVisitor );
 142  0
                     if ( excludeMojo )
 143  
                     {
 144  0
                         mojoClassVisitor.getMojoAnnotatedClass().setMojo( null );
 145  
                     }
 146  0
                     if ( isStoreClass( mojoClassVisitor.getMojoAnnotatedClass() ) != null )
 147  
                     {
 148  0
                         getLogger().debug(
 149  
                             "found MojoAnnotatedClass:" + mojoClassVisitor.getMojoAnnotatedClass().getClassName() + ":"
 150  
                                 + mojoClassVisitor.getMojoAnnotatedClass() );
 151  0
                         mojoClassVisitor.getMojoAnnotatedClass().setArtifact( artifact );
 152  0
                         mojoAnnotatedClasses.put( mojoClassVisitor.getMojoAnnotatedClass().getClassName(),
 153  
                                                   mojoClassVisitor.getMojoAnnotatedClass() );
 154  
                     }
 155  
                 }
 156  
             }
 157  
         }
 158  
         finally
 159  
         {
 160  0
             IOUtil.close( archiveStream );
 161  0
         }
 162  0
         return mojoAnnotatedClasses;
 163  
     }
 164  
 
 165  
     /**
 166  
      * @param classDirectory
 167  
      * @param includePatterns
 168  
      * @param artifact
 169  
      * @param excludeMojo     for dependencies we exclude Mojo annotations found
 170  
      * @return
 171  
      * @throws IOException
 172  
      * @throws ExtractionException
 173  
      */
 174  
     protected Map<String, MojoAnnotatedClass> scanDirectory( File classDirectory, List<String> includePatterns,
 175  
                                                              Artifact artifact, boolean excludeMojo )
 176  
         throws IOException, ExtractionException
 177  
     {
 178  1
         if ( !classDirectory.exists() )
 179  
         {
 180  0
             return Collections.emptyMap();
 181  
         }
 182  1
         Map<String, MojoAnnotatedClass> mojoAnnotatedClasses = new HashMap<String, MojoAnnotatedClass>();
 183  1
         DirectoryScanner scanner = new DirectoryScanner();
 184  1
         scanner.setBasedir( classDirectory );
 185  1
         scanner.addDefaultExcludes();
 186  1
         if ( includePatterns != null )
 187  
         {
 188  1
             scanner.setIncludes( includePatterns.toArray( new String[includePatterns.size()] ) );
 189  
         }
 190  1
         scanner.scan();
 191  1
         String[] classFiles = scanner.getIncludedFiles();
 192  
 
 193  2
         for ( String classFile : classFiles )
 194  
         {
 195  1
             if ( !classFile.endsWith( ".class" ) )
 196  
             {
 197  0
                 continue;
 198  
             }
 199  
 
 200  1
             InputStream is = new BufferedInputStream( new FileInputStream( new File( classDirectory, classFile ) ) );
 201  
             try
 202  
             {
 203  1
                 MojoClassVisitor mojoClassVisitor = new MojoClassVisitor( getLogger() );
 204  1
                 ClassReader rdr = new ClassReader( is );
 205  1
                 rdr.accept( mojoClassVisitor,
 206  
                             ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG );
 207  1
                 analyzeVisitors( mojoClassVisitor );
 208  
 
 209  1
                 MojoAnnotatedClass mojoAnnotatedClass = mojoClassVisitor.getMojoAnnotatedClass();
 210  
 
 211  1
                 if ( excludeMojo )
 212  
                 {
 213  0
                     mojoAnnotatedClass.setMojo( null );
 214  
                 }
 215  
 
 216  1
                 if ( isStoreClass( mojoAnnotatedClass ) != null )
 217  
                 {
 218  1
                     getLogger().debug( "found MojoAnnotatedClass:" + mojoAnnotatedClass.getClassName() + ":"
 219  
                                            + mojoAnnotatedClass );
 220  1
                     mojoAnnotatedClass.setArtifact( artifact );
 221  1
                     mojoAnnotatedClasses.put( mojoAnnotatedClass.getClassName(), mojoAnnotatedClass );
 222  
                 }
 223  
             }
 224  
             finally
 225  
             {
 226  1
                 IOUtil.close( is );
 227  1
             }
 228  
         }
 229  1
         return mojoAnnotatedClasses;
 230  
     }
 231  
 
 232  
     private MojoAnnotatedClass isStoreClass( MojoAnnotatedClass mojoAnnotatedClass )
 233  
     {
 234  
         // see MPLUGIN-206 we can have intermediate classes without annotations
 235  1
         if ( mojoAnnotatedClass == null )
 236  
         {
 237  0
             return null;
 238  
         }
 239  1
         return mojoAnnotatedClass;
 240  
         /**
 241  
          if ( !mojoAnnotatedClass.getComponents().isEmpty() || !mojoAnnotatedClass.getParameters().isEmpty()
 242  
          || mojoAnnotatedClass.getExecute() != null || mojoAnnotatedClass.getMojo() != null )
 243  
          {
 244  
          return mojoAnnotatedClass;
 245  
          }
 246  
          return null;
 247  
          **/
 248  
     }
 249  
 
 250  
 
 251  
     protected void analyzeVisitors( MojoClassVisitor mojoClassVisitor )
 252  
         throws ExtractionException
 253  
     {
 254  
 
 255  
         try
 256  
         {
 257  1
             MojoAnnotationVisitor mojoAnnotationVisitor =
 258  
                 mojoClassVisitor.getAnnotationVisitorMap().get( Mojo.class.getName() );
 259  1
             if ( mojoAnnotationVisitor != null )
 260  
             {
 261  1
                 MojoAnnotationContent mojoAnnotationContent = new MojoAnnotationContent();
 262  1
                 for ( Map.Entry<String, Object> entry : mojoAnnotationVisitor.getAnnotationValues().entrySet() )
 263  
                 {
 264  3
                     reflector.invoke( mojoAnnotationContent, entry.getKey(), new Object[]{ entry.getValue() } );
 265  
                 }
 266  1
                 mojoClassVisitor.getMojoAnnotatedClass().setMojo( mojoAnnotationContent );
 267  
             }
 268  
 
 269  1
             mojoAnnotationVisitor = mojoClassVisitor.getAnnotationVisitorMap().get( Execute.class.getName() );
 270  1
             if ( mojoAnnotationVisitor != null )
 271  
             {
 272  1
                 ExecuteAnnotationContent executeAnnotationContent = new ExecuteAnnotationContent();
 273  
 
 274  1
                 for ( Map.Entry<String, Object> entry : mojoAnnotationVisitor.getAnnotationValues().entrySet() )
 275  
                 {
 276  3
                     reflector.invoke( executeAnnotationContent, entry.getKey(), new Object[]{ entry.getValue() } );
 277  
                 }
 278  1
                 mojoClassVisitor.getMojoAnnotatedClass().setExecute( executeAnnotationContent );
 279  
             }
 280  
 
 281  1
             List<MojoFieldVisitor> mojoFieldVisitors =
 282  
                 mojoClassVisitor.findFieldWithAnnotationClass( Parameter.class.getName() );
 283  
 
 284  1
             for ( MojoFieldVisitor mojoFieldVisitor : mojoFieldVisitors )
 285  
             {
 286  2
                 ParameterAnnotationContent parameterAnnotationContent =
 287  
                     new ParameterAnnotationContent( mojoFieldVisitor.getFieldName(), mojoFieldVisitor.getClassName() );
 288  2
                 if ( mojoFieldVisitor.getMojoAnnotationVisitor() != null )
 289  
                 {
 290  2
                     for ( Map.Entry<String, Object> entry : mojoFieldVisitor.getMojoAnnotationVisitor().getAnnotationValues().entrySet() )
 291  
                     {
 292  5
                         reflector.invoke( parameterAnnotationContent, entry.getKey(),
 293  
                                           new Object[]{ entry.getValue() } );
 294  
                     }
 295  
 
 296  
                 }
 297  2
                 mojoClassVisitor.getMojoAnnotatedClass().getParameters().put( parameterAnnotationContent.getFieldName(),
 298  
                                                                               parameterAnnotationContent );
 299  2
             }
 300  
 
 301  1
             mojoFieldVisitors = mojoClassVisitor.findFieldWithAnnotationClass( Component.class.getName() );
 302  
 
 303  1
             for ( MojoFieldVisitor mojoFieldVisitor : mojoFieldVisitors )
 304  
             {
 305  2
                 ComponentAnnotationContent componentAnnotationContent =
 306  
                     new ComponentAnnotationContent( mojoFieldVisitor.getFieldName() );
 307  
 
 308  2
                 if ( mojoFieldVisitor.getMojoAnnotationVisitor() != null )
 309  
                 {
 310  2
                     for ( Map.Entry<String, Object> entry : mojoFieldVisitor.getMojoAnnotationVisitor().getAnnotationValues().entrySet() )
 311  
                     {
 312  2
                         String methodName = entry.getKey();
 313  2
                         if ( StringUtils.equals( "role", methodName ) )
 314  
                         {
 315  1
                             Type type = (Type) entry.getValue();
 316  1
                             componentAnnotationContent.setRoleClassName( type.getClassName() );
 317  1
                         }
 318  
                         else
 319  
                         {
 320  1
                             reflector.invoke( componentAnnotationContent, entry.getKey(),
 321  
                                               new Object[]{ entry.getValue() } );
 322  
                         }
 323  2
                     }
 324  2
                     if ( StringUtils.isEmpty( componentAnnotationContent.getRoleClassName() ) )
 325  
                     {
 326  1
                         componentAnnotationContent.setRoleClassName( mojoFieldVisitor.getClassName() );
 327  
                     }
 328  
                 }
 329  2
                 mojoClassVisitor.getMojoAnnotatedClass().getComponents().put( componentAnnotationContent.getFieldName(),
 330  
                                                                               componentAnnotationContent );
 331  2
             }
 332  
 
 333  
         }
 334  0
         catch ( Exception e )
 335  
         {
 336  0
             throw new ExtractionException( e.getMessage(), e );
 337  1
         }
 338  1
     }
 339  
 }