/*******************************************************************************
* Copyright (c) 2008, 2011 VMware Inc. and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VMware Inc. - initial contribution
* EclipseSource - Bug 358442 Change InstallArtifact graph from a tree to a DAG
*******************************************************************************/
package org.eclipse.virgo.kernel.deployer.core.internal;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.eclipse.virgo.nano.deployer.api.core.DeploymentException;
import org.eclipse.virgo.kernel.install.artifact.BundleInstallArtifact;
import org.eclipse.virgo.kernel.install.artifact.InstallArtifact;
import org.eclipse.virgo.kernel.install.artifact.PlanInstallArtifact;
import org.eclipse.virgo.kernel.install.environment.InstallEnvironment;
import org.eclipse.virgo.kernel.install.pipeline.stage.transform.Transformer;
import org.eclipse.virgo.kernel.install.pipeline.stage.transform.internal.BundleInstallArtifactGatheringGraphVisitor;
import org.eclipse.virgo.kernel.osgi.framework.ImportExpander;
import org.eclipse.virgo.kernel.osgi.framework.ImportMergeException;
import org.eclipse.virgo.kernel.osgi.framework.UnableToSatisfyDependenciesException;
import org.eclipse.virgo.util.common.GraphNode;
import org.eclipse.virgo.util.common.GraphNode.ExceptionThrowingDirectedAcyclicGraphVisitor;
import org.eclipse.virgo.util.osgi.manifest.BundleManifest;
/**
* {@link ImportExpandingTransformer} is a {@link Transformer} that expands Import-Library and Import-Bundle into package imports.
* Expansion of imports in bundles that are part of a scope is performed against all of the bundles at the same time.
* Expansion of bundles that are not part of a scope is performed on a bundle-by-bundle basis.
* <p />
*
* <strong>Concurrent Semantics</strong><br />
*
* Thread-safe.
*
*/
final class ImportExpandingTransformer implements Transformer {
private final ImportExpander importExpander;
ImportExpandingTransformer(ImportExpander importExpander) {
this.importExpander = importExpander;
}
/**
* {@inheritDoc}
*/
public void transform(GraphNode<InstallArtifact> installGraph, final InstallEnvironment installEnvironment) throws DeploymentException {
installGraph.visit(new ImportExpandingGraphVisitor(installEnvironment));
}
private final class ImportExpandingGraphVisitor implements ExceptionThrowingDirectedAcyclicGraphVisitor<InstallArtifact, DeploymentException> {
private final InstallEnvironment installEnvironment;
ImportExpandingGraphVisitor(InstallEnvironment installEnvironment) {
this.installEnvironment = installEnvironment;
}
/**
* {@inheritDoc}
*/
public boolean visit(GraphNode<InstallArtifact> graph) throws DeploymentException {
if (graph.getValue() instanceof PlanInstallArtifact) {
PlanInstallArtifact planInstallArtifact = (PlanInstallArtifact) graph.getValue();
if (planInstallArtifact.isScoped()) {
expandImportsOfBundlesInScopedPlan(graph, this.installEnvironment);
return false;
}
} else if (graph.getValue() instanceof BundleInstallArtifact) {
expandImports(Collections.singleton((BundleInstallArtifact) graph.getValue()), this.installEnvironment);
}
return true;
}
}
void expandImportsOfBundlesInScopedPlan(GraphNode<InstallArtifact> planGraph, InstallEnvironment installEnvironment) throws DeploymentException {
BundleInstallArtifactGatheringGraphVisitor visitor = new BundleInstallArtifactGatheringGraphVisitor();
planGraph.visit(visitor);
expandImports(visitor.getChildBundles(), installEnvironment);
}
void expandImports(Set<BundleInstallArtifact> bundleInstallArtifacts, InstallEnvironment installEnvironment) throws DeploymentException {
List<BundleManifest> bundleManifestList = new ArrayList<BundleManifest>(bundleInstallArtifacts.size());
for (BundleInstallArtifact bundleInstallArtifact : bundleInstallArtifacts) {
try {
BundleManifest bundleManifest = bundleInstallArtifact.getBundleManifest();
bundleManifestList.add(bundleManifest);
} catch (IOException e) {
installEnvironment.getInstallLog().log(this, "I/O error getting bundle manifest for %s", bundleInstallArtifact.toString());
throw new DeploymentException("I/O error getting bundle manifest for " + bundleInstallArtifact, e);
}
}
try {
this.importExpander.expandImports(bundleManifestList);
installEnvironment.getInstallLog().log(this, "Expanded imports of %s", bundleInstallArtifacts.toString());
} catch (ImportMergeException e) {
installEnvironment.getInstallLog().log(this, "Error in %s merging expanded imports for package %s from %s",
bundleInstallArtifacts.toString(), e.getConflictingPackageName(), e.getSources());
throw new DeploymentException("Error merging expanded imports for " + bundleInstallArtifacts, e);
} catch (UnableToSatisfyDependenciesException e) {
installEnvironment.getInstallLog().log(this, "Unsatisfied dependencies in %s: %s", bundleInstallArtifacts.toString(),
e.getFailureDescription());
throw new DeploymentException(e.getMessage(), e);
}
}
}