Java tutorial
/** * 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 org.apache.commons.lang.StringUtils; import org.commonjava.cartographer.CartoDataException; import org.commonjava.cartographer.CartoRequestException; import org.commonjava.cartographer.graph.GraphResolver; import org.commonjava.cartographer.graph.fn.GraphFunction; import org.commonjava.cartographer.graph.fn.MatchingProjectFunction; import org.commonjava.cartographer.graph.fn.MultiGraphFunction; import org.commonjava.cartographer.graph.fn.ProjectCollector; import org.commonjava.cartographer.graph.fn.ProjectProjector; import org.commonjava.cartographer.graph.fn.ProjectSelector; import org.commonjava.cartographer.graph.fn.ValueHolder; import org.commonjava.cartographer.graph.util.CartoGraphUtils; import org.commonjava.cartographer.ops.GraphOps; import org.commonjava.cartographer.request.GraphDescription; import org.commonjava.cartographer.request.PathsRequest; import org.commonjava.cartographer.request.ProjectGraphRelationshipsRequest; import org.commonjava.cartographer.request.ProjectGraphRequest; import org.commonjava.cartographer.request.SingleGraphRequest; import org.commonjava.cartographer.result.GraphExport; import org.commonjava.cartographer.result.MappedProjectRelationships; import org.commonjava.cartographer.result.MappedProjectRelationshipsResult; import org.commonjava.cartographer.result.MappedProjectResult; import org.commonjava.cartographer.result.MappedProjects; import org.commonjava.cartographer.result.MappedProjectsResult; import org.commonjava.cartographer.result.ProjectError; import org.commonjava.cartographer.result.ProjectErrors; import org.commonjava.cartographer.result.ProjectListResult; import org.commonjava.cartographer.result.ProjectPath; import org.commonjava.cartographer.result.ProjectPathsResult; import org.commonjava.cartographer.graph.RelationshipGraph; import org.commonjava.cartographer.graph.RelationshipGraphException; import org.commonjava.cartographer.graph.filter.AnyFilter; import org.commonjava.cartographer.graph.filter.ParentFilter; import org.commonjava.cartographer.graph.filter.ProjectRelationshipFilter; import org.commonjava.maven.atlas.graph.model.EProjectCycle; import org.commonjava.maven.atlas.graph.rel.ParentRelationship; import org.commonjava.maven.atlas.graph.rel.ProjectRelationship; import org.commonjava.cartographer.graph.spi.RelationshipGraphConnectionException; import org.commonjava.cartographer.graph.spi.neo4j.io.Conversions; import org.commonjava.cartographer.graph.traverse.BuildOrderTraversal; import org.commonjava.cartographer.graph.traverse.PathsTraversal; import org.commonjava.cartographer.graph.traverse.TraversalType; import org.commonjava.cartographer.graph.traverse.model.BuildOrder; import org.commonjava.maven.atlas.ident.ref.ProjectVersionRef; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @ApplicationScoped public class GraphOpsImpl implements GraphOps { private final Logger logger = LoggerFactory.getLogger(getClass()); @Inject private GraphResolver resolver; protected GraphOpsImpl() { } public GraphOpsImpl(final GraphResolver resolver) { this.resolver = resolver; } @Override public ProjectListResult listProjects(final ProjectGraphRequest recipe) throws CartoDataException, CartoRequestException { final ProjectListResult result = new ProjectListResult(); final ProjectProjector<ProjectVersionRef> extractor = (ref, graph) -> graph.containsGraph(ref) ? ref : null; final ProjectCollector<ProjectVersionRef> consumer = (unused, ref) -> { if (ref != null) { result.addProject(ref); } }; resolver.resolveAndExtractSingleGraph(AnyFilter.INSTANCE, recipe, new MatchingProjectFunction<>(recipe, extractor, consumer)); return result; } @Override public ProjectPathsResult getPaths(final PathsRequest recipe) throws CartoDataException, CartoRequestException { // Collections.sort( paths, RelationshipPathComparator.INSTANCE ); ProjectPathsResult result = new ProjectPathsResult(); final MultiGraphFunction<Set<ProjectRelationship<?, ?>>> extractor = (allRels, graphMap) -> { for (final GraphDescription desc : graphMap.keySet()) { final RelationshipGraph graph = graphMap.get(desc); final ProjectRelationshipFilter filter = desc.filter(); final PathsTraversal paths = new PathsTraversal(recipe.buildFilter(filter), recipe.getTargets()); try { graph.traverse(paths, TraversalType.depth_first); } catch (final RelationshipGraphException ex) { throw new CartoDataException( "Failed to open / traverse the graph (for paths operation): " + ex.getMessage(), ex); } final Set<List<ProjectRelationship<?, ?>>> discoveredPaths = paths.getDiscoveredPaths(); for (final List<ProjectRelationship<?, ?>> path : discoveredPaths) { if (path == null || path.isEmpty()) { continue; } for (final ProjectRelationship<?, ?> rel : path) { if (!allRels.contains(rel)) { // continue to the next path... break; } } List<ProjectRelationship<?, ?>> detachedPath = Conversions.convertToDetachedRelationships(path); final ProjectVersionRef ref = detachedPath.get(path.size() - 1).getTarget(); result.addPath(ref, new ProjectPath(detachedPath)); } } }; resolver.resolveAndExtractMultiGraph(AnyFilter.INSTANCE, recipe, (allProjects, allRels, roots) -> allRels.get(), extractor); return result; } @Override public ProjectErrors getProjectErrors(final ProjectGraphRequest recipe) throws CartoDataException, CartoRequestException { return getAllProjectErrors(recipe); } private ProjectErrors getAllProjectErrors(final ProjectGraphRequest recipe) throws CartoDataException, CartoRequestException { final ProjectErrors result = new ProjectErrors(); final ProjectProjector<String> extractor = (ref, graph) -> { final String error = graph.getProjectError(ref); if (StringUtils.isEmpty(error)) { return null; } return error; }; final ProjectCollector<String> consumer = (ref, error) -> { if (error != null) { result.addProject(new ProjectError(ref, error)); } }; resolver.resolveAndExtractSingleGraph(AnyFilter.INSTANCE, recipe, new MatchingProjectFunction<>(recipe, extractor, consumer)); return result; } @Override public MappedProjectResult getProjectParent(final ProjectGraphRequest recipe) throws CartoDataException, CartoRequestException { MappedProjectResult result = new MappedProjectResult(); final ProjectProjector<ProjectVersionRef> extractor = (ref, graph) -> { final Set<ProjectRelationship<?, ?>> rels = graph.getDirectRelationships(ref); for (final ProjectRelationship<?, ?> rel : rels) { if (rel instanceof ParentRelationship) { return rel.getTarget(); } } return null; }; final ProjectCollector<ProjectVersionRef> consumer = result::addProject; resolver.resolveAndExtractSingleGraph(ParentFilter.EXCLUDE_TERMINAL_PARENTS, recipe, new MatchingProjectFunction<>(recipe, extractor, consumer)); return result; } @Override public MappedProjectRelationshipsResult getDirectRelationshipsFrom( final ProjectGraphRelationshipsRequest recipe) throws CartoDataException, CartoRequestException { MappedProjectRelationshipsResult result = new MappedProjectRelationshipsResult(); final ProjectProjector<Set<ProjectRelationship<?, ?>>> extractor = (ref, graph) -> { final Set<ProjectRelationship<?, ?>> rels = graph.findDirectRelationshipsFrom(ref, recipe.isManagedIncluded(), recipe.isConcreteIncluded(), recipe.toTypeArray()); return rels == null || rels.isEmpty() ? null : new HashSet<>(rels); }; final ProjectCollector<Set<ProjectRelationship<?, ?>>> consumer = (ref, rels) -> { if (rels != null) { result.addProject(new MappedProjectRelationships(ref, rels)); } }; resolver.resolveAndExtractSingleGraph(recipe.getTypeFilter(), recipe, new MatchingProjectFunction<>(recipe, extractor, consumer)); return result; } @Override public MappedProjectRelationshipsResult getDirectRelationshipsTo(final ProjectGraphRelationshipsRequest recipe) throws CartoDataException, CartoRequestException { MappedProjectRelationshipsResult result = new MappedProjectRelationshipsResult(); final ProjectProjector<Set<ProjectRelationship<?, ?>>> extractor = (ref, graph) -> { final Set<ProjectRelationship<?, ?>> rels = graph.findDirectRelationshipsTo(ref, recipe.isManagedIncluded(), recipe.isConcreteIncluded(), recipe.toTypeArray()); return rels == null || rels.isEmpty() ? null : new HashSet<>(rels); }; final ProjectCollector<Set<ProjectRelationship<?, ?>>> consumer = (ref, rels) -> { if (rels != null) { result.addProject(new MappedProjectRelationships(ref, rels)); } }; resolver.resolveAndExtractSingleGraph(recipe.getTypeFilter(), recipe, new MatchingProjectFunction<>(recipe, extractor, consumer)); return result; } @Override public ProjectListResult reindex(final ProjectGraphRequest recipe) throws CartoDataException, CartoRequestException { return doReindex(recipe); } private ProjectListResult doReindex(final ProjectGraphRequest recipe) throws CartoDataException, CartoRequestException { recipe.setResolve(false); if (recipe.getGraph().filter() == null) { recipe.getGraph().setFilter(AnyFilter.INSTANCE); } final ProjectListResult result = new ProjectListResult(); final ProjectProjector<ProjectVersionRef> extractor = (ref, graph) -> { try { graph.reindex(ref); return ref; } catch (final RelationshipGraphConnectionException e) { logger.error(String.format("Failed to re-index %s in: %s", ref, recipe.getWorkspaceId()), e); } return null; }; final ProjectCollector<ProjectVersionRef> consumer = (unused, ref) -> { if (ref != null) { result.addProject(ref); } }; resolver.resolveAndExtractSingleGraph(AnyFilter.INSTANCE, recipe, new MatchingProjectFunction<>(recipe, extractor, consumer)); return result; } @Override public ProjectListResult getIncomplete(final ProjectGraphRequest recipe) throws CartoDataException, CartoRequestException { final ProjectListResult result = new ProjectListResult(); final ProjectProjector<ProjectVersionRef> extractor = (ref, graph) -> ref; final ProjectCollector<ProjectVersionRef> consumer = (unused, ref) -> result.addProject(ref); final ProjectSelector supplier = RelationshipGraph::getIncompleteSubgraphs; resolver.resolveAndExtractSingleGraph(AnyFilter.INSTANCE, recipe, new MatchingProjectFunction<>(recipe, extractor, consumer, supplier)); return result; } @Override public ProjectListResult getVariable(final ProjectGraphRequest recipe) throws CartoDataException, CartoRequestException { final ProjectListResult result = new ProjectListResult(); final ProjectProjector<ProjectVersionRef> extractor = (ref, graph) -> ref; final ProjectCollector<ProjectVersionRef> consumer = (unused, ref) -> result.addProject(ref); final ProjectSelector supplier = RelationshipGraph::getVariableSubgraphs; resolver.resolveAndExtractSingleGraph(AnyFilter.INSTANCE, recipe, new MatchingProjectFunction<>(recipe, extractor, consumer, supplier)); return result; } @Override public MappedProjectsResult getAncestry(final ProjectGraphRequest recipe) throws CartoDataException, CartoRequestException { final MappedProjectsResult result = new MappedProjectsResult(); final ProjectProjector<List<ProjectVersionRef>> extractor = (ref, graph) -> { try { return CartoGraphUtils.getAncestry(ref, graph); } catch (final RelationshipGraphException e) { logger.error( String.format("Failed to retrieve ancestry of: %s in: %s", ref, recipe.getWorkspaceId()), e); } return Collections.emptyList(); }; final ProjectCollector<List<ProjectVersionRef>> consumer = (ref, mapped) -> result .addProject(new MappedProjects(ref, mapped)); resolver.resolveAndExtractSingleGraph(AnyFilter.INSTANCE, recipe, new MatchingProjectFunction<>(recipe, extractor, consumer)); return result; } @Override public BuildOrder getBuildOrder(final ProjectGraphRequest recipe) throws CartoDataException, CartoRequestException { final BuildOrderTraversal traversal = new BuildOrderTraversal(); final ProjectProjector<ProjectVersionRef> extractor = (ref, graph) -> { try { graph.traverse(ref, traversal, TraversalType.breadth_first); return ref; } catch (final RelationshipGraphException e) { logger.error(String.format("Failed to traverse graph: %s to discover build order for: %s", recipe.getWorkspaceId(), ref), e); } return null; }; final ProjectCollector<ProjectVersionRef> consumer = (ref, ref2) -> { }; final ProjectSelector supplier = RelationshipGraph::getRoots; resolver.resolveAndExtractSingleGraph(AnyFilter.INSTANCE, recipe, new MatchingProjectFunction<>(recipe, extractor, consumer, supplier)); return traversal.getBuildOrder(); } @Override public GraphExport exportGraph(final SingleGraphRequest recipe) throws CartoDataException, CartoRequestException { final ValueHolder<GraphExport> holder = new ValueHolder<>(); final GraphFunction extractor = (graph) -> { final Set<ProjectRelationship<?, ?>> rels = graph.getAllRelationships(); final Set<ProjectVersionRef> missing = graph.getAllIncompleteSubgraphs(); if (missing != null && missing.containsAll(recipe.getGraph().getRoots())) { holder.consumer().accept(null); } final Set<ProjectVersionRef> variable = graph.getAllVariableSubgraphs(); final Set<EProjectCycle> cycles = graph.getCycles(); final Map<ProjectVersionRef, String> errorMap = graph.getAllProjectErrors(); ProjectErrors errors = new ProjectErrors(); for (ProjectVersionRef key : errorMap.keySet()) { errors.addProject(new ProjectError(key, errorMap.get(key))); } holder.consumer().accept(new GraphExport(rels, missing, variable, errors, cycles)); }; resolver.resolveAndExtractSingleGraph(AnyFilter.INSTANCE, recipe, extractor); return holder.get(); } }