Coverage Report - org.apache.maven.tools.plugin.annotations.scanner.DefaultMojoAnnotationsScanner
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultMojoAnnotationsScanner
68 %
72/105
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
             InputStream is = new BufferedInputStream( new FileInputStream( new File( classDirectory, classFile ) ) );
 196  
             try
 197  
             {
 198  
 
 199  1
                 if ( classFile.endsWith( ".class" ) )
 200  
                 {
 201  1
                     MojoClassVisitor mojoClassVisitor = new MojoClassVisitor( getLogger() );
 202  1
                     ClassReader rdr = new ClassReader( is );
 203  1
                     rdr.accept( mojoClassVisitor,
 204  
                                 ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG );
 205  1
                     analyzeVisitors( mojoClassVisitor );
 206  1
                     if ( excludeMojo )
 207  
                     {
 208  0
                         mojoClassVisitor.getMojoAnnotatedClass().setMojo( null );
 209  
                     }
 210  1
                     if ( isStoreClass( mojoClassVisitor.getMojoAnnotatedClass() ) != null )
 211  
                     {
 212  1
                         getLogger().debug(
 213  
                             "found MojoAnnotatedClass:" + mojoClassVisitor.getMojoAnnotatedClass().getClassName() + ":"
 214  
                                 + mojoClassVisitor.getMojoAnnotatedClass() );
 215  1
                         mojoClassVisitor.getMojoAnnotatedClass().setArtifact( artifact );
 216  1
                         mojoAnnotatedClasses.put( mojoClassVisitor.getMojoAnnotatedClass().getClassName(),
 217  
                                                   mojoClassVisitor.getMojoAnnotatedClass() );
 218  
                     }
 219  
 
 220  
                 }
 221  
             }
 222  
             finally
 223  
             {
 224  1
                 IOUtil.close( is );
 225  1
             }
 226  
 
 227  
         }
 228  1
         return mojoAnnotatedClasses;
 229  
     }
 230  
 
 231  
     private MojoAnnotatedClass isStoreClass( MojoAnnotatedClass mojoAnnotatedClass )
 232  
     {
 233  
         // see MPLUGIN-206 we can have intermediate classes without annotations
 234  1
         if ( mojoAnnotatedClass == null )
 235  
         {
 236  0
             return null;
 237  
         }
 238  1
         return mojoAnnotatedClass;
 239  
         /**
 240  
          if ( !mojoAnnotatedClass.getComponents().isEmpty() || !mojoAnnotatedClass.getParameters().isEmpty()
 241  
          || mojoAnnotatedClass.getExecute() != null || mojoAnnotatedClass.getMojo() != null )
 242  
          {
 243  
          return mojoAnnotatedClass;
 244  
          }
 245  
          return null;
 246  
          **/
 247  
     }
 248  
 
 249  
 
 250  
     protected void analyzeVisitors( MojoClassVisitor mojoClassVisitor )
 251  
         throws ExtractionException
 252  
     {
 253  
 
 254  
         try
 255  
         {
 256  1
             MojoAnnotationVisitor mojoAnnotationVisitor =
 257  
                 mojoClassVisitor.getAnnotationVisitorMap().get( Mojo.class.getName() );
 258  1
             if ( mojoAnnotationVisitor != null )
 259  
             {
 260  1
                 MojoAnnotationContent mojoAnnotationContent = new MojoAnnotationContent();
 261  1
                 for ( Map.Entry<String, Object> entry : mojoAnnotationVisitor.getAnnotationValues().entrySet() )
 262  
                 {
 263  3
                     reflector.invoke( mojoAnnotationContent, entry.getKey(), new Object[]{ entry.getValue() } );
 264  
                 }
 265  1
                 mojoClassVisitor.getMojoAnnotatedClass().setMojo( mojoAnnotationContent );
 266  
             }
 267  
 
 268  1
             mojoAnnotationVisitor = mojoClassVisitor.getAnnotationVisitorMap().get( Execute.class.getName() );
 269  1
             if ( mojoAnnotationVisitor != null )
 270  
             {
 271  1
                 ExecuteAnnotationContent executeAnnotationContent = new ExecuteAnnotationContent();
 272  
 
 273  1
                 for ( Map.Entry<String, Object> entry : mojoAnnotationVisitor.getAnnotationValues().entrySet() )
 274  
                 {
 275  3
                     reflector.invoke( executeAnnotationContent, entry.getKey(), new Object[]{ entry.getValue() } );
 276  
                 }
 277  1
                 mojoClassVisitor.getMojoAnnotatedClass().setExecute( executeAnnotationContent );
 278  
             }
 279  
 
 280  1
             List<MojoFieldVisitor> mojoFieldVisitors =
 281  
                 mojoClassVisitor.findFieldWithAnnotationClass( Parameter.class.getName() );
 282  
 
 283  1
             for ( MojoFieldVisitor mojoFieldVisitor : mojoFieldVisitors )
 284  
             {
 285  2
                 ParameterAnnotationContent parameterAnnotationContent =
 286  
                     new ParameterAnnotationContent( mojoFieldVisitor.getFieldName(), mojoFieldVisitor.getClassName() );
 287  2
                 if ( mojoFieldVisitor.getMojoAnnotationVisitor() != null )
 288  
                 {
 289  2
                     for ( Map.Entry<String, Object> entry : mojoFieldVisitor.getMojoAnnotationVisitor().getAnnotationValues().entrySet() )
 290  
                     {
 291  5
                         reflector.invoke( parameterAnnotationContent, entry.getKey(),
 292  
                                           new Object[]{ entry.getValue() } );
 293  
                     }
 294  
 
 295  
                 }
 296  2
                 mojoClassVisitor.getMojoAnnotatedClass().getParameters().put( parameterAnnotationContent.getFieldName(),
 297  
                                                                               parameterAnnotationContent );
 298  2
             }
 299  
 
 300  1
             mojoFieldVisitors = mojoClassVisitor.findFieldWithAnnotationClass( Component.class.getName() );
 301  
 
 302  1
             for ( MojoFieldVisitor mojoFieldVisitor : mojoFieldVisitors )
 303  
             {
 304  2
                 ComponentAnnotationContent componentAnnotationContent =
 305  
                     new ComponentAnnotationContent( mojoFieldVisitor.getFieldName() );
 306  
 
 307  2
                 if ( mojoFieldVisitor.getMojoAnnotationVisitor() != null )
 308  
                 {
 309  2
                     for ( Map.Entry<String, Object> entry : mojoFieldVisitor.getMojoAnnotationVisitor().getAnnotationValues().entrySet() )
 310  
                     {
 311  2
                         String methodName = entry.getKey();
 312  2
                         if ( StringUtils.equals( "role", methodName ) )
 313  
                         {
 314  1
                             Type type = (Type) entry.getValue();
 315  1
                             componentAnnotationContent.setRoleClassName( type.getClassName() );
 316  1
                         }
 317  
                         else
 318  
                         {
 319  1
                             reflector.invoke( componentAnnotationContent, entry.getKey(),
 320  
                                               new Object[]{ entry.getValue() } );
 321  
                         }
 322  2
                     }
 323  2
                     if ( StringUtils.isEmpty( componentAnnotationContent.getRoleClassName() ) )
 324  
                     {
 325  1
                         componentAnnotationContent.setRoleClassName( mojoFieldVisitor.getClassName() );
 326  
                     }
 327  
                 }
 328  2
                 mojoClassVisitor.getMojoAnnotatedClass().getComponents().put( componentAnnotationContent.getFieldName(),
 329  
                                                                               componentAnnotationContent );
 330  2
             }
 331  
 
 332  
         }
 333  0
         catch ( Exception e )
 334  
         {
 335  0
             throw new ExtractionException( e.getMessage(), e );
 336  1
         }
 337  1
     }
 338  
 }