1 package org.apache.maven.plugin.javadoc.resolver;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import static org.codehaus.plexus.util.IOUtil.close;
23
24 import org.apache.maven.artifact.Artifact;
25 import org.apache.maven.artifact.DefaultArtifact;
26 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
27 import org.apache.maven.artifact.repository.ArtifactRepository;
28 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
29 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
30 import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
31 import org.apache.maven.artifact.resolver.ArtifactResolver;
32 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
33 import org.apache.maven.plugin.javadoc.AbstractJavadocMojo;
34 import org.apache.maven.plugin.javadoc.JavadocUtil;
35 import org.apache.maven.plugin.javadoc.ResourcesBundleMojo;
36 import org.apache.maven.plugin.javadoc.options.JavadocOptions;
37 import org.apache.maven.plugin.javadoc.options.io.xpp3.JavadocOptionsXpp3Reader;
38 import org.apache.maven.project.MavenProject;
39 import org.codehaus.plexus.archiver.ArchiverException;
40 import org.codehaus.plexus.archiver.UnArchiver;
41 import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
42 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
43
44 import java.io.File;
45 import java.io.FileInputStream;
46 import java.io.IOException;
47 import java.util.ArrayList;
48 import java.util.Arrays;
49 import java.util.Collection;
50 import java.util.HashMap;
51 import java.util.LinkedHashSet;
52 import java.util.List;
53 import java.util.Map;
54 import java.util.Set;
55
56
57
58
59 public final class ResourceResolver
60 {
61
62
63
64
65 public static final String SOURCES_CLASSIFIER = "sources";
66
67
68
69
70 public static final String TEST_SOURCES_CLASSIFIER = "test-sources";
71
72 private static final List<String> SOURCE_VALID_CLASSIFIERS = Arrays.asList( SOURCES_CLASSIFIER,
73 TEST_SOURCES_CLASSIFIER );
74
75 private static final List<String> RESOURCE_VALID_CLASSIFIERS =
76 Arrays.asList( AbstractJavadocMojo.JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER,
77 AbstractJavadocMojo.TEST_JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER );
78
79 private ResourceResolver()
80 {
81 }
82
83
84
85
86
87
88 @SuppressWarnings( "unchecked" )
89 public static List<JavadocBundle> resolveDependencyJavadocBundles( final SourceResolverConfig config )
90 throws IOException
91 {
92 final List<JavadocBundle> bundles = new ArrayList<JavadocBundle>();
93
94 final Map<String, MavenProject> projectMap = new HashMap<String, MavenProject>();
95 if ( config.reactorProjects() != null )
96 {
97 for ( final MavenProject p : config.reactorProjects() )
98 {
99 projectMap.put( key( p.getGroupId(), p.getArtifactId() ), p );
100 }
101 }
102
103 final List<Artifact> artifacts = config.project().getTestArtifacts();
104
105 final List<Artifact> forResourceResolution = new ArrayList<Artifact>( artifacts.size() );
106 for ( final Artifact artifact : artifacts )
107 {
108 final String key = key( artifact.getGroupId(), artifact.getArtifactId() );
109 final MavenProject p = projectMap.get( key );
110 if ( p != null )
111 {
112 bundles.addAll( resolveBundleFromProject( config, p, artifact ) );
113 }
114 else
115 {
116 forResourceResolution.add( artifact );
117 }
118 }
119
120 bundles.addAll( resolveBundlesFromArtifacts( config, forResourceResolution ) );
121
122 return bundles;
123 }
124
125
126
127
128
129
130
131 @SuppressWarnings( "unchecked" )
132 public static List<String> resolveDependencySourcePaths( final SourceResolverConfig config )
133 throws ArtifactResolutionException, ArtifactNotFoundException
134 {
135 final List<String> dirs = new ArrayList<String>();
136
137 final Map<String, MavenProject> projectMap = new HashMap<String, MavenProject>();
138 if ( config.reactorProjects() != null )
139 {
140 for ( final MavenProject p : config.reactorProjects() )
141 {
142 projectMap.put( key( p.getGroupId(), p.getArtifactId() ), p );
143 }
144 }
145
146 final List<Artifact> artifacts = config.project().getTestArtifacts();
147
148 final List<Artifact> forResourceResolution = new ArrayList<Artifact>( artifacts.size() );
149 for ( final Artifact artifact : artifacts )
150 {
151 final String key = key( artifact.getGroupId(), artifact.getArtifactId() );
152 final MavenProject p = projectMap.get( key );
153 if ( p != null )
154 {
155 dirs.addAll( resolveFromProject( config, p, artifact ) );
156 }
157 else
158 {
159 forResourceResolution.add( artifact );
160 }
161 }
162
163 dirs.addAll( resolveFromArtifacts( config, forResourceResolution ) );
164
165 return dirs;
166 }
167
168 private static List<JavadocBundle> resolveBundleFromProject( SourceResolverConfig config, MavenProject project,
169 Artifact artifact ) throws IOException
170 {
171 List<JavadocBundle> bundles = new ArrayList<JavadocBundle>();
172
173 List<String> classifiers = new ArrayList<String>();
174 if ( config.includeCompileSources() )
175 {
176 classifiers.add( AbstractJavadocMojo.JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER );
177 }
178
179 if ( config.includeTestSources() )
180 {
181 classifiers.add( AbstractJavadocMojo.TEST_JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER );
182 }
183
184 for ( String classifier : classifiers )
185 {
186 File optionsFile =
187 new File( project.getBuild().getDirectory(), "javadoc-bundle-options/javadoc-options-" + classifier
188 + ".xml" );
189 if ( !optionsFile.exists() )
190 {
191 continue;
192 }
193
194 FileInputStream stream = null;
195 try
196 {
197 stream = new FileInputStream( optionsFile );
198 JavadocOptions options = new JavadocOptionsXpp3Reader().read( stream );
199 stream.close();
200 stream = null;
201 bundles.add( new JavadocBundle( options, new File( project.getBasedir(),
202 options.getJavadocResourcesDirectory() ) ) );
203 }
204 catch ( XmlPullParserException e )
205 {
206 IOException error =
207 new IOException( "Failed to read javadoc options from: " + optionsFile + "\nReason: "
208 + e.getMessage() );
209 error.initCause( e );
210
211 throw error;
212 }
213 finally
214 {
215 close( stream );
216 }
217 }
218
219 return bundles;
220 }
221
222 private static List<JavadocBundle> resolveBundlesFromArtifacts( final SourceResolverConfig config,
223 final List<Artifact> artifacts )
224 throws IOException
225 {
226 final List<Artifact> toResolve = new ArrayList<Artifact>( artifacts.size() );
227
228 for ( final Artifact artifact : artifacts )
229 {
230 if ( config.filter() != null && !config.filter().include( artifact ) )
231 {
232 continue;
233 }
234
235 if ( config.includeCompileSources() )
236 {
237 toResolve.add( createResourceArtifact( artifact,
238 AbstractJavadocMojo.JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER,
239 config ) );
240 }
241
242 if ( config.includeTestSources() )
243 {
244 toResolve.add( createResourceArtifact( artifact,
245 AbstractJavadocMojo.TEST_JAVADOC_RESOURCES_ATTACHMENT_CLASSIFIER,
246 config ) );
247 }
248 }
249
250 List<String> dirs = null;
251 try
252 {
253 dirs = resolveAndUnpack( toResolve, config, RESOURCE_VALID_CLASSIFIERS, false );
254 }
255 catch ( ArtifactResolutionException e )
256 {
257 if ( config.log().isDebugEnabled() )
258 {
259 config.log().debug( e.getMessage(), e );
260 }
261 }
262 catch ( ArtifactNotFoundException e )
263 {
264 if ( config.log().isDebugEnabled() )
265 {
266 config.log().debug( e.getMessage(), e );
267 }
268 }
269
270 List<JavadocBundle> result = new ArrayList<JavadocBundle>();
271
272 if ( dirs != null )
273 {
274 for ( String d : dirs )
275 {
276 File dir = new File( d );
277 File resources = new File( dir, ResourcesBundleMojo.RESOURCES_DIR_PATH );
278 JavadocOptions options = null;
279
280 File javadocOptions = new File( dir, ResourcesBundleMojo.BUNDLE_OPTIONS_PATH );
281 if ( javadocOptions.exists() )
282 {
283 FileInputStream reader = null;
284 try
285 {
286 reader = new FileInputStream( javadocOptions );
287 options = new JavadocOptionsXpp3Reader().read( reader );
288 }
289 catch ( XmlPullParserException e )
290 {
291 IOException error = new IOException( "Failed to parse javadoc options: " + e.getMessage() );
292 error.initCause( e );
293
294 throw error;
295 }
296 finally
297 {
298 close( reader );
299 }
300 }
301
302 result.add( new JavadocBundle( options, resources ) );
303 }
304 }
305
306 return result;
307 }
308
309 private static List<String> resolveFromArtifacts( final SourceResolverConfig config,
310 final List<Artifact> artifacts )
311 throws ArtifactResolutionException, ArtifactNotFoundException
312 {
313 final List<Artifact> toResolve = new ArrayList<Artifact>( artifacts.size() );
314
315 for ( final Artifact artifact : artifacts )
316 {
317 if ( config.filter() != null && !config.filter().include( artifact ) )
318 {
319 continue;
320 }
321
322 if ( config.includeCompileSources() )
323 {
324 toResolve.add( createResourceArtifact( artifact, SOURCES_CLASSIFIER, config ) );
325 }
326
327 if ( config.includeTestSources() )
328 {
329 toResolve.add( createResourceArtifact( artifact, TEST_SOURCES_CLASSIFIER, config ) );
330 }
331 }
332
333 return resolveAndUnpack( toResolve, config, SOURCE_VALID_CLASSIFIERS, true );
334 }
335
336 private static Artifact createResourceArtifact( final Artifact artifact, final String classifier,
337 final SourceResolverConfig config )
338 {
339 final DefaultArtifact a =
340 (DefaultArtifact) config.artifactFactory().createArtifactWithClassifier( artifact.getGroupId(),
341 artifact.getArtifactId(),
342 artifact.getVersion(), "jar",
343 classifier );
344
345 a.setRepository( artifact.getRepository() );
346
347 return a;
348 }
349
350 @SuppressWarnings( "unchecked" )
351 private static List<String> resolveAndUnpack( final List<Artifact> artifacts, final SourceResolverConfig config,
352 final List<String> validClassifiers, final boolean propagateErrors )
353 throws ArtifactResolutionException, ArtifactNotFoundException
354 {
355
356
357
358 final Set<Artifact> artifactSet = new LinkedHashSet<Artifact>( artifacts );
359 final Artifact pomArtifact = config.project().getArtifact();
360 final ArtifactRepository localRepo = config.localRepository();
361 final List<ArtifactRepository> remoteRepos = config.project().getRemoteArtifactRepositories();
362 final ArtifactMetadataSource metadataSource = config.artifactMetadataSource();
363
364 final ArtifactFilter filter = config.filter();
365 ArtifactFilter resolutionFilter = null;
366 if ( filter != null )
367 {
368
369
370
371
372 resolutionFilter = new ProjectArtifactFilter( pomArtifact, filter );
373 }
374
375 final ArtifactResolver resolver = config.artifactResolver();
376
377 @SuppressWarnings( "rawtypes" )
378 Map managed = config.project().getManagedVersionMap();
379
380 final ArtifactResolutionResult resolutionResult = resolver.resolveTransitively(
381 artifactSet, pomArtifact, managed, localRepo, remoteRepos, metadataSource, resolutionFilter );
382
383 final List<String> result = new ArrayList<String>( artifacts.size() );
384 for ( final Artifact a : (Collection<Artifact>) resolutionResult.getArtifacts() )
385 {
386 if ( !validClassifiers.contains( a.getClassifier() ) || ( filter != null && !filter.include( a ) ) )
387 {
388 continue;
389 }
390
391 final File d =
392 new File( config.outputBasedir(), a.getArtifactId() + "-" + a.getVersion() + "-" + a.getClassifier() );
393
394 if ( !d.exists() )
395 {
396 d.mkdirs();
397 }
398
399 try
400 {
401 final UnArchiver unArchiver = config.archiverManager().getUnArchiver( a.getType() );
402
403 unArchiver.setDestDirectory( d );
404 unArchiver.setSourceFile( a.getFile() );
405
406 unArchiver.extract();
407
408 result.add( d.getAbsolutePath() );
409 }
410 catch ( final NoSuchArchiverException e )
411 {
412 if ( propagateErrors )
413 {
414 throw new ArtifactResolutionException( "Failed to retrieve valid un-archiver component: "
415 + a.getType(), a, e );
416 }
417 }
418 catch ( final ArchiverException e )
419 {
420 if ( propagateErrors )
421 {
422 throw new ArtifactResolutionException( "Failed to unpack: " + a.getId(), a, e );
423 }
424 }
425 }
426
427 return result;
428 }
429
430 @SuppressWarnings( "unchecked" )
431 private static List<String> resolveFromProject( final SourceResolverConfig config,
432 final MavenProject reactorProject, final Artifact artifact )
433 {
434 final List<String> dirs = new ArrayList<String>();
435
436 if ( config.filter() == null || config.filter().include( artifact ) )
437 {
438 if ( config.includeCompileSources() )
439 {
440 final List<String> srcRoots = reactorProject.getCompileSourceRoots();
441 for ( final String root : srcRoots )
442 {
443 dirs.add( root );
444 }
445 }
446
447 if ( config.includeTestSources() )
448 {
449 final List<String> srcRoots = reactorProject.getTestCompileSourceRoots();
450 for ( final String root : srcRoots )
451 {
452 dirs.add( root );
453 }
454 }
455 }
456
457 return JavadocUtil.pruneDirs( reactorProject, dirs );
458 }
459
460 private static String key( final String gid, final String aid )
461 {
462 return gid + ":" + aid;
463 }
464
465 }