/*******************************************************************************
* 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.net.URL;
import org.eclipse.virgo.nano.deployer.api.core.DeployerLogEvents;
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.environment.InstallEnvironment;
import org.eclipse.virgo.kernel.install.pipeline.stage.transform.Transformer;
import org.eclipse.virgo.util.common.GraphNode;
import org.eclipse.virgo.util.common.GraphNode.ExceptionThrowingDirectedAcyclicGraphVisitor;
import org.eclipse.virgo.util.osgi.manifest.BundleManifest;
/**
* {@link ManifestUpgrader} upgrades OSGi R3 manifests to be R4.1 compliant as this the minimum required to enable
* scoping.
* <p />
*
* <strong>Concurrent Semantics</strong><br />
*
* This class is thread safe.
*
*/
public class ManifestUpgrader implements Transformer {
private static final int BUNDLE_MANIFEST_VERSION_FOR_OSGI_R4 = 2;
/**
* {@inheritDoc}
*/
public void transform(GraphNode<InstallArtifact> installGraph, final InstallEnvironment installEnvironment) throws DeploymentException {
installGraph.visit(new ExceptionThrowingDirectedAcyclicGraphVisitor<InstallArtifact, DeploymentException>() {
public boolean visit(GraphNode<InstallArtifact> graph) throws DeploymentException {
operate(graph.getValue(), installEnvironment);
return true;
}
});
}
void operate(InstallArtifact installArtifact, InstallEnvironment installEnvironment) throws DeploymentException {
if (installArtifact instanceof BundleInstallArtifact) {
BundleManifest bundleManifest = getBundleManifest(installArtifact, installEnvironment);
upgradeManifestIfNecessary(bundleManifest, installArtifact, installEnvironment);
validateManifest(bundleManifest, installArtifact, installEnvironment);
removeBundleUpdateLocation(installArtifact, installEnvironment, bundleManifest);
}
}
private BundleManifest getBundleManifest(InstallArtifact installArtifact, InstallEnvironment installEnvironment) throws DeploymentException {
try {
return ((BundleInstallArtifact) installArtifact).getBundleManifest();
} catch (IOException e) {
installEnvironment.getInstallLog().log(DeployerLogEvents.BUNDLE_MANIFEST_NOT_FOUND, e, installArtifact.getName(), installArtifact.getVersion());
throw new DeploymentException("I/O error accessing bundle manifest for " + installArtifact, e);
}
}
/**
* Upgrade the bundle manifest version to OSGi R4 if it is older. Do not issue a log message to avoid flooding the
* log.
*
* This upgrade is necessary to support application scoping.
*
* @param bundleManifest The manifest to upgrade
* @throws DeploymentException
*/
private void upgradeManifestIfNecessary(BundleManifest bundleManifest, InstallArtifact installArtifact, InstallEnvironment installEnvironment) {
if (bundleManifest.getBundleManifestVersion() < BUNDLE_MANIFEST_VERSION_FOR_OSGI_R4) {
installEnvironment.getInstallLog().log(this, "OSGi R3 or earlier manifest detected:\n'%s'\nfor %s - upgrading manifest to OSGi R4.",
bundleManifest.toString(), installArtifact.toString());
bundleManifest.setBundleManifestVersion(BUNDLE_MANIFEST_VERSION_FOR_OSGI_R4);
if (bundleManifest.getBundleSymbolicName().getSymbolicName() == null) {
bundleManifest.getBundleSymbolicName().setSymbolicName(installArtifact.getName());
}
}
}
private void validateManifest(BundleManifest bundleManifest, InstallArtifact installArtifact, InstallEnvironment installEnvironment)
throws DeploymentException {
if (bundleManifest.getBundleSymbolicName().getSymbolicName() == null) {
installEnvironment.getInstallLog().log(DeployerLogEvents.MISSING_BUNDLE_SYMBOLIC_NAME, installArtifact.getName(),
installArtifact.getVersion(), bundleManifest);
throw new DeploymentException("OSGi R4 manifest with no bundle symbolic name detected:\n" + bundleManifest + "'\nfor module '" + this
+ "'.");
}
}
/**
* Remove any bundle update location header to avoid it interfering with refresh.
*/
private void removeBundleUpdateLocation(InstallArtifact installArtifact, InstallEnvironment installEnvironment, BundleManifest bundleManifest) {
URL bundleUpdateLocation = bundleManifest.getBundleUpdateLocation();
if (bundleUpdateLocation != null) {
installEnvironment.getInstallLog().log(DeployerLogEvents.DISCARDING_BUNDLE_UPDATE_LOCATION, bundleUpdateLocation,
installArtifact.getName(), installArtifact.getVersion().toString());
bundleManifest.setBundleUpdateLocation(null);
}
}
}