/** * Copyright (C) 2013 Red Hat, Inc. (jdcasey@commonjava.org) * * 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.commonjava.cartographer.INTERNAL.ops; import java.util.*; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import org.commonjava.cartographer.request.GraphAnalysisRequest; import org.commonjava.cartographer.request.GraphCalculation; import org.commonjava.cartographer.request.GraphDescription; import org.commonjava.cartographer.request.MultiGraphRequest; import org.commonjava.cartographer.graph.RelationshipGraph; import org.commonjava.cartographer.graph.filter.AnyFilter; import org.commonjava.maven.atlas.graph.rel.ProjectRelationship; import org.commonjava.maven.atlas.ident.ref.ProjectRef; import org.commonjava.maven.atlas.ident.ref.ProjectVersionRef; import org.commonjava.cartographer.CartoRequestException; import org.commonjava.cartographer.CartoDataException; import org.commonjava.cartographer.graph.GraphResolver; import org.commonjava.cartographer.ops.CalculationOps; import org.commonjava.cartographer.graph.MultiGraphCalculator; import org.commonjava.cartographer.graph.fn.MultiGraphFunction; import org.commonjava.cartographer.graph.fn.ValueHolder; import org.commonjava.cartographer.result.GraphDifference; @ApplicationScoped public class CalculationOpsImpl implements CalculationOps { @Inject private MultiGraphCalculator graphCalculator; @Inject private GraphResolver graphResolver; protected CalculationOpsImpl() { } public CalculationOpsImpl( final MultiGraphCalculator graphCalculator, GraphResolver graphResolver ) { this.graphCalculator = graphCalculator; this.graphResolver = graphResolver; } @Override public GraphDifference<ProjectRelationship<?, ?>> difference( final GraphAnalysisRequest request ) throws CartoDataException, CartoRequestException { List<MultiGraphRequest> requests = request.getGraphRequests(); if ( requests == null || requests.size() != 2 ) { throw new CartoRequestException( "You must specify exactly 2 graph requests to calculate a difference!" ); } MultiGraphRequest from = requests.get( 0 ); MultiGraphRequest to = requests.get( 1 ); ValueHolder<Set<ProjectRelationship<?, ?>>> fromRels = new ValueHolder<>(); ValueHolder<Set<ProjectRelationship<?, ?>>> toRels = new ValueHolder<>(); graphResolver.resolveAndExtractMultiGraph( AnyFilter.INSTANCE, from, ( allProjects, allRelationships, roots ) -> allRelationships.get(), ( elements, graphs ) -> fromRels.set( elements ) ); graphResolver.resolveAndExtractMultiGraph( AnyFilter.INSTANCE, to, ( allProjects, allRelationships, roots ) -> allRelationships.get(), ( elements, graphs ) -> toRels.set( elements ) ); final Set<ProjectRelationship<?, ?>> removed = new HashSet<>( fromRels.get() ); removed.removeAll( toRels.get() ); final Set<ProjectRelationship<?, ?>> added = new HashSet<>( toRels.get() ); added.removeAll( fromRels.get() ); return new GraphDifference<>( from, to, added, removed ); } @Override public GraphDifference<ProjectVersionRef> intersectingTargetDrift( final GraphAnalysisRequest request ) throws CartoDataException, CartoRequestException { List<MultiGraphRequest> requests = request.getGraphRequests(); if ( requests == null || requests.size() != 2 ) { throw new CartoRequestException( "You must specify exactly 2 graph requests to calculate a difference!" ); } MultiGraphRequest from = requests.get( 0 ); MultiGraphRequest to = requests.get( 1 ); ValueHolder<Map<ProjectRef, Set<ProjectVersionRef>>> fromMap = new ValueHolder<>(); ValueHolder<Map<ProjectRef, Set<ProjectVersionRef>>> toMap = new ValueHolder<>(); graphResolver.resolveAndExtractMultiGraph( AnyFilter.INSTANCE, from, ( allProjects, allRelationships, roots ) -> allProjects.get(), mapTargetsToGA( fromMap ) ); graphResolver.resolveAndExtractMultiGraph( AnyFilter.INSTANCE, to, ( allProjects, allRelationships, roots ) -> allProjects.get(), mapTargetsToGA( toMap ) ); Map<ProjectRef, Set<ProjectVersionRef>> firstAll = fromMap.get(); Map<ProjectRef, Set<ProjectVersionRef>> secondAll = toMap.get(); reduceToIntersection( firstAll, secondAll ); final Set<ProjectVersionRef> removed = new HashSet<>(); firstAll.values().stream().filter( refSet -> refSet != null ).forEach( removed::addAll ); final Set<ProjectVersionRef> added = new HashSet<>(); secondAll.values().stream().filter( refSet -> refSet != null ).forEach( added::addAll ); return new GraphDifference<>( from, to, added, removed ); } private void reduceToIntersection( final Map<ProjectRef, Set<ProjectVersionRef>> first, final Map<ProjectRef, Set<ProjectVersionRef>> second ) { new HashSet<>( first.keySet() ).stream().filter( ref -> !second.containsKey( ref ) ).forEach( first::remove ); new HashSet<>( second.keySet() ).stream().filter( ref -> !first.containsKey( ref ) ).forEach( second::remove ); } private MultiGraphFunction<Set<ProjectVersionRef>> mapTargetsToGA( ValueHolder<Map<ProjectRef, Set<ProjectVersionRef>>> value ) { final Map<ProjectRef, Set<ProjectVersionRef>> result = new HashMap<>(); value.set( result ); return ( elements, graph ) -> elements.forEach( ( ref ) -> { final ProjectRef pr = ref.asProjectRef(); Set<ProjectVersionRef> pvrs = result.get( pr ); if ( pvrs == null ) { pvrs = new HashSet<>(); result.put( pr, pvrs ); } pvrs.add( ref ); } ); } @Override public GraphCalculation calculate( final MultiGraphRequest request ) throws CartoDataException, CartoRequestException { Map<GraphDescription, RelationshipGraph> graphMap = graphResolver.resolveToGraphMap( request ); return graphCalculator.calculateFromGraphMap( request.getGraphComposition(), graphMap ); } }