You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by jd...@apache.org on 2011/08/25 22:03:57 UTC

svn commit: r1161723 [2/3] - in /maven/sandbox/trunk/mae: ./ mae-boms/mae-library-bom/ mae-booter/ mae-booter/src/main/java/org/apache/maven/mae/boot/embed/ mae-booter/src/test/java/org/apache/maven/mae/internal/container/ mae-booter/src/test/java/org/...

Added: maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/DependencyGraphResolver.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/DependencyGraphResolver.java?rev=1161723&view=auto
==============================================================================
--- maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/DependencyGraphResolver.java (added)
+++ maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/DependencyGraphResolver.java Thu Aug 25 20:03:54 2011
@@ -0,0 +1,763 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.maven.mae.depgraph.impl;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.log4j.Logger;
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.mae.depgraph.DepGraphNode;
+import org.apache.maven.mae.depgraph.DepGraphRootNode;
+import org.apache.maven.mae.depgraph.DependencyGraph;
+import org.apache.maven.mae.project.session.ProjectToolsSession;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.DependencyManagement;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.sonatype.aether.RepositorySystem;
+import org.sonatype.aether.RepositorySystemSession;
+import org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.artifact.ArtifactTypeRegistry;
+import org.sonatype.aether.collection.CollectRequest;
+import org.sonatype.aether.collection.CollectResult;
+import org.sonatype.aether.collection.DependencyCollectionException;
+import org.sonatype.aether.graph.DependencyFilter;
+import org.sonatype.aether.graph.DependencyNode;
+import org.sonatype.aether.graph.DependencyVisitor;
+import org.sonatype.aether.graph.Exclusion;
+import org.sonatype.aether.repository.RemoteRepository;
+import org.sonatype.aether.resolution.ArtifactRequest;
+import org.sonatype.aether.resolution.ArtifactResolutionException;
+import org.sonatype.aether.resolution.ArtifactResult;
+import org.sonatype.aether.util.DefaultRepositorySystemSession;
+import org.sonatype.aether.util.artifact.JavaScopes;
+
+@Component( role = DependencyGraphResolver.class )
+public class DependencyGraphResolver
+{
+
+    private static final Logger LOGGER = Logger.getLogger( DependencyGraphResolver.class );
+
+    @Requirement
+    private RepositorySystem repositorySystem;
+
+    public DependencyGraph accumulateGraph( final Collection<MavenProject> rootProjects,
+                                            RepositorySystemSession rss,
+                                            final ProjectToolsSession session )
+    {
+        // if ( LOGGER.isDebugEnabled() )
+        {
+            if ( LOGGER.isDebugEnabled() )
+            {
+                LOGGER.debug( "Preparing for dependency-graph accumulation..." );
+            }
+        }
+        rss = prepareForGraphResolution( rss, session );
+
+        // if ( LOGGER.isDebugEnabled() )
+        {
+            if ( LOGGER.isDebugEnabled() )
+            {
+                LOGGER.debug( "Accumulating dependency graph..." );
+            }
+        }
+
+        return accumulate( session, rss, rootProjects, session.getRemoteRepositoriesArray() );
+    }
+
+    public DependencyGraph resolveGraph( final DependencyGraph depGraph,
+                                         final Collection<MavenProject> rootProjects,
+                                         final RepositorySystemSession rss,
+                                         final ProjectToolsSession session )
+    {
+
+        // if ( LOGGER.isDebugEnabled() )
+        {
+            if ( LOGGER.isDebugEnabled() )
+            {
+                LOGGER.debug( "Resolving dependencies in graph..." );
+            }
+        }
+        resolve( rss, rootProjects, depGraph, session );
+
+        // if ( LOGGER.isDebugEnabled() )
+        {
+            if ( LOGGER.isDebugEnabled() )
+            {
+                LOGGER.debug( "Graph state contains: " + depGraph.size() + " nodes." );
+            }
+        }
+
+        return depGraph;
+    }
+
+    // TODO: Allow fine-tuning of scopes resolved...
+    private RepositorySystemSession prepareForGraphResolution( final RepositorySystemSession s,
+                                                               final ProjectToolsSession session )
+    {
+        final DefaultRepositorySystemSession result = new DefaultRepositorySystemSession( s );
+        result.setDependencySelector( session.getDependencySelector() );
+
+        return result;
+    }
+
+    private void resolve( final RepositorySystemSession session,
+                          final Collection<MavenProject> rootProjects,
+                          final DependencyGraph depGraph, final ProjectToolsSession toolsSession )
+    {
+        final Set<DependencyResolveWorker> workers = new HashSet<DependencyResolveWorker>();
+        for ( final DepGraphNode node : depGraph )
+        {
+            if ( node == null || node.hasErrors() || node.isPreResolved() )
+            {
+                continue;
+            }
+
+            // if ( LOGGER.isDebugEnabled() )
+            {
+                if ( LOGGER.isDebugEnabled() )
+                {
+                    LOGGER.debug( "Resolving: " + node.getLatestArtifact() );
+                }
+            }
+            workers.add( new DependencyResolveWorker( node, session, repositorySystem ) );
+        }
+
+        runResolve( workers, toolsSession );
+        // for ( final DependencyResolveWorker worker : workers )
+        // {
+        // worker.run();
+        // }
+
+        // if ( LOGGER.isDebugEnabled() )
+        {
+            if ( LOGGER.isDebugEnabled() )
+            {
+                LOGGER.debug( "Dependency-graph resolution complete." );
+            }
+        }
+    }
+
+    private void runResolve( final Set<DependencyResolveWorker> workers,
+                             final ProjectToolsSession session )
+    {
+        final ExecutorService executorService =
+            Executors.newFixedThreadPool( session.getResolveThreads() );
+
+        final CountDownLatch latch = new CountDownLatch( workers.size() );
+        for ( final DependencyResolveWorker worker : workers )
+        {
+            worker.setLatch( latch );
+            executorService.execute( worker );
+        }
+
+        synchronized ( latch )
+        {
+            long count = 0;
+            while ( ( count = latch.getCount() ) > 0 )
+            {
+                // if ( LOGGER.isDebugEnabled() )
+                {
+                    if ( LOGGER.isDebugEnabled() )
+                    {
+                        LOGGER.debug( count + " resolution workers remaining. Waiting 3s..." );
+                    }
+                }
+                try
+                {
+                    latch.await( 3, TimeUnit.SECONDS );
+                }
+                catch ( final InterruptedException e )
+                {
+                    break;
+                }
+            }
+        }
+
+        boolean terminated = false;
+        int count = 1;
+        while ( !terminated )
+        {
+            try
+            {
+                executorService.shutdown();
+                // if ( LOGGER.isDebugEnabled() )
+                {
+                    if ( LOGGER.isDebugEnabled() )
+                    {
+                        LOGGER.debug( "Attempt " + count
+                            + " to shutdown graph-resolver. Waiting 3s..." );
+                    }
+                }
+
+                count++;
+                terminated = executorService.awaitTermination( 3, TimeUnit.SECONDS );
+            }
+            catch ( final InterruptedException e )
+            {
+                break;
+            }
+        }
+    }
+
+    private DependencyGraph accumulate( final ProjectToolsSession session,
+                                        final RepositorySystemSession rss,
+                                        final Collection<MavenProject> projects,
+                                        final RemoteRepository... remoteRepositories )
+    {
+        final ArtifactTypeRegistry stereotypes = rss.getArtifactTypeRegistry();
+
+        DependencyGraph depGraph;
+        synchronized ( session )
+        {
+            depGraph = session.getState( DependencyGraph.class );
+            if ( depGraph == null )
+            {
+                depGraph = new DependencyGraph();
+            }
+        }
+
+        final GraphAccumulator accumulator =
+            new GraphAccumulator( depGraph, session.getDependencyFilter() );
+
+        for ( final MavenProject project : projects )
+        {
+            // if ( LOGGER.isDebugEnabled() )
+            {
+                if ( LOGGER.isDebugEnabled() )
+                {
+                    LOGGER.debug( "Collecting dependencies for: " + project );
+                }
+            }
+            final CollectRequest request = new CollectRequest();
+            request.setRequestContext( "project" );
+            request.setRepositories( Arrays.asList( remoteRepositories ) );
+
+            if ( project.getDependencyArtifacts() == null )
+            {
+                // if ( LOGGER.isDebugEnabled() )
+                {
+                    if ( LOGGER.isDebugEnabled() )
+                    {
+                        LOGGER.debug( "Adding dependencies to collection request..." );
+                    }
+                }
+                for ( final Dependency dependency : project.getDependencies() )
+                {
+                    request.addDependency( RepositoryUtils.toDependency( dependency, stereotypes ) );
+                }
+            }
+            else
+            {
+                // if ( LOGGER.isDebugEnabled() )
+                {
+                    if ( LOGGER.isDebugEnabled() )
+                    {
+                        LOGGER.debug( "Mapping project dependencies by management key..." );
+                    }
+                }
+                final Map<String, Dependency> dependencies = new HashMap<String, Dependency>();
+                for ( final Dependency dependency : project.getDependencies() )
+                {
+                    final String key = dependency.getManagementKey();
+                    dependencies.put( key, dependency );
+                }
+
+                // if ( LOGGER.isDebugEnabled() )
+                {
+                    if ( LOGGER.isDebugEnabled() )
+                    {
+                        LOGGER.debug( "Adding dependencies to collection request..." );
+                    }
+                }
+                for ( final org.apache.maven.artifact.Artifact artifact : project.getDependencyArtifacts() )
+                {
+                    final String key = artifact.getDependencyConflictId();
+                    final Dependency dependency = dependencies.get( key );
+                    final Collection<org.apache.maven.model.Exclusion> exclusions =
+                        dependency != null ? dependency.getExclusions() : null;
+
+                    org.sonatype.aether.graph.Dependency dep =
+                        RepositoryUtils.toDependency( artifact, exclusions );
+                    if ( !JavaScopes.SYSTEM.equals( dep.getScope() )
+                        && dep.getArtifact().getFile() != null )
+                    {
+                        // enable re-resolution
+                        org.sonatype.aether.artifact.Artifact art = dep.getArtifact();
+                        art = art.setFile( null ).setVersion( art.getBaseVersion() );
+                        dep = dep.setArtifact( art );
+                    }
+                    request.addDependency( dep );
+                }
+            }
+
+            final DependencyManagement depMngt = project.getDependencyManagement();
+            if ( depMngt != null )
+            {
+                // if ( LOGGER.isDebugEnabled() )
+                {
+                    if ( LOGGER.isDebugEnabled() )
+                    {
+                        LOGGER.debug( "Adding managed dependencies to collection request..." );
+                    }
+                }
+                for ( final Dependency dependency : depMngt.getDependencies() )
+                {
+                    request.addManagedDependency( RepositoryUtils.toDependency( dependency,
+                                                                                stereotypes ) );
+                }
+            }
+
+            // if ( LOGGER.isDebugEnabled() )
+            {
+                if ( LOGGER.isDebugEnabled() )
+                {
+                    LOGGER.debug( "Collecting dependencies..." );
+                }
+            }
+            CollectResult result;
+            final Object old = rss.getData().get( ProjectToolsSession.SESSION_KEY );
+            try
+            {
+                rss.getData().set( ProjectToolsSession.SESSION_KEY, session );
+                result = repositorySystem.collectDependencies( rss, request );
+            }
+            catch ( final DependencyCollectionException e )
+            {
+                // TODO: Handle problem resolving POMs...
+                result = e.getResult();
+
+                // result.setDependencyGraph( e.getResult().getRoot() );
+                // result.setCollectionErrors( e.getResult().getExceptions() );
+                //
+                // throw new DependencyResolutionException( result, "Could not resolve dependencies for project "
+                // + project.getId() + ": " + e.getMessage(), e );
+            }
+            finally
+            {
+                rss.getData().set( ProjectToolsSession.SESSION_KEY, old );
+            }
+
+            final DependencyNode root = result.getRoot();
+            final DepGraphRootNode rootNode = depGraph.addRoot( root, project );
+
+            accumulator.resetForNextRun( root, rootNode );
+
+            // if ( LOGGER.isDebugEnabled() )
+            {
+                if ( LOGGER.isDebugEnabled() )
+                {
+                    LOGGER.debug( "Adding collected dependencies to consolidated dependency graph..." );
+                }
+            }
+            result.getRoot().accept( accumulator );
+
+        }
+
+        return depGraph;
+    }
+
+    private static final class GraphAccumulator
+        implements DependencyVisitor
+    {
+        private final LinkedList<DependencyNode> parents = new LinkedList<DependencyNode>();
+
+        private final Set<Exclusion> exclusions = new HashSet<Exclusion>();
+
+        private final Set<Exclusion> lastExclusions = new HashSet<Exclusion>();
+
+        private final DependencyGraph depGraph;
+
+        private DependencyNode root;
+
+        private DepGraphRootNode rootNode;
+
+        private final DependencyFilter filter;
+
+        GraphAccumulator( final DependencyGraph depGraph, final DependencyFilter filter )
+        {
+            this.depGraph = depGraph;
+            this.filter = filter;
+        }
+
+        void resetForNextRun( final DependencyNode root, final DepGraphRootNode rootNode )
+        {
+            parents.clear();
+            this.root = root;
+            this.rootNode = rootNode;
+            exclusions.clear();
+            lastExclusions.clear();
+        }
+
+        @Override
+        public boolean visitEnter( final DependencyNode node )
+        {
+            if ( filter != null && !filter.accept( node, parents ) )
+            {
+                return false;
+            }
+
+            if ( node == root )
+            {
+                parents.addFirst( root );
+                return true;
+            }
+            else if ( node == null || node.getDependency() == null
+                || node.getDependency().getArtifact() == null )
+            {
+                // if ( LOGGER.isDebugEnabled() )
+                {
+                    if ( LOGGER.isDebugEnabled() )
+                    {
+                        LOGGER.debug( "Invalid node: " + node );
+                    }
+                }
+                return true;
+            }
+
+            // if ( LOGGER.isDebugEnabled() )
+            {
+                if ( LOGGER.isDebugEnabled() )
+                {
+                    LOGGER.debug( "START: dependency-processing for: " + node );
+                }
+            }
+
+            boolean result = false;
+            final Artifact artifact = node.getDependency().getArtifact();
+            if ( !excluded( artifact ) )
+            {
+                // if ( LOGGER.isDebugEnabled() )
+                {
+                    if ( LOGGER.isDebugEnabled() )
+                    {
+                        LOGGER.debug( "Enabling resolution for: " + node );
+                    }
+                }
+
+                final DependencyNode parent = parents.getFirst();
+                // if ( LOGGER.isDebugEnabled() )
+                {
+                    if ( LOGGER.isDebugEnabled() )
+                    {
+                        LOGGER.debug( "Adding dependency from: " + parent + " to: " + node );
+                    }
+                }
+
+                // TODO: don't traverse beyond this node if it's already been considered...though we still need to
+                // connect it
+                // to the parent node (see below).
+                result = !depGraph.contains( node );
+
+                // result = true;
+
+                if ( parent == root )
+                {
+                    depGraph.addDependency( rootNode, node );
+                }
+                else
+                {
+                    depGraph.addDependency( parent, node );
+                }
+
+                if ( node.getDependency().getExclusions() != null )
+                {
+                    for ( final Exclusion exclusion : node.getDependency().getExclusions() )
+                    {
+                        if ( exclusions.add( exclusion ) )
+                        {
+                            lastExclusions.add( exclusion );
+                        }
+                    }
+                }
+
+                // if ( LOGGER.isDebugEnabled() )
+                {
+                    if ( LOGGER.isDebugEnabled() )
+                    {
+                        LOGGER.debug( "Pushing node: " + node + " onto parents stack." );
+                    }
+                }
+                parents.addFirst( node );
+
+                final StringBuilder builder = new StringBuilder();
+                for ( int i = 0; i < parents.size(); i++ )
+                {
+                    builder.append( "  " );
+                }
+                builder.append( ">>>" );
+                builder.append( node );
+                // if ( LOGGER.isDebugEnabled() )
+                {
+                    if ( LOGGER.isDebugEnabled() )
+                    {
+                        LOGGER.debug( builder.toString() );
+                    }
+                }
+            }
+            else
+            {
+                // if ( LOGGER.isDebugEnabled() )
+                {
+                    if ( LOGGER.isDebugEnabled() )
+                    {
+                        LOGGER.debug( "DISABLING resolution for: " + node );
+                    }
+                }
+            }
+
+            if ( node != null && !node.getRelocations().isEmpty() )
+            {
+                // if ( LOGGER.isDebugEnabled() )
+                {
+                    if ( LOGGER.isDebugEnabled() )
+                    {
+                        LOGGER.debug( "The artifact " + node.getRelocations().get( 0 )
+                            + " has been relocated to " + node.getDependency().getArtifact() );
+                    }
+                }
+            }
+
+            return result;
+        }
+
+        private boolean excluded( final Artifact artifact )
+        {
+            for ( final Exclusion exclusion : exclusions )
+            {
+                if ( match( exclusion.getGroupId(), artifact.getGroupId() )
+                    && match( exclusion.getArtifactId(), artifact.getArtifactId() )
+                    && match( exclusion.getExtension(), artifact.getExtension() )
+                    && match( exclusion.getClassifier(), artifact.getClassifier() ) )
+                {
+                    // if ( LOGGER.isDebugEnabled() )
+                    {
+                        if ( LOGGER.isDebugEnabled() )
+                        {
+                            LOGGER.debug( "EXCLUDED: " + artifact );
+                        }
+                    }
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        private boolean match( final String excluded, final String check )
+        {
+            return "*".equals( excluded ) || excluded.equals( check );
+        }
+
+        @Override
+        public boolean visitLeave( final DependencyNode node )
+        {
+            if ( node == null || parents.isEmpty() )
+            {
+                return true;
+            }
+
+            if ( node == parents.getFirst() )
+            {
+                // if ( LOGGER.isDebugEnabled() )
+                {
+                    if ( LOGGER.isDebugEnabled() )
+                    {
+                        LOGGER.debug( "Removing exclusions from last node: " + node );
+                    }
+                }
+
+                for ( final Exclusion exclusion : lastExclusions )
+                {
+                    exclusions.remove( exclusion );
+                }
+
+                lastExclusions.clear();
+
+                final StringBuilder builder = new StringBuilder();
+                for ( int i = 0; i < parents.size(); i++ )
+                {
+                    builder.append( "  " );
+                }
+                builder.append( "<<<" );
+                builder.append( node );
+                // if ( LOGGER.isDebugEnabled() )
+                {
+                    if ( LOGGER.isDebugEnabled() )
+                    {
+                        LOGGER.debug( builder.toString() );
+                    }
+                }
+
+                parents.removeFirst();
+            }
+            else
+            {
+                final int idx = parents.indexOf( node );
+                if ( idx > -1 )
+                {
+                    // if ( LOGGER.isDebugEnabled() )
+                    {
+                        if ( LOGGER.isDebugEnabled() )
+                        {
+                            LOGGER.debug( "TRAVERSAL LEAK. Removing " + ( idx + 1 )
+                                + " unaccounted-for parents that have finished traversal." );
+                        }
+                    }
+
+                    for ( int i = 0; i <= idx; i++ )
+                    {
+                        parents.removeFirst();
+                    }
+                }
+            }
+
+            // if ( LOGGER.isDebugEnabled() )
+            {
+                if ( LOGGER.isDebugEnabled() )
+                {
+                    LOGGER.debug( "END: dependency-processing for: " + node );
+                }
+            }
+
+            return true;
+        }
+
+    }
+
+    private static final class DependencyResolveWorker
+        implements Runnable
+    {
+
+        private final DepGraphNode depState;
+
+        private final RepositorySystemSession session;
+
+        private final RepositorySystem repositorySystem;
+
+        private ArtifactResult result;
+
+        private CountDownLatch latch;
+
+        DependencyResolveWorker( final DepGraphNode depState,
+                                 final RepositorySystemSession session,
+                                 final RepositorySystem repositorySystem )
+        {
+            this.depState = depState;
+            this.session = session;
+            this.repositorySystem = repositorySystem;
+        }
+
+        void setLatch( final CountDownLatch latch )
+        {
+            this.latch = latch;
+        }
+
+        @Override
+        public void run()
+        {
+            final Artifact artifact = depState.getLatestArtifact();
+
+            try
+            {
+                final ArtifactRequest request =
+                    new ArtifactRequest(
+                                         artifact,
+                                         new ArrayList<RemoteRepository>(
+                                                                          depState.getRemoteRepositories() ),
+                                         "project" );
+
+                result = new ArtifactResult( request );
+                if ( validateForResolution() )
+                {
+                    try
+                    {
+                        // if ( LOGGER.isDebugEnabled() )
+                        {
+                            if ( LOGGER.isDebugEnabled() )
+                            {
+                                LOGGER.debug( "RESOLVE: " + artifact );
+                            }
+                        }
+
+                        result = repositorySystem.resolveArtifact( session, request );
+                    }
+                    catch ( final ArtifactResolutionException e )
+                    {
+                        result.addException( e );
+                    }
+                }
+            }
+            finally
+            {
+                // final Runtime r = Runtime.getRuntime();
+                //
+                // final long MB = 1024 * 1024;
+                //
+                // System.out.println( "Memory status: " + ( r.totalMemory() - r.freeMemory() ) / MB + "M/"
+                // + r.totalMemory() / MB + "M" );
+
+                // FIXME: Do we need to detect whether resolution already happened for this artifact before we try to
+                // resolve it
+                // again??
+                depState.merge( result );
+                if ( latch != null )
+                {
+                    latch.countDown();
+                }
+            }
+        }
+
+        private boolean validateForResolution()
+        {
+            boolean valid = true;
+            if ( session == null )
+            {
+                result.addException( new IllegalArgumentException( "Cannot resolve dependency: "
+                    + depState.getLatestArtifact() + ", RepositorySystemSession has not been set!" ) );
+
+                valid = false;
+            }
+
+            if ( repositorySystem == null )
+            {
+                result.addException( new IllegalArgumentException( "Cannot resolve dependency: "
+                    + depState.getLatestArtifact() + ", RepositorySystem has not been set!" ) );
+
+                valid = false;
+            }
+
+            return valid;
+        }
+    }
+
+}

Propchange: maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/DependencyGraphResolver.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/DisconnectedDepNode.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/DisconnectedDepNode.java?rev=1161723&view=auto
==============================================================================
--- maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/DisconnectedDepNode.java (added)
+++ maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/DisconnectedDepNode.java Thu Aug 25 20:03:54 2011
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.maven.mae.depgraph.impl;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.graph.Dependency;
+import org.sonatype.aether.graph.DependencyNode;
+import org.sonatype.aether.graph.DependencyVisitor;
+import org.sonatype.aether.repository.RemoteRepository;
+import org.sonatype.aether.version.Version;
+import org.sonatype.aether.version.VersionConstraint;
+
+final class DisconnectedDepNode
+    implements DependencyNode
+{
+
+    private final DependencyNode delegate;
+
+    DisconnectedDepNode( final DependencyNode delegate )
+    {
+        this.delegate = delegate;
+    }
+
+    @Override
+    public List<DependencyNode> getChildren()
+    {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public boolean accept( final DependencyVisitor visitor )
+    {
+        return false;
+    }
+
+    @Override
+    public Dependency getDependency()
+    {
+        return delegate.getDependency();
+    }
+
+    @Override
+    public void setArtifact( final Artifact artifact )
+    {
+        delegate.setArtifact( artifact );
+    }
+
+    @Override
+    public List<Artifact> getRelocations()
+    {
+        return delegate.getRelocations();
+    }
+
+    @Override
+    public Collection<Artifact> getAliases()
+    {
+        return delegate.getAliases();
+    }
+
+    @Override
+    public VersionConstraint getVersionConstraint()
+    {
+        return delegate.getVersionConstraint();
+    }
+
+    @Override
+    public Version getVersion()
+    {
+        return delegate.getVersion();
+    }
+
+    @Override
+    public void setScope( final String scope )
+    {
+        delegate.setScope( scope );
+    }
+
+    @Override
+    public String getPremanagedVersion()
+    {
+        return delegate.getPremanagedVersion();
+    }
+
+    @Override
+    public String getPremanagedScope()
+    {
+        return delegate.getPremanagedScope();
+    }
+
+    @Override
+    public List<RemoteRepository> getRepositories()
+    {
+        return delegate.getRepositories();
+    }
+
+    @Override
+    public String getRequestContext()
+    {
+        return delegate.getRequestContext();
+    }
+
+    @Override
+    public void setRequestContext( final String context )
+    {
+        delegate.setRequestContext( context );
+    }
+
+    @Override
+    public Map<Object, Object> getData()
+    {
+        return delegate.getData();
+    }
+
+    @Override
+    public void setData( final Object key, final Object value )
+    {
+        delegate.setData( key, value );
+    }
+
+}

Propchange: maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/DisconnectedDepNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/FlexibleScopeDependencySelector.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/FlexibleScopeDependencySelector.java?rev=1161723&view=auto
==============================================================================
--- maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/FlexibleScopeDependencySelector.java (added)
+++ maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/FlexibleScopeDependencySelector.java Thu Aug 25 20:03:54 2011
@@ -0,0 +1,166 @@
+package org.apache.maven.mae.depgraph.impl;
+
+/*******************************************************************************
+ * Copyright (c) 2010-2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ *   http://www.eclipse.org/legal/epl-v10.html
+ * The Apache License v2.0 is available at
+ *   http://www.apache.org/licenses/LICENSE-2.0.html
+ * You may elect to redistribute this code under either of these licenses.
+ *******************************************************************************/
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.sonatype.aether.collection.DependencyCollectionContext;
+import org.sonatype.aether.collection.DependencySelector;
+import org.sonatype.aether.graph.Dependency;
+
+/**
+ * A dependency selector that filters transitive dependencies based on their scope. Direct dependencies are always
+ * included regardless of their scope. <em>Note:</em> This filter does not assume any relationships between the scopes.
+ * In particular, the filter is not aware of scopes that logically include other scopes.
+ * 
+ * @author Benjamin Bentmann
+ * @see Dependency#getScope()
+ */
+public class FlexibleScopeDependencySelector
+    implements DependencySelector
+{
+
+    private boolean transitive;
+
+    private final Set<String> included;
+
+    private final Set<String> excluded;
+
+    public FlexibleScopeDependencySelector()
+    {
+        included = new HashSet<String>();
+        excluded = new HashSet<String>();
+    }
+
+    /**
+     * Creates a new selector using the specified includes and excludes.
+     * 
+     * @param included The set of scopes to include, may be {@code null} or empty to include any scope.
+     * @param excluded The set of scopes to exclude, may be {@code null} or empty to exclude no scope.
+     */
+    public FlexibleScopeDependencySelector( final Collection<String> included,
+                                            final Collection<String> excluded )
+    {
+        transitive = false;
+        if ( included != null )
+        {
+            this.included = new HashSet<String>();
+            this.included.addAll( included );
+        }
+        else
+        {
+            this.included = Collections.emptySet();
+        }
+        if ( excluded != null )
+        {
+            this.excluded = new HashSet<String>();
+            this.excluded.addAll( excluded );
+        }
+        else
+        {
+            this.excluded = Collections.emptySet();
+        }
+    }
+
+    /**
+     * Creates a new selector using the specified excludes.
+     * 
+     * @param excluded The set of scopes to exclude, may be {@code null} or empty to exclude no scope.
+     */
+    public FlexibleScopeDependencySelector( final String... excluded )
+    {
+        this( null, Arrays.asList( excluded ) );
+    }
+
+    private FlexibleScopeDependencySelector( final boolean transitive,
+                                             final Collection<String> included,
+                                             final Collection<String> excluded )
+    {
+        this.transitive = transitive;
+        this.included = included == null ? null : new HashSet<String>( included );
+        this.excluded = excluded == null ? null : new HashSet<String>( excluded );
+    }
+
+    @Override
+    public boolean selectDependency( final Dependency dependency )
+    {
+        if ( !transitive )
+        {
+            return true;
+        }
+
+        String scope = dependency.getScope();
+        return ( included.isEmpty() || included.contains( scope ) )
+            && ( excluded.isEmpty() || !excluded.contains( scope ) );
+    }
+
+    @Override
+    public DependencySelector deriveChildSelector( final DependencyCollectionContext context )
+    {
+        if ( this.transitive || context.getDependency() == null )
+        {
+            return this;
+        }
+
+        return new FlexibleScopeDependencySelector( true, included, excluded );
+    }
+
+    @Override
+    public boolean equals( final Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        else if ( null == obj || !getClass().equals( obj.getClass() ) )
+        {
+            return false;
+        }
+
+        FlexibleScopeDependencySelector that = (FlexibleScopeDependencySelector) obj;
+        return transitive == that.transitive && included.equals( that.included )
+            && excluded.equals( that.excluded );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        int hash = 17;
+        hash = hash * 31 + ( transitive ? 1 : 0 );
+        hash = hash * 31 + included.hashCode();
+        hash = hash * 31 + excluded.hashCode();
+        return hash;
+    }
+
+    public FlexibleScopeDependencySelector includeScope( final String scope )
+    {
+        included.add( scope );
+        return this;
+    }
+
+    public FlexibleScopeDependencySelector excludeScope( final String scope )
+    {
+        excluded.add( scope );
+        return this;
+    }
+
+    public FlexibleScopeDependencySelector setTransitive( final boolean transitive )
+    {
+        this.transitive = transitive;
+        return this;
+    }
+}

Propchange: maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/FlexibleScopeDependencySelector.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/collect/BareBonesDependencyCollector.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/collect/BareBonesDependencyCollector.java?rev=1161723&view=auto
==============================================================================
--- maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/collect/BareBonesDependencyCollector.java (added)
+++ maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/collect/BareBonesDependencyCollector.java Thu Aug 25 20:03:54 2011
@@ -0,0 +1,713 @@
+package org.apache.maven.mae.depgraph.impl.collect;
+
+/*******************************************************************************
+ * Copyright (c) 2010-2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ *   http://www.eclipse.org/legal/epl-v10.html
+ * The Apache License v2.0 is available at
+ *   http://www.apache.org/licenses/LICENSE-2.0.html
+ * You may elect to redistribute this code under either of these licenses.
+ *******************************************************************************/
+
+import static org.sonatype.aether.util.artifact.ArtifacIdUtils.toId;
+
+import org.apache.log4j.Logger;
+import org.apache.maven.mae.project.session.ProjectToolsSession;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.sonatype.aether.RepositoryException;
+import org.sonatype.aether.RepositorySystemSession;
+import org.sonatype.aether.RequestTrace;
+import org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.artifact.ArtifactType;
+import org.sonatype.aether.artifact.ArtifactTypeRegistry;
+import org.sonatype.aether.collection.CollectRequest;
+import org.sonatype.aether.collection.CollectResult;
+import org.sonatype.aether.collection.DependencyCollectionContext;
+import org.sonatype.aether.collection.DependencyCollectionException;
+import org.sonatype.aether.collection.DependencyGraphTransformationContext;
+import org.sonatype.aether.collection.DependencyGraphTransformer;
+import org.sonatype.aether.collection.DependencyManagement;
+import org.sonatype.aether.collection.DependencyManager;
+import org.sonatype.aether.collection.DependencySelector;
+import org.sonatype.aether.collection.DependencyTraverser;
+import org.sonatype.aether.graph.Dependency;
+import org.sonatype.aether.graph.DependencyFilter;
+import org.sonatype.aether.graph.DependencyNode;
+import org.sonatype.aether.impl.ArtifactDescriptorReader;
+import org.sonatype.aether.impl.DependencyCollector;
+import org.sonatype.aether.impl.RemoteRepositoryManager;
+import org.sonatype.aether.impl.VersionRangeResolver;
+import org.sonatype.aether.impl.internal.DefaultDependencyCollector;
+import org.sonatype.aether.repository.ArtifactRepository;
+import org.sonatype.aether.repository.RemoteRepository;
+import org.sonatype.aether.resolution.ArtifactDescriptorException;
+import org.sonatype.aether.resolution.ArtifactDescriptorRequest;
+import org.sonatype.aether.resolution.ArtifactDescriptorResult;
+import org.sonatype.aether.resolution.VersionRangeRequest;
+import org.sonatype.aether.resolution.VersionRangeResolutionException;
+import org.sonatype.aether.resolution.VersionRangeResult;
+import org.sonatype.aether.spi.locator.Service;
+import org.sonatype.aether.spi.locator.ServiceLocator;
+import org.sonatype.aether.util.DefaultRepositorySystemSession;
+import org.sonatype.aether.util.DefaultRequestTrace;
+import org.sonatype.aether.util.artifact.ArtifactProperties;
+import org.sonatype.aether.version.Version;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * {@link DependencyCollector} implementation based on {@link DefaultDependencyCollector}, but which uses a more
+ * aggressively graph-oriented approach. This centralizes and de-dupes references to {@link Artifact} and
+ * {@link RemoteRepository} instances, in order to reduce the memory consumption.
+ * 
+ * @author Benjamin Bentmann
+ * @author John Casey
+ */
+@Component( role = DependencyCollector.class, hint = BareBonesDependencyCollector.HINT )
+public class BareBonesDependencyCollector
+    implements DependencyCollector, Service
+{
+
+    public static final String HINT = "bare-bones";
+
+    private static final Logger logger = Logger.getLogger( BareBonesDependencyCollector.class );
+
+    @Requirement
+    private RemoteRepositoryManager remoteRepositoryManager;
+
+    @Requirement
+    private ArtifactDescriptorReader descriptorReader;
+
+    @Requirement
+    private VersionRangeResolver versionRangeResolver;
+
+    public BareBonesDependencyCollector()
+    {
+        // enables default constructor
+    }
+
+    public BareBonesDependencyCollector( final Logger logger, final RemoteRepositoryManager remoteRepositoryManager,
+                                         final ArtifactDescriptorReader artifactDescriptorReader,
+                                         final VersionRangeResolver versionRangeResolver )
+    {
+        setRemoteRepositoryManager( remoteRepositoryManager );
+        setArtifactDescriptorReader( artifactDescriptorReader );
+        setVersionRangeResolver( versionRangeResolver );
+    }
+
+    @Override
+    public void initService( final ServiceLocator locator )
+    {
+        setRemoteRepositoryManager( locator.getService( RemoteRepositoryManager.class ) );
+        setArtifactDescriptorReader( locator.getService( ArtifactDescriptorReader.class ) );
+        setVersionRangeResolver( locator.getService( VersionRangeResolver.class ) );
+    }
+
+    public BareBonesDependencyCollector setRemoteRepositoryManager( final RemoteRepositoryManager remoteRepositoryManager )
+    {
+        if ( remoteRepositoryManager == null )
+        {
+            throw new IllegalArgumentException( "remote repository manager has not been specified" );
+        }
+        this.remoteRepositoryManager = remoteRepositoryManager;
+        return this;
+    }
+
+    public BareBonesDependencyCollector setArtifactDescriptorReader( final ArtifactDescriptorReader artifactDescriptorReader )
+    {
+        if ( artifactDescriptorReader == null )
+        {
+            throw new IllegalArgumentException( "artifact descriptor reader has not been specified" );
+        }
+        descriptorReader = artifactDescriptorReader;
+        return this;
+    }
+
+    public BareBonesDependencyCollector setVersionRangeResolver( final VersionRangeResolver versionRangeResolver )
+    {
+        if ( versionRangeResolver == null )
+        {
+            throw new IllegalArgumentException( "version range resolver has not been specified" );
+        }
+        this.versionRangeResolver = versionRangeResolver;
+        return this;
+    }
+
+    @Override
+    public CollectResult collectDependencies( RepositorySystemSession session, final CollectRequest request )
+        throws DependencyCollectionException
+    {
+        session = optimizeSession( session );
+
+        final RequestTrace trace = DefaultRequestTrace.newChild( request.getTrace(), request );
+
+        final CollectResult result = new CollectResult( request );
+
+        final ProjectToolsSession toolsSession =
+            (ProjectToolsSession) session.getData().get( ProjectToolsSession.SESSION_KEY );
+        
+        DependencySelector depSelector = toolsSession == null ? null : toolsSession.getDependencySelector();
+        if ( depSelector == null )
+        {
+            depSelector = session.getDependencySelector();
+        }
+        
+        final DependencyManager depManager = session.getDependencyManager();
+        final DependencyTraverser depTraverser = session.getDependencyTraverser();
+
+        Dependency root = request.getRoot();
+        List<RemoteRepository> repositories = request.getRepositories();
+        List<Dependency> dependencies = request.getDependencies();
+        List<Dependency> managedDependencies = request.getManagedDependencies();
+
+        final SlimDepGraph graph = new SlimDepGraph( session );
+        SlimDependencyEdge edge = null;
+        if ( root != null )
+        {
+            VersionRangeResult rangeResult;
+            try
+            {
+                final VersionRangeRequest rangeRequest =
+                    new VersionRangeRequest( root.getArtifact(), request.getRepositories(), request.getRequestContext() );
+                rangeRequest.setTrace( trace );
+                rangeResult = versionRangeResolver.resolveVersionRange( session, rangeRequest );
+
+                if ( rangeResult.getVersions().isEmpty() )
+                {
+                    throw new VersionRangeResolutionException( rangeResult, "No versions available for "
+                        + root.getArtifact() + " within specified range" );
+                }
+            }
+            catch ( final VersionRangeResolutionException e )
+            {
+                result.addException( e );
+                throw new DependencyCollectionException( result );
+            }
+
+            final Version version = rangeResult.getVersions().get( rangeResult.getVersions().size() - 1 );
+            root = root.setArtifact( root.getArtifact().setVersion( version.toString() ) );
+
+            ArtifactDescriptorResult descriptorResult;
+            try
+            {
+                final ArtifactDescriptorRequest descriptorRequest = new ArtifactDescriptorRequest();
+                descriptorRequest.setArtifact( root.getArtifact() );
+                descriptorRequest.setRepositories( request.getRepositories() );
+                descriptorRequest.setRequestContext( request.getRequestContext() );
+                descriptorRequest.setTrace( trace );
+                if ( isLackingDescriptor( root.getArtifact() ) )
+                {
+                    descriptorResult = new ArtifactDescriptorResult( descriptorRequest );
+                }
+                else
+                {
+                    descriptorResult = descriptorReader.readArtifactDescriptor( session, descriptorRequest );
+                }
+            }
+            catch ( final ArtifactDescriptorException e )
+            {
+                result.addException( e );
+                throw new DependencyCollectionException( result );
+            }
+
+            root = root.setArtifact( descriptorResult.getArtifact() );
+
+            repositories =
+                remoteRepositoryManager.aggregateRepositories( session, repositories,
+                                                               descriptorResult.getRepositories(), true );
+            dependencies = mergeDeps( dependencies, descriptorResult.getDependencies() );
+            managedDependencies = mergeDeps( managedDependencies, descriptorResult.getManagedDependencies() );
+
+            final SlimDependencyNode node = new SlimDependencyNode( toId( descriptorResult.getArtifact() ), graph );
+            node.setAliases( descriptorResult.getAliases() );
+            node.setRepositories( request.getRepositories() );
+
+            edge = new SlimDependencyEdge( node, graph );
+            edge.setDependency( root );
+            edge.setRequestContext( request.getRequestContext() );
+            edge.setRelocations( descriptorResult.getRelocations() );
+            edge.setVersionConstraint( rangeResult.getVersionConstraint() );
+            edge.setVersion( version );
+        }
+        else
+        {
+            edge = new SlimDependencyEdge( new SlimDependencyNode( SlimDependencyNode.UNKNOWN_ROOT_ID, graph ), graph );
+        }
+
+        result.setRoot( edge );
+
+        final boolean traverse = ( root == null ) || depTraverser.traverseDependency( root );
+
+        if ( traverse && !dependencies.isEmpty() )
+        {
+            final LinkedList<SlimDependencyEdge> edges = new LinkedList<SlimDependencyEdge>();
+            edges.addFirst( edge );
+
+            final DependencyCollectionContext context = new CollectionContext( session, root, managedDependencies );
+
+            final DepGraphCache pool = new DepGraphCache( session );
+            process( session, toolsSession, trace, result, edges, dependencies, repositories,
+                     depSelector.deriveChildSelector( context ), depManager.deriveChildManager( context ),
+                     depTraverser.deriveChildTraverser( context ), pool, graph );
+        }
+
+        final DependencyGraphTransformer transformer = session.getDependencyGraphTransformer();
+        try
+        {
+            final DependencyGraphTransformationContext context = new GraphTransformationContext( session );
+            result.setRoot( transformer.transformGraph( edge, context ) );
+        }
+        catch ( final RepositoryException e )
+        {
+            result.addException( e );
+        }
+
+        if ( !result.getExceptions().isEmpty() )
+        {
+            throw new DependencyCollectionException( result );
+        }
+
+        return result;
+    }
+
+    private RepositorySystemSession optimizeSession( final RepositorySystemSession session )
+    {
+        final DefaultRepositorySystemSession optimized = new DefaultRepositorySystemSession( session );
+        optimized.setArtifactTypeRegistry( new TypeRegistry( session ) );
+        return optimized;
+    }
+
+    private List<Dependency> mergeDeps( final List<Dependency> dominant, final List<Dependency> recessive )
+    {
+        List<Dependency> result;
+        if ( dominant == null || dominant.isEmpty() )
+        {
+            result = recessive;
+        }
+        else if ( recessive == null || recessive.isEmpty() )
+        {
+            result = dominant;
+        }
+        else
+        {
+            result = new ArrayList<Dependency>( dominant.size() + recessive.size() );
+            final Collection<String> ids = new HashSet<String>();
+            for ( final Dependency dependency : dominant )
+            {
+                ids.add( getId( dependency.getArtifact() ) );
+                result.add( dependency );
+            }
+            for ( final Dependency dependency : recessive )
+            {
+                if ( !ids.contains( getId( dependency.getArtifact() ) ) )
+                {
+                    result.add( dependency );
+                }
+            }
+        }
+        return result;
+    }
+
+    private String getId( final Artifact a )
+    {
+        return a.getGroupId() + ':' + a.getArtifactId() + ':' + a.getClassifier() + ':' + a.getExtension();
+    }
+
+    private boolean process( final RepositorySystemSession session, final ProjectToolsSession toolsSession,
+                             final RequestTrace trace, final CollectResult result,
+                             final LinkedList<SlimDependencyEdge> edges, final List<Dependency> dependencies,
+                             final List<RemoteRepository> repositories, final DependencySelector depSelector,
+                             final DependencyManager depManager, final DependencyTraverser depTraverser,
+                             final DepGraphCache pool, final SlimDepGraph graph )
+        throws DependencyCollectionException
+    {
+        boolean cycle = false;
+
+        final DependencyFilter filter = toolsSession == null ? null : toolsSession.getDependencyFilter();
+
+        nextDependency: for ( Dependency dependency : dependencies )
+        {
+            boolean disableVersionManagement = false;
+
+            List<Artifact> relocations = Collections.emptyList();
+
+            thisDependency: while ( true )
+            {
+                if ( !depSelector.selectDependency( dependency ) )
+                {
+                    logger.warn( "SELECT - Excluding from dependency graph: " + dependency.getArtifact() );
+                    continue nextDependency;
+                }
+
+                final DependencyManagement depMngt = depManager.manageDependency( dependency );
+                String premanagedVersion = null;
+                String premanagedScope = null;
+
+                if ( depMngt != null )
+                {
+                    if ( depMngt.getVersion() != null && !disableVersionManagement )
+                    {
+                        final Artifact artifact = dependency.getArtifact();
+                        premanagedVersion = artifact.getVersion();
+                        dependency = dependency.setArtifact( artifact.setVersion( depMngt.getVersion() ) );
+                    }
+                    if ( depMngt.getProperties() != null )
+                    {
+                        final Artifact artifact = dependency.getArtifact();
+                        dependency = dependency.setArtifact( artifact.setProperties( depMngt.getProperties() ) );
+                    }
+                    if ( depMngt.getScope() != null )
+                    {
+                        premanagedScope = dependency.getScope();
+                        dependency = dependency.setScope( depMngt.getScope() );
+                    }
+                    if ( depMngt.getExclusions() != null )
+                    {
+                        dependency = dependency.setExclusions( depMngt.getExclusions() );
+                    }
+                }
+                disableVersionManagement = false;
+
+                final boolean noDescriptor = isLackingDescriptor( dependency.getArtifact() );
+
+                final boolean traverse = !noDescriptor && depTraverser.traverseDependency( dependency );
+
+                VersionRangeResult rangeResult;
+                try
+                {
+                    final VersionRangeRequest rangeRequest = new VersionRangeRequest();
+                    rangeRequest.setArtifact( dependency.getArtifact() );
+                    rangeRequest.setRepositories( repositories );
+                    rangeRequest.setRequestContext( result.getRequest().getRequestContext() );
+                    rangeRequest.setTrace( trace );
+
+                    final Object key = pool.toKey( rangeRequest );
+                    rangeResult = pool.getConstraint( key, rangeRequest );
+                    if ( rangeResult == null )
+                    {
+                        rangeResult = versionRangeResolver.resolveVersionRange( session, rangeRequest );
+                        pool.putConstraint( key, rangeResult );
+                    }
+
+                    if ( rangeResult.getVersions().isEmpty() )
+                    {
+                        throw new VersionRangeResolutionException( rangeResult, "No versions available for "
+                            + dependency.getArtifact() + " within specified range" );
+                    }
+                }
+                catch ( final VersionRangeResolutionException e )
+                {
+                    result.addException( e );
+                    continue nextDependency;
+                }
+
+                final List<Version> versions = new ArrayList<Version>( rangeResult.getVersions() );
+                Collections.reverse( versions );
+
+                for ( final Version version : versions )
+                {
+                    final Artifact originalArtifact = dependency.getArtifact().setVersion( version.toString() );
+                    Dependency d = dependency.setArtifact( originalArtifact );
+
+                    ArtifactDescriptorResult descriptorResult;
+                    try
+                    {
+                        final ArtifactDescriptorRequest descriptorRequest = new ArtifactDescriptorRequest();
+                        descriptorRequest.setArtifact( d.getArtifact() );
+                        descriptorRequest.setRepositories( repositories );
+                        descriptorRequest.setRequestContext( result.getRequest().getRequestContext() );
+                        descriptorRequest.setTrace( trace );
+
+                        if ( noDescriptor )
+                        {
+                            descriptorResult = new ArtifactDescriptorResult( descriptorRequest );
+                        }
+                        else
+                        {
+                            final Object key = pool.toKey( descriptorRequest );
+                            descriptorResult = pool.getDescriptor( key, descriptorRequest );
+                            if ( descriptorResult == null )
+                            {
+                                descriptorResult = descriptorReader.readArtifactDescriptor( session, descriptorRequest );
+                                pool.putDescriptor( key, descriptorResult );
+                            }
+                        }
+                    }
+                    catch ( final ArtifactDescriptorException e )
+                    {
+                        result.addException( e );
+                        continue;
+                    }
+
+                    d = d.setArtifact( descriptorResult.getArtifact() );
+
+                    if ( findDuplicate( edges, d.getArtifact() ) != null )
+                    {
+                        cycle = true;
+                        continue nextDependency;
+                    }
+
+                    if ( !descriptorResult.getRelocations().isEmpty() )
+                    {
+                        relocations = descriptorResult.getRelocations();
+
+                        disableVersionManagement =
+                            originalArtifact.getGroupId().equals( d.getArtifact().getGroupId() )
+                                && originalArtifact.getArtifactId().equals( d.getArtifact().getArtifactId() );
+
+                        dependency = d;
+                        continue thisDependency;
+                    }
+
+                    d = pool.intern( d.setArtifact( graph.intern( d.getArtifact() ) ) );
+
+                    DependencySelector childSelector = null;
+                    DependencyManager childManager = null;
+                    DependencyTraverser childTraverser = null;
+                    List<RemoteRepository> childRepos = null;
+                    final String key = toId( d.getArtifact() );
+
+                    boolean recurse = traverse && !descriptorResult.getDependencies().isEmpty();
+                    if ( recurse )
+                    {
+                        final DependencyCollectionContext context =
+                            new CollectionContext( session, d, descriptorResult.getManagedDependencies() );
+
+                        childSelector = depSelector.deriveChildSelector( context );
+                        childManager = depManager.deriveChildManager( context );
+                        childTraverser = depTraverser.deriveChildTraverser( context );
+
+                        childRepos =
+                            remoteRepositoryManager.aggregateRepositories( session, repositories,
+                                                                           descriptorResult.getRepositories(), true );
+                    }
+
+                    List<RemoteRepository> repos;
+                    final ArtifactRepository repo = rangeResult.getRepository( version );
+                    if ( repo instanceof RemoteRepository )
+                    {
+                        repos = Collections.singletonList( (RemoteRepository) repo );
+                    }
+                    else if ( repo == null )
+                    {
+                        repos = repositories;
+                    }
+                    else
+                    {
+                        repos = Collections.emptyList();
+                    }
+
+                    SlimDependencyNode child = graph.getNode( key );
+                    if ( child == null )
+                    {
+                        child = new SlimDependencyNode( key, graph );
+                        child.setAliases( descriptorResult.getAliases() );
+                        child.setRepositories( repos );
+                    }
+                    else
+                    {
+                        recurse = false;
+
+                        if ( repos.size() < child.getRepositories().size() )
+                        {
+                            child.setRepositories( repos );
+                        }
+                    }
+
+                    final SlimDependencyNode node = edges.getFirst().getTo();
+
+                    final SlimDependencyEdge edge = new SlimDependencyEdge( node, child, graph );
+                    edge.setDependency( d );
+                    edge.setScope( d.getScope() );
+                    edge.setPremanagedScope( premanagedScope );
+                    edge.setPremanagedVersion( premanagedVersion );
+                    edge.setRelocations( relocations );
+                    edge.setVersionConstraint( rangeResult.getVersionConstraint() );
+                    edge.setVersion( version );
+                    edge.setRequestContext( result.getRequest().getRequestContext() );
+
+                    final List<DependencyNode> parents = new ArrayList<DependencyNode>();
+                    parents.add( edges.getFirst() );
+
+                    if ( filter != null && !filter.accept( edge, parents ) )
+                    {
+                        logger.warn( "FILTER - Excluding from dependency graph: " + edge.getDependency().getArtifact() );
+                        graph.removeEdge( edge );
+                        continue nextDependency;
+                    }
+
+                    if ( recurse )
+                    {
+                        edges.addFirst( edge );
+
+                        if ( process( session, toolsSession, trace, result, edges, descriptorResult.getDependencies(), childRepos,
+                                      childSelector, childManager, childTraverser, pool, graph ) )
+                        {
+                            cycle = true;
+                            continue nextDependency;
+                        }
+
+                        edges.removeFirst();
+                    }
+                }
+
+                break;
+            }
+        }
+
+        return cycle;
+    }
+
+    private SlimDependencyEdge findDuplicate( final List<SlimDependencyEdge> edges, final Artifact artifact )
+    {
+        for ( final SlimDependencyEdge edge : edges )
+        {
+            final Dependency dependency = edge.getDependency();
+            if ( dependency == null )
+            {
+                break;
+            }
+
+            final Artifact a = dependency.getArtifact();
+            if ( !a.getArtifactId().equals( artifact.getArtifactId() ) )
+            {
+                continue;
+            }
+            if ( !a.getGroupId().equals( artifact.getGroupId() ) )
+            {
+                continue;
+            }
+            if ( !a.getBaseVersion().equals( artifact.getBaseVersion() ) )
+            {
+                continue;
+            }
+            if ( !a.getExtension().equals( artifact.getExtension() ) )
+            {
+                continue;
+            }
+            if ( !a.getClassifier().equals( artifact.getClassifier() ) )
+            {
+                continue;
+            }
+
+            return edge;
+        }
+
+        return null;
+    }
+
+    private boolean isLackingDescriptor( final Artifact artifact )
+    {
+        return artifact.getProperty( ArtifactProperties.LOCAL_PATH, null ) != null;
+    }
+
+    private static final class CollectionContext
+        implements DependencyCollectionContext
+    {
+
+        private final RepositorySystemSession session;
+
+        private final Dependency dependency;
+
+        private final List<Dependency> managedDependencies;
+
+        CollectionContext( final RepositorySystemSession session, final Dependency dependency,
+                           final List<Dependency> managedDependencies )
+        {
+            this.session = session;
+            this.dependency = dependency;
+            this.managedDependencies = managedDependencies;
+        }
+
+        @Override
+        public RepositorySystemSession getSession()
+        {
+            return session;
+        }
+
+        @Override
+        public Dependency getDependency()
+        {
+            return dependency;
+        }
+
+        @Override
+        public List<Dependency> getManagedDependencies()
+        {
+            return managedDependencies;
+        }
+
+    }
+
+    private static final class GraphTransformationContext
+        implements DependencyGraphTransformationContext
+    {
+
+        private final RepositorySystemSession session;
+
+        private final Map<Object, Object> ctx = new HashMap<Object, Object>();
+
+        GraphTransformationContext( final RepositorySystemSession session )
+        {
+            this.session = session;
+        }
+
+        @Override
+        public RepositorySystemSession getSession()
+        {
+            return session;
+        }
+
+        @Override
+        public Object get( final Object key )
+        {
+            return ctx.get( key );
+        }
+
+        @Override
+        public Object put( final Object key, final Object value )
+        {
+            return ctx.put( key, value );
+        }
+
+    }
+
+    private static final class TypeRegistry
+        implements ArtifactTypeRegistry
+    {
+        private final ArtifactTypeRegistry delegate;
+
+        private final Map<String, ArtifactType> types = new HashMap<String, ArtifactType>();
+
+        TypeRegistry( final RepositorySystemSession session )
+        {
+            delegate = session.getArtifactTypeRegistry();
+        }
+
+        @Override
+        public ArtifactType get( final String typeId )
+        {
+            ArtifactType type = types.get( typeId );
+
+            if ( type == null )
+            {
+                type = delegate.get( typeId );
+                types.put( typeId, type );
+            }
+
+            return type;
+        }
+    }
+
+}

Propchange: maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/collect/BareBonesDependencyCollector.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/collect/DepGraphCache.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/collect/DepGraphCache.java?rev=1161723&view=auto
==============================================================================
--- maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/collect/DepGraphCache.java (added)
+++ maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/collect/DepGraphCache.java Thu Aug 25 20:03:54 2011
@@ -0,0 +1,511 @@
+package org.apache.maven.mae.depgraph.impl.collect;
+
+/*******************************************************************************
+ * Copyright (c) 2010-2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ *   http://www.eclipse.org/legal/epl-v10.html
+ * The Apache License v2.0 is available at
+ *   http://www.apache.org/licenses/LICENSE-2.0.html
+ * You may elect to redistribute this code under either of these licenses.
+ *******************************************************************************/
+
+import static org.sonatype.aether.util.artifact.ArtifacIdUtils.toId;
+
+import org.sonatype.aether.RepositoryCache;
+import org.sonatype.aether.RepositorySystemSession;
+import org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.collection.DependencyManager;
+import org.sonatype.aether.collection.DependencySelector;
+import org.sonatype.aether.collection.DependencyTraverser;
+import org.sonatype.aether.graph.Dependency;
+import org.sonatype.aether.repository.ArtifactRepository;
+import org.sonatype.aether.repository.RemoteRepository;
+import org.sonatype.aether.resolution.ArtifactDescriptorRequest;
+import org.sonatype.aether.resolution.ArtifactDescriptorResult;
+import org.sonatype.aether.resolution.VersionRangeRequest;
+import org.sonatype.aether.resolution.VersionRangeResult;
+import org.sonatype.aether.version.Version;
+import org.sonatype.aether.version.VersionConstraint;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/**
+ * Based on DataPool in aether-impl, this cache provides the ability to clear the cache in the
+ * {@link RepositorySystemSession}, along with tracking for {@link RemoteRepository} instances, and NOT including
+ * tracking for nodes.
+ * 
+ * @author Benjamin Bentmann
+ * @author John Casey
+ */
+public final class DepGraphCache
+{
+
+    private static final String ARTIFACT_POOL = DepGraphCache.class.getName() + "$Artifact";
+
+    private static final String DEPENDENCY_POOL = DepGraphCache.class.getName() + "$Dependency";
+
+    private static final String REPOSITORY_POOL = DepGraphCache.class.getName() + "$Repository";
+
+    private static final String DESCRIPTORS = DepGraphCache.class.getName() + "$Descriptors";
+
+    private ObjectPool<String, Artifact> artifacts;
+
+    private ObjectPool<Dependency, Dependency> dependencies;
+
+    private ObjectPool<RemoteRepository, RemoteRepository> repositories;
+
+    private Map<Object, Descriptor> descriptors;
+
+    private final Map<Object, Constraint> constraints = new WeakHashMap<Object, Constraint>();
+
+    @SuppressWarnings( "unchecked" )
+    DepGraphCache( final RepositorySystemSession session )
+    {
+        final RepositoryCache cache = session.getCache();
+
+        if ( cache != null )
+        {
+            artifacts = (ObjectPool<String, Artifact>) cache.get( session, ARTIFACT_POOL );
+            dependencies = (ObjectPool<Dependency, Dependency>) cache.get( session, DEPENDENCY_POOL );
+            repositories = (ObjectPool<RemoteRepository, RemoteRepository>) cache.get( session, REPOSITORY_POOL );
+            descriptors = (Map<Object, Descriptor>) cache.get( session, DESCRIPTORS );
+        }
+
+        if ( artifacts == null )
+        {
+            artifacts = new ObjectPool<String, Artifact>();
+            if ( cache != null )
+            {
+                cache.put( session, ARTIFACT_POOL, artifacts );
+            }
+        }
+
+        if ( dependencies == null )
+        {
+            dependencies = new ObjectPool<Dependency, Dependency>();
+            if ( cache != null )
+            {
+                cache.put( session, DEPENDENCY_POOL, dependencies );
+            }
+        }
+
+        if ( repositories == null )
+        {
+            repositories = new ObjectPool<RemoteRepository, RemoteRepository>();
+            if ( cache != null )
+            {
+                cache.put( session, DEPENDENCY_POOL, repositories );
+            }
+        }
+
+        if ( descriptors == null )
+        {
+            descriptors = Collections.synchronizedMap( new WeakHashMap<Object, Descriptor>( 256 ) );
+            if ( cache != null )
+            {
+                cache.put( session, DESCRIPTORS, descriptors );
+            }
+        }
+    }
+
+    public static void clear( final RepositorySystemSession session )
+    {
+        synchronized ( session )
+        {
+            final RepositoryCache cache = session.getCache();
+
+            if ( cache != null )
+            {
+                cache.put( session, ARTIFACT_POOL, null );
+                cache.put( session, DEPENDENCY_POOL, null );
+                cache.put( session, REPOSITORY_POOL, null );
+                cache.put( session, DESCRIPTORS, null );
+            }
+        }
+    }
+
+    synchronized void setArtifact( final Artifact artifact )
+    {
+        final String id = toId( artifact );
+        artifacts.set( id, artifact );
+    }
+
+    Artifact getArtifact( final String key )
+    {
+        return artifacts.get( key );
+    }
+
+    Artifact intern( final Artifact artifact )
+    {
+        return artifacts.intern( toId( artifact ), artifact );
+    }
+
+    Dependency intern( final Dependency dependency )
+    {
+        return dependencies.intern( dependency, dependency );
+    }
+
+    RemoteRepository intern( final RemoteRepository repo )
+    {
+        return repositories.intern( repo, repo );
+    }
+
+    Object toKey( final ArtifactDescriptorRequest request )
+    {
+        return request.getArtifact();
+    }
+
+    ArtifactDescriptorResult getDescriptor( final Object key, final ArtifactDescriptorRequest request )
+    {
+        final Descriptor descriptor = descriptors.get( key );
+        if ( descriptor != null )
+        {
+            return descriptor.toResult( request );
+        }
+        return null;
+    }
+
+    void putDescriptor( final Object key, final ArtifactDescriptorResult result )
+    {
+        descriptors.put( key, new Descriptor( result ) );
+    }
+
+    Object toKey( final VersionRangeRequest request )
+    {
+        return new ConstraintKey( request );
+    }
+
+    VersionRangeResult getConstraint( final Object key, final VersionRangeRequest request )
+    {
+        final Constraint constraint = constraints.get( key );
+        if ( constraint != null )
+        {
+            return constraint.toResult( request );
+        }
+        return null;
+    }
+
+    void putConstraint( final Object key, final VersionRangeResult result )
+    {
+        constraints.put( key, new Constraint( result ) );
+    }
+
+    Object toKey( final Artifact artifact, final List<RemoteRepository> repositories )
+    {
+        return new NodeKey( artifact, repositories );
+    }
+
+    Object toKey( final Artifact artifact, final List<RemoteRepository> repositories,
+                  final DependencySelector selector, final DependencyManager manager,
+                  final DependencyTraverser traverser )
+    {
+        return new GraphKey( artifact, repositories, selector, manager, traverser );
+    }
+
+    static class Descriptor
+    {
+
+        final Artifact artifact;
+
+        final Map<String, Object> properties;
+
+        final List<Artifact> relocations;
+
+        final List<RemoteRepository> repositories;
+
+        final List<Dependency> dependencies;
+
+        final List<Dependency> managedDependencies;
+
+        public Descriptor( final ArtifactDescriptorResult result )
+        {
+            artifact = result.getArtifact();
+            properties = result.getProperties();
+            relocations = result.getRelocations();
+            dependencies = result.getDependencies();
+            managedDependencies = result.getManagedDependencies();
+            repositories = clone( result.getRepositories() );
+        }
+
+        public ArtifactDescriptorResult toResult( final ArtifactDescriptorRequest request )
+        {
+            final ArtifactDescriptorResult result = new ArtifactDescriptorResult( request );
+            result.setArtifact( artifact );
+            result.setProperties( properties );
+            result.setRelocations( relocations );
+            result.setDependencies( dependencies );
+            result.setManagedDependencies( dependencies );
+            result.setRepositories( clone( repositories ) );
+            return result;
+        }
+
+        private static List<RemoteRepository> clone( final List<RemoteRepository> repositories )
+        {
+            final List<RemoteRepository> clones = new ArrayList<RemoteRepository>( repositories.size() );
+            for ( final RemoteRepository repository : repositories )
+            {
+                final RemoteRepository clone = new RemoteRepository( repository );
+                clone.setMirroredRepositories( new ArrayList<RemoteRepository>( repository.getMirroredRepositories() ) );
+                clones.add( clone );
+            }
+            return clones;
+        }
+
+    }
+
+    static class Constraint
+    {
+
+        final Map<Version, ArtifactRepository> repositories;
+
+        final VersionConstraint versionConstraint;
+
+        public Constraint( final VersionRangeResult result )
+        {
+            versionConstraint = result.getVersionConstraint();
+            repositories = new LinkedHashMap<Version, ArtifactRepository>();
+            for ( final Version version : result.getVersions() )
+            {
+                repositories.put( version, result.getRepository( version ) );
+            }
+        }
+
+        public VersionRangeResult toResult( final VersionRangeRequest request )
+        {
+            final VersionRangeResult result = new VersionRangeResult( request );
+            for ( final Map.Entry<Version, ArtifactRepository> entry : repositories.entrySet() )
+            {
+                result.addVersion( entry.getKey() );
+                result.setRepository( entry.getKey(), entry.getValue() );
+            }
+            result.setVersionConstraint( versionConstraint );
+            return result;
+        }
+
+    }
+
+    static class ConstraintKey
+    {
+
+        private final Artifact artifact;
+
+        private final List<RemoteRepository> repositories;
+
+        private final int hashCode;
+
+        public ConstraintKey( final VersionRangeRequest request )
+        {
+            artifact = request.getArtifact();
+            repositories = request.getRepositories();
+            hashCode = artifact.hashCode();
+        }
+
+        @Override
+        public boolean equals( final Object obj )
+        {
+            if ( obj == this )
+            {
+                return true;
+            }
+            else if ( !( obj instanceof ConstraintKey ) )
+            {
+                return false;
+            }
+            final ConstraintKey that = (ConstraintKey) obj;
+            return artifact.equals( that.artifact ) && equals( repositories, that.repositories );
+        }
+
+        private static boolean equals( final Collection<RemoteRepository> repos1,
+                                       final Collection<RemoteRepository> repos2 )
+        {
+            if ( repos1.size() != repos2.size() )
+            {
+                return false;
+            }
+            for ( Iterator<RemoteRepository> it1 = repos1.iterator(), it2 = repos2.iterator(); it1.hasNext(); )
+            {
+                final RemoteRepository repo1 = it1.next();
+                final RemoteRepository repo2 = it2.next();
+                if ( repo1.isRepositoryManager() != repo2.isRepositoryManager() )
+                {
+                    return false;
+                }
+                if ( repo1.isRepositoryManager() )
+                {
+                    if ( !equals( repo1.getMirroredRepositories(), repo2.getMirroredRepositories() ) )
+                    {
+                        return false;
+                    }
+                }
+                else if ( !repo1.getUrl().equals( repo2.getUrl() ) )
+                {
+                    return false;
+                }
+                else if ( repo1.getPolicy( true ).isEnabled() != repo2.getPolicy( true ).isEnabled() )
+                {
+                    return false;
+                }
+                else if ( repo1.getPolicy( false ).isEnabled() != repo2.getPolicy( false ).isEnabled() )
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode()
+        {
+            return hashCode;
+        }
+
+    }
+
+    static class NodeKey
+    {
+
+        private final Artifact artifact;
+
+        private final List<RemoteRepository> repositories;
+
+        private final int hashCode;
+
+        public NodeKey( final Artifact artifact, final List<RemoteRepository> repositories )
+        {
+            this.artifact = artifact;
+            this.repositories = repositories;
+
+            int hash = 17;
+            hash = hash * 31 + artifact.hashCode();
+            hash = hash * 31 + repositories.hashCode();
+            hashCode = hash;
+        }
+
+        @Override
+        public boolean equals( final Object obj )
+        {
+            if ( obj == this )
+            {
+                return true;
+            }
+            else if ( !( obj instanceof NodeKey ) )
+            {
+                return false;
+            }
+            final NodeKey that = (NodeKey) obj;
+            return artifact.equals( that.artifact ) && repositories.equals( that.repositories );
+        }
+
+        @Override
+        public int hashCode()
+        {
+            return hashCode;
+        }
+
+    }
+
+    static class GraphKey
+    {
+
+        private final Artifact artifact;
+
+        private final List<RemoteRepository> repositories;
+
+        private final DependencySelector selector;
+
+        private final DependencyManager manager;
+
+        private final DependencyTraverser traverser;
+
+        private final int hashCode;
+
+        public GraphKey( final Artifact artifact, final List<RemoteRepository> repositories,
+                         final DependencySelector selector, final DependencyManager manager,
+                         final DependencyTraverser traverser )
+        {
+            this.artifact = artifact;
+            this.repositories = repositories;
+            this.selector = selector;
+            this.manager = manager;
+            this.traverser = traverser;
+
+            int hash = 17;
+            hash = hash * 31 + artifact.hashCode();
+            hash = hash * 31 + repositories.hashCode();
+            hash = hash * 31 + selector.hashCode();
+            hash = hash * 31 + manager.hashCode();
+            hash = hash * 31 + traverser.hashCode();
+            hashCode = hash;
+        }
+
+        @Override
+        public boolean equals( final Object obj )
+        {
+            if ( obj == this )
+            {
+                return true;
+            }
+            else if ( !( obj instanceof GraphKey ) )
+            {
+                return false;
+            }
+            final GraphKey that = (GraphKey) obj;
+            return artifact.equals( that.artifact ) && repositories.equals( that.repositories )
+                && selector.equals( that.selector ) && manager.equals( that.manager )
+                && traverser.equals( that.traverser );
+        }
+
+        @Override
+        public int hashCode()
+        {
+            return hashCode;
+        }
+
+    }
+
+    static final class ObjectPool<K, V>
+    {
+
+        private final Map<K, WeakReference<V>> objects = new WeakHashMap<K, WeakReference<V>>( 256 );
+
+        synchronized V intern( final K id, final V object )
+        {
+            final WeakReference<V> pooledRef = objects.get( id );
+            if ( pooledRef != null )
+            {
+                final V pooled = pooledRef.get();
+                if ( pooled != null )
+                {
+                    return pooled;
+                }
+            }
+
+            objects.put( id, new WeakReference<V>( object ) );
+            return object;
+        }
+
+        void set( final K id, final V object )
+        {
+            objects.put( id, new WeakReference<V>( object ) );
+        }
+
+        V get( final K id )
+        {
+            final WeakReference<V> ref = objects.get( id );
+            return ref == null ? null : ref.get();
+        }
+
+    }
+
+}

Propchange: maven/sandbox/trunk/mae/mae-components/mae-dependency-grapher/src/main/java/org/apache/maven/mae/depgraph/impl/collect/DepGraphCache.java
------------------------------------------------------------------------------
    svn:eol-style = native