]> source.dussan.org Git - archiva.git/blob
f748cb36db90af53f500f947a88701321dc0cd07
[archiva.git] /
1 package org.apache.archiva.consumers.dependencytree;
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 java.io.File;
23 import java.io.FileWriter;
24 import java.io.IOException;
25 import java.lang.reflect.Field;
26 import java.net.MalformedURLException;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.List;
30
31 import org.apache.commons.io.IOUtils;
32 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
33 import org.apache.maven.archiva.consumers.AbstractMonitoredConsumer;
34 import org.apache.maven.archiva.consumers.ConsumerException;
35 import org.apache.maven.archiva.consumers.KnownRepositoryContentConsumer;
36 import org.apache.maven.artifact.Artifact;
37 import org.apache.maven.artifact.factory.ArtifactFactory;
38 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
39 import org.apache.maven.artifact.repository.ArtifactRepository;
40 import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
41 import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
42 import org.apache.maven.artifact.resolver.ArtifactCollector;
43 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
44 import org.apache.maven.project.DefaultMavenProjectBuilder;
45 import org.apache.maven.project.MavenProject;
46 import org.apache.maven.project.MavenProjectBuilder;
47 import org.apache.maven.project.ProjectBuildingException;
48 import org.apache.maven.shared.dependency.tree.DependencyNode;
49 import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder;
50 import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException;
51 import org.apache.maven.shared.dependency.tree.filter.AncestorOrSelfDependencyNodeFilter;
52 import org.apache.maven.shared.dependency.tree.filter.DependencyNodeFilter;
53 import org.apache.maven.shared.dependency.tree.filter.StateDependencyNodeFilter;
54 import org.apache.maven.shared.dependency.tree.traversal.BuildingDependencyNodeVisitor;
55 import org.apache.maven.shared.dependency.tree.traversal.CollectingDependencyNodeVisitor;
56 import org.apache.maven.shared.dependency.tree.traversal.DependencyNodeVisitor;
57 import org.apache.maven.shared.dependency.tree.traversal.FilteringDependencyNodeVisitor;
58 import org.dom4j.Document;
59 import org.dom4j.DocumentHelper;
60 import org.dom4j.Element;
61 import org.dom4j.io.OutputFormat;
62 import org.dom4j.io.XMLWriter;
63
64 /**
65  * @plexus.component role="org.apache.maven.archiva.consumers.KnownRepositoryContentConsumer"
66  *                   role-hint="dependency-tree-generator" instantiation-strategy="per-lookup"
67  */
68 public class DependencyTreeGeneratorConsumer
69     extends AbstractMonitoredConsumer
70     implements KnownRepositoryContentConsumer
71 {
72     /** @plexus.configuration */
73     private File generatedRepositoryLocation;
74
75     /** @plexus.configuration */
76     private File localRepository;
77
78     /** @plexus.requirement */
79     private DependencyTreeBuilder dependencyTreeBuilder;
80
81     /** @plexus.requirement */
82     private ArtifactFactory artifactFactory;
83
84     /** @plexus.requirement role-hint="maven" */
85     private ArtifactMetadataSource artifactMetadataSource;
86
87     /** @plexus.requirement */
88     private ArtifactCollector artifactCollector;
89
90     /** @plexus.requirement */
91     private MavenProjectBuilder projectBuilder;
92
93     /** @plexus.requirement */
94     private ArtifactRepositoryFactory artifactRepositoryFactory;
95
96     private String repositoryLocation;
97
98     private final DefaultRepositoryLayout layout = new DefaultRepositoryLayout();
99
100     private ArtifactRepository localArtifactRepository;
101
102     private Field rawProjectCacheField;
103
104     private Field processedProjectCacheField;
105
106     public String getDescription()
107     {
108         return "Generate dependency tree metadata for tracking changes across algorithms";
109     }
110
111     public String getId()
112     {
113         return "dependency-tree-generator";
114     }
115
116     public boolean isPermanent()
117     {
118         return false;
119     }
120
121     public void setGeneratedRepositoryLocation( File generatedRepositoryLocation )
122     {
123         this.generatedRepositoryLocation = generatedRepositoryLocation;
124     }
125
126     public void beginScan( ManagedRepositoryConfiguration repository )
127         throws ConsumerException
128     {
129         repositoryLocation = repository.getLocation();
130
131         if ( generatedRepositoryLocation == null )
132         {
133             generatedRepositoryLocation = new File( repositoryLocation );
134         }
135
136         if ( localRepository == null )
137         {
138             // This is a bit crappy, it would be better to operate entirely within
139             // the base repository, but would need to adjust maven-artifact
140             localRepository = new File( System.getProperty( "user.home" ), ".m2/repository" );
141             try
142             {
143                 localArtifactRepository =
144                     artifactRepositoryFactory.createArtifactRepository( "local",
145                                                                         localRepository.toURL().toExternalForm(),
146                                                                         layout, null, null );
147             }
148             catch ( MalformedURLException e )
149             {
150                 throw new ConsumerException( e.getMessage(), e );
151             }
152         }
153     }
154
155     public void completeScan()
156     {
157     }
158
159     public List getExcludes()
160     {
161         return null;
162     }
163
164     public List getIncludes()
165     {
166         return Collections.singletonList( "**/*.pom" );
167     }
168
169     public void processFile( String path )
170         throws ConsumerException
171     {
172         MavenProject project;
173         try
174         {
175             project = projectBuilder.build( new File( repositoryLocation, path ), localArtifactRepository, null, false );
176
177             // manually flush out the cache for memory concerns and more accurate building
178             flushProjectCache( projectBuilder );
179         }
180         catch ( ProjectBuildingException e )
181         {
182             throw new ConsumerException( e.getMessage(), e );
183         }
184
185         DependencyNode rootNode;
186         try
187         {
188             // TODO: do this for different values of new ScopeArtifactFilter( scope )
189             ArtifactFilter artifactFilter = null;
190
191             rootNode =
192                 dependencyTreeBuilder.buildDependencyTree( project, localArtifactRepository, artifactFactory,
193                                                            artifactMetadataSource, artifactFilter, artifactCollector );
194         }
195         catch ( DependencyTreeBuilderException e )
196         {
197             throw new ConsumerException( e.getMessage(), e );
198         }
199
200         Document document = DocumentHelper.createDocument();
201         DependencyNodeVisitor visitor = new XmlSerializingDependencyNodeVisitor( document );
202
203         // TODO: remove the need for this when the serializer can calculate last nodes from visitor calls only
204         visitor = new BuildingDependencyNodeVisitor( visitor );
205
206         CollectingDependencyNodeVisitor collectingVisitor = new CollectingDependencyNodeVisitor();
207         DependencyNodeVisitor firstPassVisitor =
208             new FilteringDependencyNodeVisitor( collectingVisitor, StateDependencyNodeFilter.INCLUDED );
209         rootNode.accept( firstPassVisitor );
210
211         DependencyNodeFilter secondPassFilter = new AncestorOrSelfDependencyNodeFilter( collectingVisitor.getNodes() );
212         visitor = new FilteringDependencyNodeVisitor( visitor, secondPassFilter );
213
214         rootNode.accept( visitor );
215
216         FileWriter writer = null;
217         try
218         {
219             Artifact artifact =
220                 artifactFactory.createProjectArtifact( project.getGroupId(), project.getArtifactId(),
221                                                        project.getVersion() );
222
223             File generatedFile = new File( generatedRepositoryLocation, layout.pathOf( artifact ) + ".xml" );
224             generatedFile.getParentFile().mkdirs();
225             writer = new FileWriter( generatedFile );
226             OutputFormat format = OutputFormat.createPrettyPrint();
227             XMLWriter w = new XMLWriter( writer, format );
228             w.write( document );
229         }
230         catch ( IOException e )
231         {
232             throw new ConsumerException( e.getMessage(), e );
233         }
234         finally
235         {
236             IOUtils.closeQuietly( writer );
237         }
238     }
239
240     private void flushProjectCache( MavenProjectBuilder projectBuilder )
241     {
242         try
243         {
244             if ( rawProjectCacheField == null )
245             {
246                 rawProjectCacheField = DefaultMavenProjectBuilder.class.getDeclaredField( "rawProjectCache" );
247                 rawProjectCacheField.setAccessible( true );
248             }
249
250             if ( processedProjectCacheField == null )
251             {
252                 processedProjectCacheField =
253                     DefaultMavenProjectBuilder.class.getDeclaredField( "processedProjectCache" );
254                 processedProjectCacheField.setAccessible( true );
255             }
256
257             rawProjectCacheField.set( projectBuilder, new HashMap() );
258
259             processedProjectCacheField.set( projectBuilder, new HashMap() );
260         }
261         catch ( Exception e )
262         {
263             throw new RuntimeException( e );
264         }
265     }
266
267     private static class XmlSerializingDependencyNodeVisitor
268         implements DependencyNodeVisitor
269     {
270         private Element xmlNode;
271
272         public XmlSerializingDependencyNodeVisitor( Document document )
273         {
274             xmlNode = document.addElement( "tree" );
275         }
276
277         // DependencyNodeVisitor methods ------------------------------------------
278
279         /*
280          * @see org.apache.maven.shared.dependency.tree.traversal.DependencyNodeVisitor#visit(org.apache.maven.shared.dependency.tree.DependencyNode)
281          */
282         public boolean visit( DependencyNode node )
283         {
284             Element dependency = xmlNode.addElement( "dependency" );
285
286             Artifact artifact = node.getArtifact();
287             dependency.addElement( "groupId" ).setText( artifact.getGroupId() );
288             dependency.addElement( "artifactId" ).setText( artifact.getArtifactId() );
289             dependency.addElement( "type" ).setText( artifact.getType() );
290             dependency.addElement( "version" ).setText( artifact.getVersion() );
291             if ( artifact.getScope() != null )
292             {
293                 dependency.addElement( "scope" ).setText( artifact.getScope() );
294             }
295
296             xmlNode = dependency.addElement( "dependencies" );
297
298             return true;
299         }
300
301         /*
302          * @see org.apache.maven.shared.dependency.tree.traversal.DependencyNodeVisitor#endVisit(org.apache.maven.shared.dependency.tree.DependencyNode)
303          */
304         public boolean endVisit( DependencyNode node )
305         {
306             Element e = xmlNode.getParent();
307
308             if ( !xmlNode.hasContent() )
309             {
310                 e.remove( xmlNode );
311             }
312
313             xmlNode = e.getParent();
314
315             return true;
316         }
317     }
318 }