Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 84D08200C77 for ; Mon, 1 May 2017 16:23:03 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 834EE160BAE; Mon, 1 May 2017 14:23:03 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id D0364160BAB for ; Mon, 1 May 2017 16:23:01 +0200 (CEST) Received: (qmail 91926 invoked by uid 500); 1 May 2017 14:23:01 -0000 Mailing-List: contact commits-help@karaf.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@karaf.apache.org Delivered-To: mailing list commits@karaf.apache.org Received: (qmail 91916 invoked by uid 99); 1 May 2017 14:23:01 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 01 May 2017 14:23:01 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id E50D4DFB8A; Mon, 1 May 2017 14:23:00 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: jbonofre@apache.org To: commits@karaf.apache.org Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: karaf git commit: [KARAF-5107] Add DeploymentListener Date: Mon, 1 May 2017 14:23:00 +0000 (UTC) archived-at: Mon, 01 May 2017 14:23:03 -0000 Repository: karaf Updated Branches: refs/heads/karaf-4.1.x 594d80dcf -> 9e6f8c9bf [KARAF-5107] Add DeploymentListener Signed-off-by: Robert Varga Project: http://git-wip-us.apache.org/repos/asf/karaf/repo Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/9e6f8c9b Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/9e6f8c9b Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/9e6f8c9b Branch: refs/heads/karaf-4.1.x Commit: 9e6f8c9bfdfddb477aafd089eed3221c24fdac45 Parents: 594d80d Author: Robert Varga Authored: Thu Apr 27 14:15:41 2017 +0200 Committer: Jean-Baptiste Onofré Committed: Mon May 1 16:22:50 2017 +0200 ---------------------------------------------------------------------- .../apache/karaf/features/DeploymentEvent.java | 40 +++++++++++++++ .../karaf/features/DeploymentListener.java | 31 ++++++++++++ .../apache/karaf/features/FeaturesService.java | 4 ++ .../features/internal/service/Deployer.java | 41 +++++++++------ .../internal/service/FeaturesServiceImpl.java | 50 ++++++++++++++++--- .../features/internal/service/DeployerTest.java | 52 ++++++++++++++++++-- .../assembly/AssemblyDeployCallback.java | 11 +++-- .../org/apache/karaf/tooling/VerifyMojo.java | 21 ++++---- 8 files changed, 211 insertions(+), 39 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/karaf/blob/9e6f8c9b/features/core/src/main/java/org/apache/karaf/features/DeploymentEvent.java ---------------------------------------------------------------------- diff --git a/features/core/src/main/java/org/apache/karaf/features/DeploymentEvent.java b/features/core/src/main/java/org/apache/karaf/features/DeploymentEvent.java new file mode 100644 index 0000000..f9bcad0 --- /dev/null +++ b/features/core/src/main/java/org/apache/karaf/features/DeploymentEvent.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.karaf.features; + +/** + * Enumeration of deployment events. Each deployment is an operation potentially involving multiple features and its + * bundles. Deployments cannot overlap. + */ +public enum DeploymentEvent { + /** + * A new deployment operation has started. + */ + DEPLOYMENT_STARTED, + /** + * Bundle install/uninstall operations within this deployment have completed. + */ + BUNDLES_INSTALLED, + /** + * Bundle resolution has completed, but the bundles have not yet been started. + */ + BUNDLES_RESOLVED, + /** + * The deployment has completed. + */ + DEPLOYMENT_FINISHED, +} http://git-wip-us.apache.org/repos/asf/karaf/blob/9e6f8c9b/features/core/src/main/java/org/apache/karaf/features/DeploymentListener.java ---------------------------------------------------------------------- diff --git a/features/core/src/main/java/org/apache/karaf/features/DeploymentListener.java b/features/core/src/main/java/org/apache/karaf/features/DeploymentListener.java new file mode 100644 index 0000000..3371ebc --- /dev/null +++ b/features/core/src/main/java/org/apache/karaf/features/DeploymentListener.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.karaf.features; + +import java.util.EventListener; + +/** + * Interface implemented by components interested in bundle lifecycle operations triggered by {@link FeaturesService}. + */ +public interface DeploymentListener extends EventListener { + /** + * Fired when a deployment event occurs. + * + * @param event Triggered event + */ + void deploymentEvent(DeploymentEvent event); +} http://git-wip-us.apache.org/repos/asf/karaf/blob/9e6f8c9b/features/core/src/main/java/org/apache/karaf/features/FeaturesService.java ---------------------------------------------------------------------- diff --git a/features/core/src/main/java/org/apache/karaf/features/FeaturesService.java b/features/core/src/main/java/org/apache/karaf/features/FeaturesService.java index c7c932a..faceddb 100644 --- a/features/core/src/main/java/org/apache/karaf/features/FeaturesService.java +++ b/features/core/src/main/java/org/apache/karaf/features/FeaturesService.java @@ -156,6 +156,10 @@ public interface FeaturesService { void unregisterListener(FeaturesListener listener); + void registerListener(DeploymentListener listener); + + void unregisterListener(DeploymentListener listener); + FeatureState getState(String featureId); } http://git-wip-us.apache.org/repos/asf/karaf/blob/9e6f8c9b/features/core/src/main/java/org/apache/karaf/features/internal/service/Deployer.java ---------------------------------------------------------------------- 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 73c1cb3..7fb066b 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 @@ -41,6 +41,7 @@ import org.apache.felix.utils.version.VersionRange; import org.apache.felix.utils.version.VersionTable; import org.apache.karaf.features.BundleInfo; import org.apache.karaf.features.Conditional; +import org.apache.karaf.features.DeploymentEvent; import org.apache.karaf.features.Feature; import org.apache.karaf.features.FeatureEvent; import org.apache.karaf.features.FeatureState; @@ -115,6 +116,7 @@ public class Deployer { void saveState(State state); void persistResolveRequest(DeploymentRequest request) throws IOException; void installFeature(Feature feature) throws IOException, InvalidSyntaxException; + void callListeners(DeploymentEvent deployEvent); void callListeners(FeatureEvent featureEvent); Bundle installBundle(String region, String uri, InputStream is) throws BundleException; @@ -252,9 +254,13 @@ public class Deployer { for (String feature : featureSet) { String[] p = feature.split("/"); found = name.equals(p[0]) && range.contains(VersionTable.getVersion(p[1])); - if (found) break; + if (found) { + break; + } + } + if (found) { + break; } - if (found) break; } if (found) { iterator.remove(); @@ -569,7 +575,6 @@ public class Deployer { // #10: send events // - // // Handle updates on the FeaturesService bundle // @@ -578,6 +583,7 @@ public class Deployer { if (rootRegionDeployment != null && rootRegionDeployment.toDelete.contains(dstate.serviceBundle)) { throw new UnsupportedOperationException("Uninstalling the FeaturesService bundle is not supported"); } + // If the bundle needs to be updated, do the following: // - persist the request to indicate the resolution must be continued after restart // - update the checksum and save the state @@ -588,8 +594,7 @@ public class Deployer { // - start the bundle // - exit // When restarting, the resolution will be attempted again - if (rootRegionDeployment != null && rootRegionDeployment.toUpdate.containsKey(dstate.serviceBundle) - ) { + if (rootRegionDeployment != null && rootRegionDeployment.toUpdate.containsKey(dstate.serviceBundle)) { callback.persistResolveRequest(request); // If the bundle is updated because of a different checksum, // save the new checksum persistently @@ -619,6 +624,8 @@ public class Deployer { return; } + callback.callListeners(DeploymentEvent.DEPLOYMENT_STARTED); + // // Perform bundle operations // @@ -754,7 +761,7 @@ public class Deployer { } if (hasToInstall) { print("Installing bundles:", verbose); - Map customStartLevels = new HashMap(); + Map customStartLevels = new HashMap<>(); for (Map.Entry entry : deployment.regions.entrySet()) { String name = entry.getKey(); Deployer.RegionDeployment regionDeployment = entry.getValue(); @@ -795,7 +802,7 @@ public class Deployer { } } } - + // Set start levels after install to avoid starting before all bundles are installed for (Bundle bundle : customStartLevels.keySet()) { callback.setBundleStartLevel(bundle, customStartLevels.get(bundle)); @@ -874,7 +881,9 @@ public class Deployer { toResolve.addAll(toStart); toResolve.addAll(toRefresh.keySet()); removeBundlesInState(toResolve, UNINSTALLED); + callback.callListeners(DeploymentEvent.BUNDLES_INSTALLED); callback.resolveBundles(toResolve, resolver.getWiring(), deployment.resToBnd); + callback.callListeners(DeploymentEvent.BUNDLES_RESOLVED); // Compute bundles to start removeFragmentsAndBundlesInState(toStart, UNINSTALLED | ACTIVE); @@ -916,11 +925,12 @@ public class Deployer { } } } + callback.callListeners(DeploymentEvent.DEPLOYMENT_FINISHED); print("Done.", verbose); } - private VersionRange getRange(String version, String featureResolutionRange) { + private static VersionRange getRange(String version, String featureResolutionRange) { VersionRange range; if (version.equals("0.0.0")) { range = VersionRange.ANY_VERSION; @@ -946,18 +956,18 @@ public class Deployer { } } - private boolean isSubsystem(Resource resource) { + private static boolean isSubsystem(Resource resource) { return TYPE_SUBSYSTEM.equals(getType(resource)); } - private boolean isBundle(Resource resource) { + private static boolean isBundle(Resource resource) { return TYPE_BUNDLE.equals(getType(resource)); } /** * Returns the most active state of the given states */ - private FeatureState mergeStates(FeatureState s1, FeatureState s2) { + private static FeatureState mergeStates(FeatureState s1, FeatureState s2) { if (s1 == FeatureState.Started || s2 == FeatureState.Started) { return FeatureState.Started; } @@ -967,7 +977,7 @@ public class Deployer { return FeatureState.Installed; } - private void computeBundlesToRefresh(Map toRefresh, Collection bundles, Map resources, Map> resolution) { + private static void computeBundlesToRefresh(Map toRefresh, Collection bundles, Map resources, Map> resolution) { // Compute the new list of fragments Map> newFragments = new HashMap<>(); for (Bundle bundle : bundles) { @@ -1096,7 +1106,7 @@ public class Deployer { callback.print(message, verbose); } - private void removeFragmentsAndBundlesInState(Collection bundles, int state) { + private static void removeFragmentsAndBundlesInState(Collection bundles, int state) { for (Iterator iterator = bundles.iterator(); iterator.hasNext();) { Bundle bundle = iterator.next(); if ((bundle.getState() & state) != 0 @@ -1106,7 +1116,7 @@ public class Deployer { } } - private void removeBundlesInState(Collection bundles, int state) { + private static void removeBundlesInState(Collection bundles, int state) { for (Iterator iterator = bundles.iterator(); iterator.hasNext();) { Bundle bundle = iterator.next(); if ((bundle.getState() & state) != 0) { @@ -1196,7 +1206,7 @@ public class Deployer { // Compute the list of resources to deploy in the region Set bundlesInRegion = bundlesPerRegions.get(region); List toDeploy = bundlesInRegion != null - ? new ArrayList<>(bundlesInRegion) : new ArrayList(); + ? new ArrayList<>(bundlesInRegion) : new ArrayList<>(); // Remove the system bundle Bundle systemBundle = dstate.bundles.get(0l); @@ -1411,6 +1421,7 @@ public class Deployer { } if (!bundlesToDestroy.isEmpty()) { Collections.sort(bundlesToDestroy, new Comparator() { + @Override public int compare(Bundle b1, Bundle b2) { return Long.compare(b2.getLastModified(), b1.getLastModified()); } http://git-wip-us.apache.org/repos/asf/karaf/blob/9e6f8c9b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java ---------------------------------------------------------------------- diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java index eeb692e..02be751 100644 --- a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java +++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java @@ -38,7 +38,6 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; -import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -50,6 +49,8 @@ import java.util.regex.Pattern; import org.apache.felix.utils.version.VersionCleaner; import org.apache.felix.utils.version.VersionRange; import org.apache.felix.utils.version.VersionTable; +import org.apache.karaf.features.DeploymentEvent; +import org.apache.karaf.features.DeploymentListener; import org.apache.karaf.features.Feature; import org.apache.karaf.features.FeatureEvent; import org.apache.karaf.features.FeatureState; @@ -176,6 +177,8 @@ public class FeaturesServiceImpl implements FeaturesService, Deployer.DeployCall private final org.osgi.service.repository.Repository globalRepository; private final List listeners = new CopyOnWriteArrayIdentityList<>(); + private final List deploymentListeners = new CopyOnWriteArrayIdentityList<>(); + private DeploymentEvent lastDeploymentEvent = DeploymentEvent.DEPLOYMENT_FINISHED; // Synchronized on lock private final Object lock = new Object(); @@ -255,9 +258,6 @@ public class FeaturesServiceImpl implements FeaturesService, Deployer.DeployCall checkResolve(); } - @SuppressWarnings({ - "unchecked", "rawtypes" - }) public void stop() { this.executor.shutdown(); } @@ -361,6 +361,7 @@ public class FeaturesServiceImpl implements FeaturesService, Deployer.DeployCall // Listeners support // + @Override public void registerListener(FeaturesListener listener) { listeners.add(listener); try { @@ -385,10 +386,23 @@ public class FeaturesServiceImpl implements FeaturesService, Deployer.DeployCall } } + @Override public void unregisterListener(FeaturesListener listener) { listeners.remove(listener); } + @Override + public void registerListener(DeploymentListener listener) { + deploymentListeners.add(listener); + listener.deploymentEvent(lastDeploymentEvent); + } + + @Override + public void unregisterListener(DeploymentListener listener) { + deploymentListeners.remove(listener); + } + + @Override public void callListeners(FeatureEvent event) { if (eventAdminListener != null) { eventAdminListener.featureEvent(event); @@ -398,6 +412,18 @@ public class FeaturesServiceImpl implements FeaturesService, Deployer.DeployCall } } + @Override + public void callListeners(DeploymentEvent event) { + lastDeploymentEvent = event; + for (DeploymentListener listener : deploymentListeners) { + try { + listener.deploymentEvent(event); + } catch (Exception e) { + LOGGER.warn("DeploymentListener {} failed to process event {}", listener, event, e); + } + } + } + protected void callListeners(RepositoryEvent event) { if (eventAdminListener != null) { eventAdminListener.repositoryEvent(event); @@ -590,6 +616,7 @@ public class FeaturesServiceImpl implements FeaturesService, Deployer.DeployCall // Features support // + @Override public Feature getFeature(String name) throws Exception { Feature[] features = this.getFeatures(name); if (features.length < 1) { @@ -599,6 +626,7 @@ public class FeaturesServiceImpl implements FeaturesService, Deployer.DeployCall } } + @Override public Feature getFeature(String name, String version) throws Exception { Feature[] features = this.getFeatures(name, version); if (features.length < 1) { @@ -608,6 +636,7 @@ public class FeaturesServiceImpl implements FeaturesService, Deployer.DeployCall } } + @Override public Feature[] getFeatures(String nameOrId) throws Exception { String[] parts = nameOrId.split("/"); String name = parts.length > 0 ? parts[0] : nameOrId; @@ -615,6 +644,7 @@ public class FeaturesServiceImpl implements FeaturesService, Deployer.DeployCall return getFeatures(name, version); } + @Override public Feature[] getFeatures(String name, String version) throws Exception { List features = new ArrayList<>(); Pattern pattern = Pattern.compile(name); @@ -662,6 +692,7 @@ public class FeaturesServiceImpl implements FeaturesService, Deployer.DeployCall } } + @Override public Feature[] listFeatures() throws Exception { Set features = new HashSet<>(); for (Map featureWithDifferentVersion : getFeatures().values()) { @@ -780,7 +811,7 @@ public class FeaturesServiceImpl implements FeaturesService, Deployer.DeployCall return installed != null && installed.contains(id); } } - + @Override public FeatureState getState(String featureId) { String id = normalize(featureId); @@ -906,8 +937,8 @@ public class FeaturesServiceImpl implements FeaturesService, Deployer.DeployCall String req = f.getName() + "/" + new VersionRange(f.getVersion(), true); featuresToAdd.add(req); Feature[] installedFeatures = listInstalledFeatures(); - for (int i=0;i features, String region, EnumSet