All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.maven.graph.effective.EProjectWeb Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright 2012 John Casey
 * 
 * Licensed 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.graph.effective;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.apache.maven.graph.common.ref.ArtifactRef;
import org.apache.maven.graph.common.ref.ProjectVersionRef;
import org.apache.maven.graph.effective.rel.AbstractProjectRelationship;
import org.apache.maven.graph.effective.rel.DependencyRelationship;
import org.apache.maven.graph.effective.rel.ProjectRelationship;
import org.apache.maven.graph.effective.rel.RelationshipComparator;
import org.apache.maven.graph.effective.rel.RelationshipPathComparator;
import org.apache.maven.graph.effective.traverse.ProjectNetTraversal;

import edu.uci.ics.jung.graph.DirectedGraph;
import edu.uci.ics.jung.graph.DirectedSparseMultigraph;
import edu.uci.ics.jung.graph.util.Graphs;

public class EProjectWeb
    implements EProjectNet, Serializable
{

    private static final long serialVersionUID = 1L;

    private transient Set incompleteSubgraphs = new HashSet();

    private transient Set connectedProjects = new HashSet();

    private transient Set variableSubgraphs = new HashSet();

    private transient Set cycles = new HashSet();

    private final DirectedGraph> graph =
        new DirectedSparseMultigraph>();

    public EProjectWeb()
    {
    }

    public EProjectWeb( final Collection> relationships,
                        final Collection projectRelationships )
    {
        addAll( relationships );
        for ( final EProjectRelationships project : projectRelationships )
        {
            add( project );
        }
    }

    public EProjectWeb( final Set> relationships )
    {
        addAll( relationships );
    }

    /* (non-Javadoc)
     * @see org.apache.maven.graph.effective.EProjectNetwork#getAllRelationships()
     */
    public Set> getAllRelationships()
    {
        return new HashSet>( graph.getEdges() );
    }

    /* (non-Javadoc)
     * @see org.apache.maven.graph.effective.EProjectNetwork#getRawGraph()
     */
    public DirectedGraph> getRawGraph()
    {
        return Graphs.unmodifiableDirectedGraph( graph );
    }

    /* (non-Javadoc)
     * @see org.apache.maven.graph.effective.EProjectNetwork#isComplete()
     */
    public boolean isComplete()
    {
        return incompleteSubgraphs.isEmpty();
    }

    /* (non-Javadoc)
     * @see org.apache.maven.graph.effective.EProjectNetwork#isConcrete()
     */
    public boolean isConcrete()
    {
        return variableSubgraphs.isEmpty();
    }

    /* (non-Javadoc)
     * @see org.apache.maven.graph.effective.EProjectNetwork#getIncompleteSubgraphs()
     */
    public Set getIncompleteSubgraphs()
    {
        return Collections.unmodifiableSet( incompleteSubgraphs );
    }

    /* (non-Javadoc)
     * @see org.apache.maven.graph.effective.EProjectNetwork#getVariableSubgraphs()
     */
    public Set getVariableSubgraphs()
    {
        return Collections.unmodifiableSet( variableSubgraphs );
    }

    /* (non-Javadoc)
     * @see org.apache.maven.graph.effective.EProjectNetwork#add(org.apache.maven.graph.effective.EProjectRelationships)
     */
    public void add( final EProjectRelationships rels )
    {
        if ( incompleteSubgraphs.contains( rels.getProjectRef() ) )
        {
            incompleteSubgraphs.remove( rels.getProjectRef() );
        }

        connectedProjects.add( rels.getProjectRef() );

        addAll( rels.getAllRelationships() );
    }

    public > void add( final T rel )
    {
        if ( rel == null )
        {
            return;
        }

        incompleteSubgraphs.remove( rel.getDeclaring() );

        ProjectVersionRef target = rel.getTarget();
        if ( rel instanceof DependencyRelationship )
        {
            target = ( (ArtifactRef) target ).asProjectVersionRef();
        }

        if ( !graph.containsVertex( target ) )
        {
            graph.addVertex( target );
        }

        graph.addEdge( rel, rel.getDeclaring(), target );

        if ( !target.getVersionSpec()
                    .isSingle() )
        {
            variableSubgraphs.add( target );
        }
        else if ( !connectedProjects.contains( target ) )
        {
            incompleteSubgraphs.add( target );
        }
    }

    public > void addAll( final Collection rels )
    {
        if ( rels == null )
        {
            return;
        }

        for ( final T rel : rels )
        {
            add( rel );
        }

        recomputeIncompleteSubgraphs();
    }

    public > void addAll( final T... rels )
    {
        if ( rels == null )
        {
            return;
        }

        for ( final T rel : rels )
        {
            add( rel );
        }

        recomputeIncompleteSubgraphs();
    }

    /* (non-Javadoc)
     * @see org.apache.maven.graph.effective.EProjectNetwork#connect(org.apache.maven.graph.effective.EProjectWeb)
     */
    public void connect( final EProjectWeb otherWeb )
    {
        final DirectedGraph> otherGraph = otherWeb.getRawGraph();
        final Collection otherNodes = otherGraph.getVertices();
        for ( final ProjectVersionRef node : otherNodes )
        {
            final Collection> outEdges = otherGraph.getOutEdges( node );
            if ( incompleteSubgraphs.contains( node ) && outEdges != null && !outEdges.isEmpty() )
            {
                incompleteSubgraphs.remove( node );
            }
        }

        final Set otherIncomplete = otherWeb.getIncompleteSubgraphs();
        for ( final ProjectVersionRef node : otherIncomplete )
        {
            if ( incompleteSubgraphs.contains( node ) )
            {
                continue;
            }

            if ( graph.containsVertex( node ) )
            {
                final Collection> outEdges = graph.getOutEdges( node );
                if ( outEdges == null || outEdges.isEmpty() )
                {
                    incompleteSubgraphs.add( node );
                }
            }
            else
            {
                incompleteSubgraphs.add( node );
            }
        }

        this.connectedProjects.addAll( otherWeb.connectedProjects );
        addAll( otherWeb.getAllRelationships() );
    }

    /* (non-Javadoc)
     * @see org.apache.maven.graph.effective.EProjectNetwork#traverse(org.apache.maven.graph.common.ref.ProjectVersionRef, org.apache.maven.graph.effective.traverse.ProjectGraphTraversal)
     */
    public void traverse( final ProjectVersionRef start, final ProjectNetTraversal traversal )
    {
        final int passes = traversal.getRequiredPasses();
        for ( int i = 0; i < passes; i++ )
        {
            traversal.startTraverse( i, this );

            switch ( traversal.getType( i ) )
            {
                case breadth_first:
                {
                    bfsTraverse( start, traversal, i );
                    break;
                }
                case depth_first:
                {
                    dfsTraverse( start, traversal, i );
                    break;
                }
            }

            traversal.endTraverse( i, this );
        }
    }

    // TODO: Implement without recursion.
    private void dfsTraverse( final ProjectVersionRef start, final ProjectNetTraversal traversal, final int pass )
    {
        dfsIterate( start, traversal, new LinkedList>(), pass );
    }

    private void dfsIterate( final ProjectVersionRef node, final ProjectNetTraversal traversal,
                             final LinkedList> path, final int pass )
    {
        final List> edges = getSortedOutEdges( node );
        if ( edges != null )
        {
            for ( final ProjectRelationship edge : edges )
            {
                if ( traversal.traverseEdge( edge, path, pass ) )
                {
                    path.addLast( edge );

                    ProjectVersionRef target = edge.getTarget();
                    if ( target instanceof ArtifactRef )
                    {
                        target = ( (ArtifactRef) target ).asProjectVersionRef();
                    }

                    dfsIterate( target, traversal, path, pass );
                    path.removeLast();

                    traversal.edgeTraversed( edge, path, pass );
                }
            }
        }
    }

    // TODO: Implement without recursion.
    private void bfsTraverse( final ProjectVersionRef start, final ProjectNetTraversal traversal, final int pass )
    {
        final List> path = new ArrayList>();
        path.add( new SelfEdge( start ) );

        bfsIterate( Collections.singletonList( path ), traversal, pass );
    }

    private void bfsIterate( final List>> thisLayer, final ProjectNetTraversal traversal,
                             final int pass )
    {
        final List>> nextLayer = new ArrayList>>();

        for ( final List> path : thisLayer )
        {
            ProjectVersionRef node = path.get( path.size() - 1 )
                                         .getTarget();
            if ( node instanceof ArtifactRef )
            {
                node = ( (ArtifactRef) node ).asProjectVersionRef();
            }

            if ( !path.isEmpty() && ( path.get( 0 ) instanceof SelfEdge ) )
            {
                path.remove( 0 );
            }

            final List> edges = getSortedOutEdges( node );
            if ( edges != null )
            {
                for ( final ProjectRelationship edge : edges )
                {
                    if ( ( edge instanceof SelfEdge ) || traversal.traverseEdge( edge, path, pass ) )
                    {
                        final List> nextPath = new ArrayList>( path );

                        nextPath.add( edge );
                        nextLayer.add( nextPath );

                        traversal.edgeTraversed( edge, path, pass );
                    }
                }
            }
        }

        if ( !nextLayer.isEmpty() )
        {
            Collections.sort( nextLayer, new RelationshipPathComparator() );
            bfsIterate( nextLayer, traversal, pass );
        }
    }

    private List> getSortedOutEdges( final ProjectVersionRef node )
    {
        final Collection> unsorted = graph.getOutEdges( node );
        if ( unsorted != null )
        {
            final List> sorted = new ArrayList>( unsorted );
            Collections.sort( sorted, new RelationshipComparator() );

            return sorted;
        }

        return null;
    }

    private static final class SelfEdge
        extends AbstractProjectRelationship
    {

        private static final long serialVersionUID = 1L;

        SelfEdge( final ProjectVersionRef ref )
        {
            super( null, ref, ref, 0 );
        }

        @Override
        public ArtifactRef getTargetArtifact()
        {
            return new ArtifactRef( getTarget(), "pom", null, false );
        }

    }

    public Set> getUserRelationships( final ProjectVersionRef ref )
    {
        if ( !graph.containsVertex( ref ) )
        {
            return Collections.emptySet();
        }

        return new HashSet>( graph.getInEdges( ref ) );
    }

    public Set> getDirectRelationships( final ProjectVersionRef ref )
    {
        if ( !graph.containsVertex( ref ) )
        {
            return Collections.emptySet();
        }

        return new HashSet>( graph.getOutEdges( ref ) );
    }

    public Set getRoots()
    {
        final Set result = new HashSet();
        for ( final ProjectVersionRef ref : graph.getVertices() )
        {
            final Collection> inEdges = graph.getInEdges( ref );
            if ( inEdges == null || inEdges.isEmpty() )
            {
                result.add( ref );
            }
        }

        return result;
    }

    private void readObject( final java.io.ObjectInputStream in )
        throws IOException, ClassNotFoundException
    {
        in.defaultReadObject();
        incompleteSubgraphs = new HashSet();
        connectedProjects = new HashSet();
        variableSubgraphs = new HashSet();
    }

    public void recomputeIncompleteSubgraphs()
    {
        for ( final ProjectVersionRef vertex : graph.getVertices() )
        {
            incompleteSubgraphs.remove( vertex );
        }
    }

    public Set> getExactAllRelationships()
    {
        return getAllRelationships();
    }

    public boolean isCycleParticipant( final ProjectVersionRef ref )
    {
        for ( final EProjectCycle cycle : cycles )
        {
            if ( cycle.contains( ref ) )
            {
                return true;
            }
        }

        return false;
    }

    public boolean isCycleParticipant( final ProjectRelationship rel )
    {
        for ( final EProjectCycle cycle : cycles )
        {
            if ( cycle.contains( rel ) )
            {
                return true;
            }
        }

        return false;
    }

    public void addCycle( final EProjectCycle cycle )
    {
        this.cycles.add( cycle );
    }

    public Set getCycles()
    {
        return new HashSet( cycles );
    }

    public Set> getRelationshipsTargeting( final ProjectVersionRef ref )
    {
        final Collection> rels = graph.getInEdges( ref );
        if ( rels == null )
        {
            return null;
        }

        return new HashSet>( rels );
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy