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.io.IOUtils; import org.commonjava.cartographer.CartoDataException; import org.commonjava.cartographer.graph.GraphResolver; import org.commonjava.cartographer.graph.RecipeResolver; import org.commonjava.cartographer.graph.RepoContentCollector; import org.commonjava.cartographer.graph.agg.ProjectRefCollection; import org.commonjava.cartographer.spi.graph.discover.DiscoverySourceManager; import org.commonjava.cartographer.spi.graph.discover.ProjectRelationshipDiscoverer; import org.commonjava.cartographer.graph.fn.MultiGraphFunction; import org.commonjava.cartographer.ops.ResolveOps; import org.commonjava.cdi.util.weft.ExecutorConfig; import org.commonjava.cdi.util.weft.WeftManaged; import org.commonjava.cartographer.graph.RelationshipGraph; import org.commonjava.cartographer.graph.ViewParams; import org.commonjava.cartographer.graph.filter.AnyFilter; import org.commonjava.maven.atlas.graph.rel.ProjectRelationship; import org.commonjava.maven.atlas.ident.ref.ArtifactRef; import org.commonjava.maven.atlas.ident.ref.ProjectVersionRef; import org.commonjava.maven.atlas.ident.util.JoinString; import org.commonjava.cartographer.CartoRequestException; import org.commonjava.cartographer.graph.discover.DiscoveryConfig; import org.commonjava.cartographer.request.RepositoryContentRequest; import org.commonjava.maven.galley.maven.ArtifactManager; import org.commonjava.maven.galley.maven.parse.MavenPomReader; import org.commonjava.maven.galley.model.ConcreteResource; import org.commonjava.maven.galley.model.Location; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import java.net.URI; import java.util.*; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import static org.commonjava.cartographer.INTERNAL.graph.agg.AggregationUtils.collectProjectVersionReferences; @ApplicationScoped public class ResolveOpsImpl implements ResolveOps { private final Logger logger = LoggerFactory.getLogger(getClass()); @Inject private GraphResolver resolver; @Inject private DiscoverySourceManager sourceManager; @Inject private ProjectRelationshipDiscoverer discoverer; @Inject private ArtifactManager artifacts; @Inject protected MavenPomReader pomReader; @Inject private RecipeResolver recipeResolver; @Inject @WeftManaged @ExecutorConfig(daemon = true, named = "carto-graph-ops", priority = 9, threads = 16) private ExecutorService executor; protected ResolveOpsImpl() { } public ResolveOpsImpl(final DiscoverySourceManager sourceManager, final ProjectRelationshipDiscoverer discoverer, final ArtifactManager artifacts, final ExecutorService executor, final RecipeResolver dtoResolver, GraphResolver resolver) { this.sourceManager = sourceManager; this.discoverer = discoverer; this.artifacts = artifacts; this.executor = executor; this.recipeResolver = dtoResolver; this.resolver = resolver; } @Override public Map<ProjectVersionRef, Map<ArtifactRef, ConcreteResource>> resolveRepositoryContents( final RepositoryContentRequest recipe) throws CartoDataException, CartoRequestException { recipeResolver.resolve(recipe); if (recipe == null || !recipe.isValid()) { throw new CartoDataException("Repository content request is invalid: {}", recipe); } final URI sourceUri = sourceManager.createSourceURI(recipe.getSourceLocation().getUri()); if (sourceUri == null) { throw new CartoDataException("Invalid source format: '{}'. Use the form: '{}' instead.", recipe.getSourceLocation(), sourceManager.getFormatHint()); } // FIXME: lambdas... final Map<ProjectVersionRef, ProjectRefCollection> refMap = resolveReferenceMap(recipe); final List<RepoContentCollector> collectors = collectContent(refMap, recipe); final Map<ProjectVersionRef, Map<ArtifactRef, ConcreteResource>> itemMap = new HashMap<>(); for (final RepoContentCollector collector : collectors) { final Map<ArtifactRef, ConcreteResource> items = collector.getItems(); if (items != null && !items.isEmpty()) { logger.debug("{} Returning for: {}\n\n {}", collector, collector.getRef(), new JoinString("\n ", items.entrySet())); Map<ArtifactRef, ConcreteResource> existingItems = itemMap.get(collector.getRef()); if (existingItems == null) { itemMap.put(collector.getRef(), items); existingItems = items; } else { existingItems.putAll(items); } logger.debug("{} Accumulated for: {}\n\n {}", collector, collector.getRef(), new JoinString("\n ", existingItems.entrySet())); } else { logger.warn("{} No items returned for: {}", collector, collector.getRef()); } } return itemMap; } private List<RepoContentCollector> collectContent(final Map<ProjectVersionRef, ProjectRefCollection> refMap, final RepositoryContentRequest recipe) throws CartoDataException, CartoRequestException { final Location location = recipe.getSourceLocation(); final Set<Location> excluded = recipe.getExcludedSourceLocations(); if (excluded != null && excluded.contains(location)) { // no sense in going through all the rest if everything is excluded... throw new CartoDataException( "RepositoryContentRequest is insane! Source location is among those excluded!"); } int projectCounter = 1; final int projectSz = refMap.size(); final List<RepoContentCollector> collectors = new ArrayList<>(projectSz); final DiscoveryConfig dconf = recipe.getDiscoveryConfig(); for (final Map.Entry<ProjectVersionRef, ProjectRefCollection> entry : refMap.entrySet()) { final ProjectVersionRef ref = entry.getKey(); final ProjectRefCollection refs = entry.getValue(); final RepoContentCollector collector = new RepoContentCollector(ref, refs, recipe, location, dconf, artifacts, discoverer, excluded, projectCounter, projectSz); collectors.add(collector); projectCounter++; } final CountDownLatch latch = new CountDownLatch(collectors.size()); for (final RepoContentCollector collector : collectors) { collector.setLatch(latch); executor.execute(collector); } // TODO: timeout with loop... while (latch.getCount() > 0) { logger.info("Waiting for {} more content-collection threads to complete.", latch.getCount()); try { latch.await(2, TimeUnit.SECONDS); } catch (final InterruptedException e) { logger.error("Abandoning repo-content assembly for: {}", recipe); } } return collectors; } /** * Discover the dependency graphs for the configured graph composition, and then traverse them to construct a mapping of GAV to set of references * that can be used to render various kinds of output. If the request contains injectedBOMs, then read the managed dependencies from these into * a mapping of GA -> GAV that we can pass into the {@link ViewParams} we'll eventually use to discover and traverse the graph. * <br/> * Returns null if {@link RepositoryContentRequest#setSourceLocation(Location)} hasn't * been called before this method is called. * <br/> * @throws {@link CartoDataException} if one or more of the request's injected BOMs cannot be resolved or if an * unexpected problem takes place during graph resolution or traversal. * @throws {@link CartoRequestException} if the request doesn't contain enough basic * info to be used (See: {@link RepositoryContentRequest#isValid()}) or if the source {@link Location} hasn't been set on the request */ private Map<ProjectVersionRef, ProjectRefCollection> resolveReferenceMap(final RepositoryContentRequest recipe) throws CartoDataException, CartoRequestException { logger.info("Building repository for: {}", recipe); recipeResolver.resolve(recipe); final Map<ProjectVersionRef, ProjectRefCollection> refMap = new HashMap<>(); final MultiGraphFunction<Set<ProjectRelationship<?, ?>>> extractor = (allRels, graphMap) -> { try { refMap.putAll(collectProjectVersionReferences(allRels)); for (final RelationshipGraph graph : graphMap.values()) { for (final ProjectVersionRef root : graph.getRoots()) { ProjectRefCollection refCollection = refMap.get(root); if (refCollection == null) { refCollection = new ProjectRefCollection(); refCollection.addVersionRef(root); refMap.put(root, refCollection); } if (root instanceof ArtifactRef) { refCollection.addArtifactRef((ArtifactRef) root); } } } } finally { graphMap.values().forEach(IOUtils::closeQuietly); } }; resolver.resolveAndExtractMultiGraph(AnyFilter.INSTANCE, recipe, (allRefs, allRels, roots) -> allRels.get(), extractor); return refMap; } }