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