From 6c5ccc6bbf3780f04123faec352a5e640db59e81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Baptiste=20Onofr=C3=A9?= Date: Tue, 12 Sep 2017 10:41:04 +0200 Subject: [PATCH] [KARAF-5363] Add noAutoStartBundles options to kar service --- .../resources/etc/org.apache.karaf.kar.cfg | 6 ++ .../features/internal/service/Deployer.java | 2 +- .../java/org/apache/karaf/kar/KarService.java | 22 +++++- .../java/org/apache/karaf/kar/KarsMBean.java | 11 ++- .../karaf/kar/command/InstallKarCommand.java | 6 +- .../karaf/kar/internal/KarServiceImpl.java | 67 +++++++++++++------ .../karaf/kar/internal/KarsMBeanImpl.java | 11 ++- manual/src/main/asciidoc/user-guide/kar.adoc | 14 ++++ 8 files changed, 113 insertions(+), 26 deletions(-) diff --git a/assemblies/features/framework/src/main/resources/resources/etc/org.apache.karaf.kar.cfg b/assemblies/features/framework/src/main/resources/resources/etc/org.apache.karaf.kar.cfg index dfe491d0cff..1f8fef002b3 100644 --- a/assemblies/features/framework/src/main/resources/resources/etc/org.apache.karaf.kar.cfg +++ b/assemblies/features/framework/src/main/resources/resources/etc/org.apache.karaf.kar.cfg @@ -23,6 +23,12 @@ # noAutoRefreshBundles=false +# +# Enable or disable the automatic start of the bundles when installing +# the features contained in a KAR file +# +noAutoStartBundles=false + # # Directory where the kar are stored (when downloaded from Maven for instance) # diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/Deployer.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/Deployer.java index f17f1e66452..dfc4511286e 100644 --- a/features/core/src/main/java/org/apache/karaf/features/internal/service/Deployer.java +++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/Deployer.java @@ -473,7 +473,7 @@ public void deploy(DeploymentState dstate, DeploymentRequest request) throws Exc if (bundle == null) { // bundle is not present, it's provided by feature // we are using bundleInfo and start flag - if (bundleInfo != null && bundleInfo.isStart()) { + if (bundleInfo != null && bundleInfo.isStart() && !noStart) { states.put(resource, FeatureState.Started); } else { states.put(resource, FeatureState.Resolved); diff --git a/kar/src/main/java/org/apache/karaf/kar/KarService.java b/kar/src/main/java/org/apache/karaf/kar/KarService.java index f2dbdc5a2f1..219f9effda7 100644 --- a/kar/src/main/java/org/apache/karaf/kar/KarService.java +++ b/kar/src/main/java/org/apache/karaf/kar/KarService.java @@ -37,6 +37,15 @@ public interface KarService { * @throws Exception in case of installation failure. */ void install(URI karUri) throws Exception; + + /** + * Install KAR from a given URI + * + * @param karUri URI of the kar to install + * @param noAutoStartBundles true to not start automatically the bundles, false else + * @throws Exception in case of installation failure + */ + void install(URI karUri, boolean noAutoStartBundles) throws Exception; /** * Install a kar with manually given repository and @@ -45,10 +54,21 @@ public interface KarService { * @param karUri Uri of the kar to be installed * @param repoDir destination for the repository contents of the kar * @param resourceDir destination for the resource contents of the kar - * @throws Exception in case of installation failure. + * @throws Exception in case of installation failure */ void install(URI karUri, File repoDir, File resourceDir) throws Exception; + /** + * Install a kar with manually given repository and resource directories. + * + * @param karUri Uri of the kar to be installed. + * @param repoDir destination for the repository contents of the kar + * @param resourceDir destination for the resource contents of the kar + * @param noAutoStartBundles true to not start automatically the bundles, false else + * @throws Exception in case of installation failure + */ + void install(URI karUri, File repoDir, File resourceDir, boolean noAutoStartBundles) throws Exception; + /** * Uninstall the given KAR * diff --git a/kar/src/main/java/org/apache/karaf/kar/KarsMBean.java b/kar/src/main/java/org/apache/karaf/kar/KarsMBean.java index df8f3d91d7d..3a5d31ea0d8 100644 --- a/kar/src/main/java/org/apache/karaf/kar/KarsMBean.java +++ b/kar/src/main/java/org/apache/karaf/kar/KarsMBean.java @@ -40,11 +40,20 @@ public interface KarsMBean { /** * Install a KAR file from the given URL. * - * @param url the JAR URL. + * @param url the KAR URL. * @throws MBeanException in case of installation failure. */ void install(String url) throws MBeanException; + /** + * Install a KAR file from a given URL and decide to start or not the bundles. + * + * @param url the KAR URL. + * @param noAutoStartBundles true to not automatically start the bundles, false else. + * @throws MBeanException in case of installation failure. + */ + void install(String url, boolean noAutoStartBundles) throws MBeanException; + /** * Uninstall a KAR file. * diff --git a/kar/src/main/java/org/apache/karaf/kar/command/InstallKarCommand.java b/kar/src/main/java/org/apache/karaf/kar/command/InstallKarCommand.java index 806367ae979..489c9f4eaae 100644 --- a/kar/src/main/java/org/apache/karaf/kar/command/InstallKarCommand.java +++ b/kar/src/main/java/org/apache/karaf/kar/command/InstallKarCommand.java @@ -20,6 +20,7 @@ import org.apache.karaf.shell.api.action.Action; import org.apache.karaf.shell.api.action.Argument; import org.apache.karaf.shell.api.action.Command; +import org.apache.karaf.shell.api.action.Option; import org.apache.karaf.shell.api.action.lifecycle.Reference; import org.apache.karaf.shell.api.action.lifecycle.Service; @@ -32,11 +33,14 @@ public class InstallKarCommand implements Action { @Argument(index = 0, name = "url", description = "The URL of the KAR file to install.", required = true, multiValued = false) private String url; + @Option(name = "--no-start", description = "Do not start the bundles automatically", required = false, multiValued = false) + private boolean noAutoStartBundle = false; + @Reference private KarService karService; public Object execute() throws Exception { - karService.install(new URI(url)); + karService.install(new URI(url), noAutoStartBundle); return null; } diff --git a/kar/src/main/java/org/apache/karaf/kar/internal/KarServiceImpl.java b/kar/src/main/java/org/apache/karaf/kar/internal/KarServiceImpl.java index 30f72799381..ec7e21d34c4 100644 --- a/kar/src/main/java/org/apache/karaf/kar/internal/KarServiceImpl.java +++ b/kar/src/main/java/org/apache/karaf/kar/internal/KarServiceImpl.java @@ -69,6 +69,7 @@ public class KarServiceImpl implements KarService { private FeaturesService featuresService; private boolean noAutoRefreshBundles; + private boolean noAutoStartBundles; private List unsatisfiedKars; private AtomicBoolean busy; private DelayedDeployerThread delayedDeployerThread; @@ -84,17 +85,27 @@ public KarServiceImpl(String karafBase, String karStorage, FeaturesService featu unsatisfiedKars = Collections.synchronizedList(new ArrayList()); busy = new AtomicBoolean(); } - + @Override public void install(URI karUri) throws Exception { + install(karUri, false); + } + + @Override + public void install(URI karUri, boolean noAutoStartBundles) throws Exception { String karName = new Kar(karUri).getKarName(); LOGGER.debug("Installing KAR {} from {}", karName, karUri); File karDir = new File(storage, karName); - install(karUri, karDir, base); + install(karUri, karDir, base, noAutoStartBundles); } - + @Override public void install(URI karUri, File repoDir, File resourceDir) throws Exception { + install(karUri, repoDir, resourceDir, false); + } + + @Override + public void install(URI karUri, File repoDir, File resourceDir, boolean noAutoStartBundles) throws Exception { busy.set(true); try { Kar kar = new Kar(karUri); @@ -107,30 +118,30 @@ public void install(URI karUri, File repoDir, File resourceDir) throws Exception if (kar.isShouldInstallFeatures()) { List featureRepos = kar.getFeatureRepos(); Dependency missingDependency = findMissingDependency(featureRepos); - if(missingDependency==null) { - installFeatures(featureRepos); + if (missingDependency == null) { + installFeatures(featureRepos, noAutoStartBundles); } else { LOGGER.warn("Feature dependency {} is not available. Kar deployment postponed to see if it is about to be deployed",missingDependency); unsatisfiedKars.add(kar); - if(delayedDeployerThread==null) { - delayedDeployerThread = new DelayedDeployerThread(); + if (delayedDeployerThread == null) { + delayedDeployerThread = new DelayedDeployerThread(noAutoStartBundles); delayedDeployerThread.start(); } } } - if(!unsatisfiedKars.isEmpty()) { + if (!unsatisfiedKars.isEmpty()) { for (Iterator iterator = unsatisfiedKars.iterator(); iterator.hasNext();) { Kar delayedKar = iterator.next(); if(findMissingDependency(delayedKar.getFeatureRepos())==null) { LOGGER.info("Dependencies of kar {} are now satisfied. Installing",delayedKar.getKarName()); iterator.remove(); - installFeatures(delayedKar.getFeatureRepos()); + installFeatures(delayedKar.getFeatureRepos(), noAutoStartBundles); } } } - if(unsatisfiedKars.isEmpty()) { - if(delayedDeployerThread!=null) { + if (unsatisfiedKars.isEmpty()) { + if (delayedDeployerThread != null) { delayedDeployerThread.cancel(); } delayedDeployerThread = null; @@ -256,7 +267,7 @@ public List list() throws Exception { private void addToFeaturesRepositories(URI uri) throws Exception { try { featuresService.removeRepository(uri); - featuresService.addRepository(uri); + featuresService.addRepository(uri, false); LOGGER.info("Added feature repository '{}'", uri); } catch (Exception e) { LOGGER.warn("Unable to add repository '{}'", uri, e); @@ -268,20 +279,24 @@ private void addToFeaturesRepositories(URI uri) throws Exception { * * @param featuresRepositories the list of features XML. */ - private void installFeatures(List featuresRepositories) throws Exception { + private void installFeatures(List featuresRepositories, boolean noAutoStartBundles) throws Exception { for (Repository repository : featuresService.listRepositories()) { for (URI karFeatureRepoUri : featuresRepositories) { if (repository.getURI().equals(karFeatureRepoUri)) { try { for (Feature feature : repository.getFeatures()) { if (feature.getInstall() == null || Feature.DEFAULT_INSTALL_MODE.equals(feature.getInstall())) { + EnumSet options = EnumSet.noneOf(FeaturesService.Option.class); try { - LOGGER.debug("noAutoRefreshBundles is " + isNoAutoRefreshBundles()); + LOGGER.debug("noAutoRefreshBundles is {}", isNoAutoRefreshBundles()); if (isNoAutoRefreshBundles()) { - featuresService.installFeature(feature, EnumSet.of(FeaturesService.Option.NoAutoRefreshBundles)); - } else { - featuresService.installFeature(feature, EnumSet.noneOf(FeaturesService.Option.class)); + options.add(FeaturesService.Option.NoAutoRefreshBundles); } + LOGGER.debug("noAutoStartBundles is {} (default {})", noAutoStartBundles, this.noAutoStartBundles); + if (noAutoStartBundles || this.noAutoStartBundles) { + options.add(FeaturesService.Option.NoAutoStartBundles); + } + featuresService.installFeature(feature, options); } catch (Exception e) { LOGGER.warn("Unable to install Kar feature {}", feature.getName() + "/" + feature.getVersion(), e); } @@ -454,13 +469,23 @@ public void setNoAutoRefreshBundles(boolean noAutoRefreshBundles) { this.noAutoRefreshBundles = noAutoRefreshBundles; } - private class DelayedDeployerThread extends Thread - { + public boolean isNoAutoStartBundles() { + return noAutoStartBundles; + } + + public void setNoAutoStartBundles(boolean noAutoStartBundles) { + this.noAutoStartBundles = noAutoStartBundles; + } + + private class DelayedDeployerThread extends Thread { + + private boolean noAutoStartBundles; private AtomicBoolean cancel; - public DelayedDeployerThread() { + public DelayedDeployerThread(boolean noAutoStartBundles) { super("Delayed kar deployment"); cancel = new AtomicBoolean(); + this.noAutoStartBundles = noAutoStartBundles; } public void cancel() { @@ -487,7 +512,7 @@ private void installDelayedKars() { Kar kar = iterator.next(); iterator.remove(); try { - installFeatures(kar.getFeatureRepos()); + installFeatures(kar.getFeatureRepos(), noAutoStartBundles); } catch (Exception e) { LOGGER.error("Delayed deployment of kar "+kar.getKarName()+" failed",e); } diff --git a/kar/src/main/java/org/apache/karaf/kar/internal/KarsMBeanImpl.java b/kar/src/main/java/org/apache/karaf/kar/internal/KarsMBeanImpl.java index 9cee12b8ea2..c926acebe2e 100644 --- a/kar/src/main/java/org/apache/karaf/kar/internal/KarsMBeanImpl.java +++ b/kar/src/main/java/org/apache/karaf/kar/internal/KarsMBeanImpl.java @@ -33,6 +33,7 @@ public KarsMBeanImpl() throws NotCompliantMBeanException { super(KarsMBean.class); } + @Override public List getKars() throws MBeanException { try { return karService.list(); @@ -41,18 +42,26 @@ public List getKars() throws MBeanException { } } + @Override public void create(String repoName, List features) { karService.create(repoName, features, null); } + @Override public void install(String url) throws MBeanException { + install(url, false); + } + + @Override + public void install(String url, boolean noAutoStartBundles) throws MBeanException { try { - karService.install(new URI(url)); + karService.install(new URI(url), noAutoStartBundles); } catch (Exception e) { throw new MBeanException(null, e.toString()); } } + @Override public void uninstall(String name) throws MBeanException { try { karService.uninstall(name); diff --git a/manual/src/main/asciidoc/user-guide/kar.adoc b/manual/src/main/asciidoc/user-guide/kar.adoc index 6e1a367f9fa..fca3caf4a7c 100644 --- a/manual/src/main/asciidoc/user-guide/kar.adoc +++ b/manual/src/main/asciidoc/user-guide/kar.adoc @@ -227,6 +227,8 @@ The KAR file is uncompressed and populated the `KARAF_BASE/system` folder. The Apache Karaf KAR service is looking for features XML files in the KAR file, registers the features XML and automatically installs all features described in the features repositories present in the KAR file. +Optionally, you can control if the bundles should be automatically started or not using `--no-start` option. + ===== `kar:uninstall` The `kar:uninstall` command uninstall a KAR file (identified by a name). @@ -275,6 +277,17 @@ You can change the behaviours of the KAR deployer in the `etc/org.apache.karaf.k # the features contained in a KAR file # noAutoRefreshBundles=false + +# +# Enable or disable the automatic start of the bundles when installing +# the features contained in a KAR file +# +noAutoStartBundles=false + +# +# Directory where the kar are stored (when downloaded from Maven for instance) +# +#karStorage=${karaf.data}/kar ---- By default, when the KAR deployer install features, by default, it refresh the bundles already installed. @@ -293,6 +306,7 @@ The `Kars` attributes provides the list of KAR files (name) installed. ===== Operations * `install(url)` installs the KAR file at the given `url`. +* `install(url, noAutoStartBundles)` installs the KAR file at the given `url`, deciding if you want to automatically start the bundles or not. * `create(repository, features)` creates a KAR file using the given features `repository` name, and optionally the list of `features` to include in the KAR file. * `uninstall(name)` uninstalls a KAR file with the given `name`.