1 package org.apache.maven.tools.plugin.annotations.scanner;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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.codehaus.plexus.util.reflection.ReflectorException;
41 import org.objectweb.asm.ClassReader;
42 import org.objectweb.asm.Type;
43
44 import java.io.BufferedInputStream;
45 import java.io.File;
46 import java.io.FileInputStream;
47 import java.io.IOException;
48 import java.io.InputStream;
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
57
58
59 @org.codehaus.plexus.component.annotations.Component( role = MojoAnnotationsScanner.class )
60 public class DefaultMojoAnnotationsScanner
61 extends AbstractLogEnabled
62 implements MojoAnnotationsScanner
63 {
64 private Reflector reflector = new Reflector();
65
66 public Map<String, MojoAnnotatedClass> scan( MojoAnnotationsScannerRequest request )
67 throws ExtractionException
68 {
69 Map<String, MojoAnnotatedClass> mojoAnnotatedClasses = new HashMap<String, MojoAnnotatedClass>();
70
71 try
72 {
73 for ( Artifact dependency : request.getDependencies() )
74 {
75 scan( mojoAnnotatedClasses, dependency.getFile(), request.getIncludePatterns(), dependency, true );
76 }
77
78 for ( File classDirectory : request.getClassesDirectories() )
79 {
80 scan( mojoAnnotatedClasses, classDirectory, request.getIncludePatterns(),
81 request.getProject().getArtifact(), false );
82 }
83 }
84 catch ( IOException e )
85 {
86 throw new ExtractionException( e.getMessage(), e );
87 }
88
89 return mojoAnnotatedClasses;
90 }
91
92 protected void scan( Map<String, MojoAnnotatedClass> mojoAnnotatedClasses, File source,
93 List<String> includePatterns, Artifact artifact, boolean excludeMojo )
94 throws IOException, ExtractionException
95 {
96 if ( source == null || ! source.exists() )
97 {
98 return;
99 }
100
101 Map<String, MojoAnnotatedClass> scanResult;
102 if ( source.isDirectory() )
103 {
104 scanResult = scanDirectory( source, includePatterns, artifact, excludeMojo );
105 }
106 else
107 {
108 scanResult = scanArchive( source, artifact, excludeMojo );
109 }
110
111 mojoAnnotatedClasses.putAll( scanResult );
112 }
113
114
115
116
117
118
119
120
121
122 protected Map<String, MojoAnnotatedClass> scanArchive( File archiveFile, Artifact artifact, boolean excludeMojo )
123 throws IOException, ExtractionException
124 {
125 Map<String, MojoAnnotatedClass> mojoAnnotatedClasses = new HashMap<String, MojoAnnotatedClass>();
126
127 ZipInputStream archiveStream = new ZipInputStream( new FileInputStream( archiveFile ) );
128
129 try
130 {
131 for ( ZipEntry zipEntry = archiveStream.getNextEntry(); zipEntry != null;
132 zipEntry = archiveStream.getNextEntry() )
133 {
134 if ( !zipEntry.getName().endsWith( ".class" ) )
135 {
136 continue;
137 }
138
139 analyzeClassStream( mojoAnnotatedClasses, archiveStream, artifact, excludeMojo );
140 }
141 }
142 finally
143 {
144 IOUtil.close( archiveStream );
145 }
146
147 return mojoAnnotatedClasses;
148 }
149
150
151
152
153
154
155
156
157
158
159 protected Map<String, MojoAnnotatedClass> scanDirectory( File classDirectory, List<String> includePatterns,
160 Artifact artifact, boolean excludeMojo )
161 throws IOException, ExtractionException
162 {
163 Map<String, MojoAnnotatedClass> mojoAnnotatedClasses = new HashMap<String, MojoAnnotatedClass>();
164
165 DirectoryScanner scanner = new DirectoryScanner();
166 scanner.setBasedir( classDirectory );
167 scanner.addDefaultExcludes();
168 if ( includePatterns != null )
169 {
170 scanner.setIncludes( includePatterns.toArray( new String[includePatterns.size()] ) );
171 }
172 scanner.scan();
173 String[] classFiles = scanner.getIncludedFiles();
174
175 for ( String classFile : classFiles )
176 {
177 if ( !classFile.endsWith( ".class" ) )
178 {
179 continue;
180 }
181
182 InputStream is = new BufferedInputStream( new FileInputStream( new File( classDirectory, classFile ) ) );
183 try
184 {
185 analyzeClassStream( mojoAnnotatedClasses, is, artifact, excludeMojo );
186 }
187 finally
188 {
189 IOUtil.close( is );
190 }
191 }
192 return mojoAnnotatedClasses;
193 }
194
195 private void analyzeClassStream( Map<String, MojoAnnotatedClass> mojoAnnotatedClasses, InputStream is,
196 Artifact artifact, boolean excludeMojo )
197 throws IOException, ExtractionException
198 {
199 MojoClassVisitor mojoClassVisitor = new MojoClassVisitor( getLogger() );
200
201 ClassReader rdr = new ClassReader( is );
202 rdr.accept( mojoClassVisitor, ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG );
203
204 analyzeVisitors( mojoClassVisitor );
205
206 MojoAnnotatedClass mojoAnnotatedClass = mojoClassVisitor.getMojoAnnotatedClass();
207
208 if ( excludeMojo )
209 {
210 mojoAnnotatedClass.setMojo( null );
211 }
212
213 if ( mojoAnnotatedClass != null )
214 {
215 if ( getLogger().isDebugEnabled() && mojoAnnotatedClass.hasAnnotations() )
216 {
217 getLogger().debug( "found MojoAnnotatedClass:" + mojoAnnotatedClass.getClassName() + ":"
218 + mojoAnnotatedClass );
219 }
220 mojoAnnotatedClass.setArtifact( artifact );
221 mojoAnnotatedClasses.put( mojoAnnotatedClass.getClassName(), mojoAnnotatedClass );
222 }
223 }
224
225 protected void populateAnnotationContent( Object content, MojoAnnotationVisitor mojoAnnotationVisitor )
226 throws ReflectorException
227 {
228 for ( Map.Entry<String, Object> entry : mojoAnnotationVisitor.getAnnotationValues().entrySet() )
229 {
230 reflector.invoke( content, entry.getKey(), new Object[] { entry.getValue() } );
231 }
232 }
233
234 protected void analyzeVisitors( MojoClassVisitor mojoClassVisitor )
235 throws ExtractionException
236 {
237 final MojoAnnotatedClass mojoAnnotatedClass = mojoClassVisitor.getMojoAnnotatedClass();
238
239 try
240 {
241
242 MojoAnnotationVisitor mojoAnnotationVisitor = mojoClassVisitor.getAnnotationVisitor( Mojo.class );
243 if ( mojoAnnotationVisitor != null )
244 {
245 MojoAnnotationContent mojoAnnotationContent = new MojoAnnotationContent();
246 populateAnnotationContent( mojoAnnotationContent, mojoAnnotationVisitor );
247 mojoAnnotatedClass.setMojo( mojoAnnotationContent );
248 }
249
250
251 mojoAnnotationVisitor = mojoClassVisitor.getAnnotationVisitor( Execute.class );
252 if ( mojoAnnotationVisitor != null )
253 {
254 ExecuteAnnotationContent executeAnnotationContent = new ExecuteAnnotationContent();
255 populateAnnotationContent( executeAnnotationContent, mojoAnnotationVisitor );
256 mojoAnnotatedClass.setExecute( executeAnnotationContent );
257 }
258
259
260 List<MojoFieldVisitor> mojoFieldVisitors = mojoClassVisitor.findFieldWithAnnotation( Parameter.class );
261 for ( MojoFieldVisitor mojoFieldVisitor : mojoFieldVisitors )
262 {
263 ParameterAnnotationContent parameterAnnotationContent =
264 new ParameterAnnotationContent( mojoFieldVisitor.getFieldName(), mojoFieldVisitor.getClassName() );
265 if ( mojoFieldVisitor.getMojoAnnotationVisitor() != null )
266 {
267 populateAnnotationContent( parameterAnnotationContent, mojoFieldVisitor.getMojoAnnotationVisitor() );
268 }
269
270 mojoAnnotatedClass.getParameters().put( parameterAnnotationContent.getFieldName(),
271 parameterAnnotationContent );
272 }
273
274
275 mojoFieldVisitors = mojoClassVisitor.findFieldWithAnnotation( Component.class );
276 for ( MojoFieldVisitor mojoFieldVisitor : mojoFieldVisitors )
277 {
278 ComponentAnnotationContent componentAnnotationContent =
279 new ComponentAnnotationContent( mojoFieldVisitor.getFieldName() );
280
281 if ( mojoFieldVisitor.getMojoAnnotationVisitor() != null )
282 {
283 for ( Map.Entry<String, Object> entry : mojoFieldVisitor.getMojoAnnotationVisitor().getAnnotationValues().entrySet() )
284 {
285 String methodName = entry.getKey();
286 if ( StringUtils.equals( "role", methodName ) )
287 {
288 Type type = (Type) entry.getValue();
289 componentAnnotationContent.setRoleClassName( type.getClassName() );
290 }
291 else
292 {
293 reflector.invoke( componentAnnotationContent, entry.getKey(),
294 new Object[]{ entry.getValue() } );
295 }
296 }
297
298 if ( StringUtils.isEmpty( componentAnnotationContent.getRoleClassName() ) )
299 {
300 componentAnnotationContent.setRoleClassName( mojoFieldVisitor.getClassName() );
301 }
302 }
303 mojoAnnotatedClass.getComponents().put( componentAnnotationContent.getFieldName(),
304 componentAnnotationContent );
305 }
306 }
307 catch ( ReflectorException e )
308 {
309 throw new ExtractionException( e.getMessage(), e );
310 }
311 }
312 }