blob: 51d233a6b331f248f80791e34827a633b8845c2c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012 SAP AG
* 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:
* SAP AG - initial contribution
*******************************************************************************/
package org.eclipse.virgo.nano.deployer.internal;
import static java.lang.Integer.parseInt;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.eclipse.virgo.medic.eventlog.EventLogger;
import org.eclipse.virgo.nano.core.KernelConfig;
import org.eclipse.virgo.nano.deployer.NanoDeployerLogEvents;
import org.eclipse.virgo.nano.deployer.SimpleDeployer;
import org.eclipse.virgo.nano.deployer.api.core.ApplicationDeployer;
import org.eclipse.virgo.nano.deployer.api.core.DeployerConfiguration;
import org.eclipse.virgo.nano.deployer.api.core.DeploymentIdentity;
import org.eclipse.virgo.nano.deployer.api.core.DeploymentOptions;
import org.eclipse.virgo.nano.deployer.support.HotDeployerEnabler;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Version;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
import org.osgi.service.packageadmin.PackageAdmin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class StandardApplicationDeployer implements ApplicationDeployer {
private static final String TOPIC_RECOVERY_COMPLETED = "org/eclipse/virgo/kernel/deployer/recovery/COMPLETED";
private EventLogger eventLogger;
private PackageAdmin packageAdmin;
private final List<SimpleDeployer> simpleDeployers = new ArrayList<>();
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private KernelConfig kernelConfig;
private HotDeployerEnabler hotDeployerEnabler = null;
private BundleContext bundleContext;
private BundleDeployer defaultDeployer;
private EventAdmin eventAdmin;
public void activate(ComponentContext context) {
this.bundleContext = context.getBundleContext();
this.defaultDeployer = new BundleDeployer(context.getBundleContext(), this.packageAdmin, this.eventLogger);
this.simpleDeployers.add(this.defaultDeployer);
recoveryComplete();
initialiseHotDeployer();
// TODO register the deployer MBean when the management classes are factored out in a new bundle.
// Deployer deployerMBean = new StandardDeployer(appDeployer);
}
public void deactivate(ComponentContext context) {
if (this.hotDeployerEnabler != null) {
this.hotDeployerEnabler.stopHotDeployer();
}
}
private void initialiseHotDeployer() {
int deployerTimeout = parseInt(this.kernelConfig.getProperty("deployer.timeout"));
String pickupDirectory = this.kernelConfig.getProperty("deployer.pickupDirectory");
int scanInterval = parseInt(this.kernelConfig.getProperty("deployer.scanIntervalMillis"));
DeployerConfiguration deployerConfiguration = new StandardDeployerConfiguration(deployerTimeout, new File(pickupDirectory), scanInterval);
this.hotDeployerEnabler = new HotDeployerEnabler(this, deployerConfiguration, this.eventLogger);
this.hotDeployerEnabler.startHotDeployer();
}
@Override
public DeploymentIdentity deploy(URI uri) {
boolean isThereSuitableDeployer = false;
for (SimpleDeployer deployer : this.simpleDeployers) {
if (deployer.canServeFileType(getFileTypeFromUri(uri))) {
isThereSuitableDeployer = true;
if (!deployer.isDeployFileValid(new File(uri))) {
this.eventLogger.log(NanoDeployerLogEvents.NANO_INVALID_FILE);
} else {
if (deployer.isDeployed(uri)) {
deployer.update(uri);
} else {
deployer.deploy(uri);
}
}
}
}
if (!isThereSuitableDeployer) {
handleUnsupportedFileType(uri);
}
return null;
}
@Override
public DeploymentIdentity[] bulkDeploy(List<URI> uris, DeploymentOptions options) {
if (uris != null && !uris.isEmpty()) {
installDeployables(uris);
startDeployables(uris);
return getDeploymentIdentities(uris);
} else {
this.logger.warn("Cannot perform bulk deploy operation of the given URIs list as it is either empty or null.");
return null;
}
}
private DeploymentIdentity[] getDeploymentIdentities(List<URI> uris) {
List<DeploymentIdentity> accumulatedDIs = new ArrayList<>();
for (URI uri : uris) {
DeploymentIdentity di = getDeploymentIdentity(uri);
if (di != null) {
accumulatedDIs.add(di);
}
}
return accumulatedDIs.toArray(new DeploymentIdentity[0]);
}
@Override
public void undeploy(DeploymentIdentity deploymentIdentity) {
if (this.bundleContext != null) {
String symbolicName = deploymentIdentity.getSymbolicName();
String version = deploymentIdentity.getVersion();
List<Bundle> existingBundles = new ArrayList<>();
for (Bundle bundle : this.bundleContext.getBundles()) {
if (bundle.getSymbolicName().equals(symbolicName) && bundle.getVersion().toString().equals(version)) {
existingBundles.add(bundle);
}
}
if (existingBundles.size() > 1) {
this.logger.warn("Multiple bundles matching the marked for uninstall symbolicName-version pair. List of all matches: "
+ Arrays.toString(existingBundles.toArray(new Bundle[0])));
this.logger.warn("Uninstalling the last-installed matching bundle " + existingBundles.get(existingBundles.size() - 1).toString());
}
boolean isThereSuitableDeployer = false;
for (SimpleDeployer deployer : this.simpleDeployers) {
if (deployer.canServeFileType(deploymentIdentity.getType())) {
isThereSuitableDeployer = true;
deployer.undeploy(existingBundles.get(0));
}
}
if (!isThereSuitableDeployer) {
this.defaultDeployer.undeploy(existingBundles.get(0));
}
}
}
@Override
public DeploymentIdentity getDeploymentIdentity(URI uri) {
for (SimpleDeployer deployer : this.simpleDeployers) {
if (deployer.canServeFileType(getFileTypeFromUri(uri))) {
return deployer.getDeploymentIdentity(uri);
}
}
return null;
}
@Override
public boolean isDeployed(URI uri) {
for (SimpleDeployer simpleDeployer : this.simpleDeployers) {
if (simpleDeployer.canServeFileType(getFileTypeFromUri(uri))) {
return simpleDeployer.isDeployed(uri) ^ simpleDeployer.isOfflineUpdated(uri);
}
}
return false;
}
private String getFileTypeFromUri(URI uri) {
String path = uri.toString();
return path.substring(path.lastIndexOf(".") + 1);
}
@Override
public DeploymentIdentity deploy(URI uri, DeploymentOptions options) {
return this.deploy(uri);
}
@Override
public DeploymentIdentity deploy(String type, String name, Version version) {
throw new UnsupportedOperationException("Not supported in Virgo Nano.");
}
@Override
public DeploymentIdentity deploy(String type, String name, Version version, DeploymentOptions options) {
throw new UnsupportedOperationException("Not supported in Virgo Nano.");
}
@Override
public void undeploy(String applicationSymbolicName, String version) {
throw new UnsupportedOperationException("Not supported in Virgo Nano.");
}
@Override
public DeploymentIdentity install(URI uri, DeploymentOptions options) {
throw new UnsupportedOperationException("Not supported in Virgo Nano.");
}
@Override
public DeploymentIdentity install(URI uri) {
throw new UnsupportedOperationException("Not supported in Virgo Nano.");
}
@Override
public void undeploy(String type, String name, String version) {
throw new UnsupportedOperationException("Not supported in Virgo Nano.");
}
@Override
public void undeploy(DeploymentIdentity deploymentIdentity, boolean deleted) {
throw new UnsupportedOperationException("Not supported in Virgo Nano.");
}
@Override
public DeploymentIdentity refresh(URI uri, String symbolicName) {
throw new UnsupportedOperationException("Not supported in Virgo Nano.");
}
@Override
public void refreshBundle(String bundleSymbolicName, String bundleVersion) {
throw new UnsupportedOperationException("Not supported in Virgo Nano.");
}
@Override
public DeploymentIdentity[] getDeploymentIdentities() {
throw new UnsupportedOperationException("Not supported in Virgo Nano.");
}
public void bindEventLogger(EventLogger logger) {
this.eventLogger = logger;
}
public void unbindEventLogger(EventLogger logger) {
this.eventLogger = null;
}
public void bindEventAdmin(EventAdmin admin) {
this.eventAdmin = admin;
}
public void unbindEventAdmin(EventAdmin admin) {
this.eventAdmin = null;
}
public void bindKernelConfig(KernelConfig config) {
this.kernelConfig = config;
}
public void unbindKernelConfig(KernelConfig config) {
this.kernelConfig = null;
}
public void bindPackageAdmin(PackageAdmin packageAdmin) {
this.packageAdmin = packageAdmin;
}
public void unbindPackageAdmin(PackageAdmin packageAdmin) {
this.packageAdmin = null;
}
public void bindSimpleDeployer(SimpleDeployer deployer) {
this.simpleDeployers.add(deployer);
}
public void unbindSimpleDeployer(SimpleDeployer deployer) {
this.simpleDeployers.remove(deployer);
}
private void handleUnsupportedFileType(URI uri) {
List<String> acceptedTypes = new ArrayList<>();
for (SimpleDeployer deployer : this.simpleDeployers) {
acceptedTypes.addAll(deployer.getAcceptedFileTypes());
}
this.eventLogger.log(NanoDeployerLogEvents.NANO_UNRECOGNIZED_TYPE, uri, acceptedTypes);
}
private void installDeployables(List<URI> uris) {
for (URI uri : uris) {
boolean isThereSuitableDeployer = false;
for (SimpleDeployer deployer : this.simpleDeployers) {
if (deployer.canServeFileType(getFileTypeFromUri(uri))) {
isThereSuitableDeployer = true;
if (!deployer.isDeployFileValid(new File(uri))) {
this.eventLogger.log(NanoDeployerLogEvents.NANO_INVALID_FILE);
} else {
if (deployer.isDeployed(uri)) {
deployer.update(uri);
} else {
deployer.install(uri);
}
}
}
}
if (!isThereSuitableDeployer) {
handleUnsupportedFileType(uri);
}
}
}
private void startDeployables(List<URI> uris) {
for (URI uri : uris) {
boolean isThereSuitableDeployer = false;
for (SimpleDeployer deployer : this.simpleDeployers) {
if (deployer.canServeFileType(getFileTypeFromUri(uri))) {
isThereSuitableDeployer = true;
if (!deployer.isDeployFileValid(new File(uri))) {
this.eventLogger.log(NanoDeployerLogEvents.NANO_INVALID_FILE);
} else {
deployer.start(uri);
}
}
}
if (!isThereSuitableDeployer) {
handleUnsupportedFileType(uri);
}
}
}
private void recoveryComplete() {
this.eventAdmin.postEvent(new Event(TOPIC_RECOVERY_COMPLETED, (Map<String, ?>) null));
}
}