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