You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2014/04/25 00:49:29 UTC

[1/3] git commit: [KARAF-2888] Fix messages printed by the FeaturesService

Repository: karaf
Updated Branches:
  refs/heads/master d8e6ae44f -> 2e1dbb7b5


[KARAF-2888] Fix messages printed by the FeaturesService

Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/b123f9f6
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/b123f9f6
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/b123f9f6

Branch: refs/heads/master
Commit: b123f9f6e427b2d0f5c05b71f741d6858af485d9
Parents: d8e6ae4
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Thu Apr 24 17:31:10 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Thu Apr 24 17:31:10 2014 +0200

----------------------------------------------------------------------
 .../karaf/features/internal/service/FeaturesServiceImpl.java     | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/b123f9f6/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 cbfb15a..7863884 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
@@ -951,7 +951,7 @@ public class FeaturesServiceImpl implements FeaturesService {
         }
 
         if (simulate) {
-            if (!toRefresh.isEmpty()) {
+            if (!noRefresh && !toRefresh.isEmpty()) {
                 print("  Bundles to refresh:", verbose);
                 for (Bundle bundle : toRefresh) {
                     print("    " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
@@ -1250,7 +1250,7 @@ public class FeaturesServiceImpl implements FeaturesService {
             while (!toStart.isEmpty()) {
                 List<Bundle> bs = getBundlesToStart(toStart);
                 for (Bundle bundle : bs) {
-                    LOGGER.info("  " + bundle.getSymbolicName() + " / " + bundle.getVersion());
+                    print("  " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
                     try {
                         bundle.start();
                     } catch (BundleException e) {


[3/3] git commit: [KARAF-2888] Allow non-managed bundles to automatically become managed if they are required by a feature and only used by managed bundles Allow updates to bundle information, such as start and start-level

Posted by gn...@apache.org.
[KARAF-2888] Allow non-managed bundles to automatically become managed if they are required by a feature and only used by managed bundles
Allow updates to bundle information, such as start and start-level

Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/2e1dbb7b
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/2e1dbb7b
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/2e1dbb7b

Branch: refs/heads/master
Commit: 2e1dbb7b59139ee6e8d6ebce21fbfe6bc5593489
Parents: 6e36051
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Thu Apr 24 23:31:31 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Apr 25 00:02:00 2014 +0200

----------------------------------------------------------------------
 .../features/command/InstallFeatureCommand.java |   6 +
 .../apache/karaf/features/FeaturesService.java  |   1 +
 .../internal/region/ResourceComparator.java     |  43 ------
 .../internal/region/SubsystemResolver.java      | 132 +++++++++---------
 .../internal/service/BundleComparator.java      |  44 ++++++
 .../internal/service/FeaturesServiceImpl.java   | 134 ++++++++++++++++---
 .../internal/service/ResourceComparator.java    |  43 ++++++
 .../karaf/features/internal/util/MapUtils.java  |   5 +
 8 files changed, 290 insertions(+), 118 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/2e1dbb7b/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
index ccd869a..1f45aa0 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
@@ -44,6 +44,9 @@ public class InstallFeatureCommand extends FeaturesCommandSupport {
     @Option(name = "-s", aliases = "--no-auto-start", description = "Do not start the bundles", required = false, multiValued = false)
     boolean noStart;
 
+    @Option(name = "-m", aliases = "--no-auto-manage", description = "Do not automatically manage bundles", required = false, multiValued = false)
+    boolean noManage;
+
     @Option(name = "-v", aliases = "--verbose", description = "Explain what is being done", required = false, multiValued = false)
     boolean verbose;
 
@@ -64,6 +67,9 @@ public class InstallFeatureCommand extends FeaturesCommandSupport {
         if (noRefresh) {
             options.add(FeaturesService.Option.NoAutoRefreshBundles);
         }
+        if (noManage) {
+            options.add(FeaturesService.Option.NoAutoManageBundles);
+        }
         if (verbose) {
             options.add(FeaturesService.Option.Verbose);
         }

http://git-wip-us.apache.org/repos/asf/karaf/blob/2e1dbb7b/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 7bb3cf8..178f404 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
@@ -31,6 +31,7 @@ public interface FeaturesService {
         NoAutoRefreshUnmanagedBundles,
         NoAutoRefreshBundles,
         NoAutoStartBundles,
+        NoAutoManageBundles,
         Simulate,
         Verbose
     }

http://git-wip-us.apache.org/repos/asf/karaf/blob/2e1dbb7b/features/core/src/main/java/org/apache/karaf/features/internal/region/ResourceComparator.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/region/ResourceComparator.java b/features/core/src/main/java/org/apache/karaf/features/internal/region/ResourceComparator.java
deleted file mode 100644
index 19ba529..0000000
--- a/features/core/src/main/java/org/apache/karaf/features/internal/region/ResourceComparator.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.internal.region;
-
-import java.util.Comparator;
-
-import org.apache.felix.resolver.Util;
-import org.osgi.framework.Version;
-import org.osgi.resource.Resource;
-
-public class ResourceComparator implements Comparator<Resource> {
-
-    @Override
-    public int compare(Resource o1, Resource o2) {
-        String bsn1 = Util.getSymbolicName(o1);
-        String bsn2 = Util.getSymbolicName(o2);
-        int c = bsn1.compareTo(bsn2);
-        if (c == 0) {
-            Version v1 = Util.getVersion(o1);
-            Version v2 = Util.getVersion(o2);
-            c = v1.compareTo(v2);
-            if (c == 0) {
-                c = o1.hashCode() - o2.hashCode();
-            }
-        }
-        return c;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2e1dbb7b/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolver.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolver.java b/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolver.java
index 86d8e1b..a6355d2 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolver.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolver.java
@@ -16,8 +16,6 @@
  */
 package org.apache.karaf.features.internal.region;
 
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -29,7 +27,6 @@ import org.apache.felix.resolver.ResolverImpl;
 import org.apache.felix.resolver.Util;
 import org.apache.karaf.features.BundleInfo;
 import org.apache.karaf.features.Feature;
-import org.apache.karaf.features.Repository;
 import org.apache.karaf.features.internal.download.DownloadManager;
 import org.apache.karaf.features.internal.download.Downloader;
 import org.apache.karaf.features.internal.download.StreamProvider;
@@ -69,6 +66,16 @@ public class SubsystemResolver {
     private Subsystem root;
     private Map<Resource, List<Wire>> wiring;
 
+    // Cached computed results
+    private Map<String, String> flatSubsystemsMap;
+    private Map<String, Set<Resource>> bundlesPerRegions;
+    private Map<Resource, String> bundles;
+    private Map<String, Set<Resource>> featuresPerRegions;
+    private Map<Resource, String> features;
+    private RegionDigraph flatDigraph;
+    private Map<String, Map<String, BundleInfo>> bundleInfos;
+
+
     public SubsystemResolver() {
         this(new SimpleDownloader());
     }
@@ -152,22 +159,23 @@ public class SubsystemResolver {
     }
 
     public Map<String, Map<String, BundleInfo>> getBundleInfos() {
-        Map<String, Map<String, BundleInfo>> infos = new HashMap<String, Map<String, BundleInfo>>();
-        Map<String, String> flats = getFlatSubsystemsMap();
-        addBundleInfos(infos, root, flats);
-        return infos;
+        if (bundleInfos == null) {
+            bundleInfos = new HashMap<String, Map<String, BundleInfo>>();
+            addBundleInfos(root);
+        }
+        return bundleInfos;
     }
 
-    private void addBundleInfos(Map<String, Map<String, BundleInfo>> infos, Subsystem subsystem, Map<String, String> flats) {
-        String region = flats.get(subsystem.getName());
-        Map<String, BundleInfo> bis = infos.get(region);
+    private void addBundleInfos(Subsystem subsystem) {
+        String region = getFlatSubsystemsMap().get(subsystem.getName());
+        Map<String, BundleInfo> bis = bundleInfos.get(region);
         if (bis == null) {
             bis = new HashMap<String, BundleInfo>();
-            infos.put(region, bis);
+            bundleInfos.put(region, bis);
         }
         bis.putAll(subsystem.getBundleInfos());
         for (Subsystem child : subsystem.getChildren()) {
-            addBundleInfos(infos, child, flats);
+            addBundleInfos(child);
         }
     }
 
@@ -175,83 +183,87 @@ public class SubsystemResolver {
         return manager.getProviders();
     }
 
-    public RegionDigraph getDigraph() {
-        return digraph;
-    }
-
     public Map<Resource, List<Wire>> getWiring() {
         return wiring;
     }
 
     public RegionDigraph getFlatDigraph() throws BundleException, InvalidSyntaxException {
-        RegionDigraph clone = this.digraph.copy();
-        RegionDigraph computedDigraph = digraph;
-        for (Region r : clone.getRegions()) {
-            clone.removeRegion(r);
-        }
-        Map<String, String> flats = getFlatSubsystemsMap();
-        for (Region r : computedDigraph.getRegions()) {
-            if (r.getName().equals(flats.get(r.getName()))) {
-                clone.createRegion(r.getName());
+        if (flatDigraph == null) {
+            flatDigraph = new StandardRegionDigraph(null, null);
+            Map<String, String> flats = getFlatSubsystemsMap();
+            for (Region r : digraph.getRegions()) {
+                if (r.getName().equals(flats.get(r.getName()))) {
+                    flatDigraph.createRegion(r.getName());
+                }
             }
-        }
-        for (Region r : computedDigraph.getRegions()) {
-            for (RegionDigraph.FilteredRegion fr : computedDigraph.getEdges(r)) {
-                String rt = flats.get(r.getName());
-                String rh = flats.get(fr.getRegion().getName());
-                if (!rh.equals(rt)) {
-                    Region tail = clone.getRegion(rt);
-                    Region head = clone.getRegion(rh);
-                    RegionFilterBuilder rfb = clone.createRegionFilterBuilder();
-                    for (Map.Entry<String, Collection<String>> entry : fr.getFilter().getSharingPolicy().entrySet()) {
-                        // Discard osgi.identity namespace
-                        if (!IDENTITY_NAMESPACE.equals(entry.getKey())) {
-                            for (String f : entry.getValue()) {
-                                rfb.allow(entry.getKey(), f);
+            for (Region r : digraph.getRegions()) {
+                for (RegionDigraph.FilteredRegion fr : digraph.getEdges(r)) {
+                    String rt = flats.get(r.getName());
+                    String rh = flats.get(fr.getRegion().getName());
+                    if (!rh.equals(rt)) {
+                        Region tail = flatDigraph.getRegion(rt);
+                        Region head = flatDigraph.getRegion(rh);
+                        RegionFilterBuilder rfb = flatDigraph.createRegionFilterBuilder();
+                        for (Map.Entry<String, Collection<String>> entry : fr.getFilter().getSharingPolicy().entrySet()) {
+                            // Discard osgi.identity namespace
+                            if (!IDENTITY_NAMESPACE.equals(entry.getKey())) {
+                                for (String f : entry.getValue()) {
+                                    rfb.allow(entry.getKey(), f);
+                                }
                             }
                         }
+                        flatDigraph.connect(tail, rfb.build(), head);
                     }
-                    clone.connect(tail, rfb.build(), head);
                 }
             }
         }
-        return clone;
+        return flatDigraph;
     }
 
     public Map<String, String> getFlatSubsystemsMap() {
-        Map<String, String> toFlatten = new HashMap<String, String>();
-        findSubsystemsToFlatten(root, toFlatten);
-        return toFlatten;
+        if (flatSubsystemsMap == null) {
+            flatSubsystemsMap = new HashMap<String, String>();
+            findSubsystemsToFlatten(root, flatSubsystemsMap);
+        }
+        return flatSubsystemsMap;
     }
 
     public Map<String, Set<Resource>> getBundlesPerRegions() {
-        return invert(getBundles());
+        if (bundlesPerRegions == null) {
+            bundlesPerRegions = invert(getBundles());
+        }
+        return bundlesPerRegions;
     }
 
     public Map<Resource, String> getBundles() {
-        String filter = String.format("(&(%s=*)(|(%s=%s)(%s=%s)))",
-                            IDENTITY_NAMESPACE,
-                            CAPABILITY_TYPE_ATTRIBUTE, TYPE_BUNDLE,
-                            CAPABILITY_TYPE_ATTRIBUTE, TYPE_FRAGMENT);
-        SimpleFilter sf = SimpleFilter.parse(filter);
-        return getResourceMapping(sf);
+        if (bundles == null) {
+            String filter = String.format("(&(%s=*)(|(%s=%s)(%s=%s)))",
+                    IDENTITY_NAMESPACE,
+                    CAPABILITY_TYPE_ATTRIBUTE, TYPE_BUNDLE,
+                    CAPABILITY_TYPE_ATTRIBUTE, TYPE_FRAGMENT);
+            SimpleFilter sf = SimpleFilter.parse(filter);
+            bundles = getResourceMapping(sf);
+        }
+        return bundles;
     }
 
     public Map<String, Set<Resource>> getFeaturesPerRegions() {
-        return invert(getFeatures());
+        if (featuresPerRegions == null) {
+            featuresPerRegions = invert(getFeatures());
+        }
+        return featuresPerRegions;
     }
 
     public Map<Resource, String> getFeatures() {
-        SimpleFilter sf = createFilter(IDENTITY_NAMESPACE, "*",
-                                       CAPABILITY_TYPE_ATTRIBUTE, TYPE_FEATURE);
-        return getResourceMapping(sf);
-    }
-
-    public Map<String, Set<Resource>> getResourcesPerRegion(SimpleFilter resourceFilter) {
-        return invert(getResourceMapping(resourceFilter));
+        if (features == null) {
+            SimpleFilter sf = createFilter(IDENTITY_NAMESPACE, "*",
+                                           CAPABILITY_TYPE_ATTRIBUTE, TYPE_FEATURE);
+            features = getResourceMapping(sf);
+        }
+        return features;
     }
 
-    public Map<Resource, String> getResourceMapping(SimpleFilter resourceFilter) {
+    private Map<Resource, String> getResourceMapping(SimpleFilter resourceFilter) {
         Map<String, String> flats = getFlatSubsystemsMap();
         Map<Resource, List<Wire>> wiring = getWiring();
         Map<Resource, String> resources = new HashMap<Resource, String>();

http://git-wip-us.apache.org/repos/asf/karaf/blob/2e1dbb7b/features/core/src/main/java/org/apache/karaf/features/internal/service/BundleComparator.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/BundleComparator.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/BundleComparator.java
new file mode 100644
index 0000000..d6bd3e1
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/BundleComparator.java
@@ -0,0 +1,44 @@
+/*
+ * 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.internal.service;
+
+import java.util.Comparator;
+
+import org.apache.felix.resolver.Util;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
+import org.osgi.resource.Resource;
+
+public class BundleComparator implements Comparator<Bundle> {
+
+    @Override
+    public int compare(Bundle o1, Bundle o2) {
+        String bsn1 = o1.getSymbolicName();
+        String bsn2 = o2.getSymbolicName();
+        int c = bsn1.compareTo(bsn2);
+        if (c == 0) {
+            Version v1 = o1.getVersion();
+            Version v2 = o2.getVersion();
+            c = v1.compareTo(v2);
+            if (c == 0) {
+                c = o1.hashCode() - o2.hashCode();
+            }
+        }
+        return c;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2e1dbb7b/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 7863884..eafd08e 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
@@ -50,7 +50,6 @@ import org.apache.karaf.features.FeaturesService;
 import org.apache.karaf.features.Repository;
 import org.apache.karaf.features.RepositoryEvent;
 import org.apache.karaf.features.internal.download.StreamProvider;
-import org.apache.karaf.features.internal.region.ResourceComparator;
 import org.apache.karaf.features.internal.region.SubsystemResolver;
 import org.apache.karaf.features.internal.util.ChecksumUtils;
 import org.apache.karaf.features.internal.util.Macro;
@@ -69,6 +68,7 @@ import org.osgi.framework.FrameworkListener;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.Version;
 import org.osgi.framework.startlevel.BundleStartLevel;
+import org.osgi.framework.startlevel.FrameworkStartLevel;
 import org.osgi.framework.wiring.BundleRevision;
 import org.osgi.framework.wiring.BundleWire;
 import org.osgi.framework.wiring.BundleWiring;
@@ -84,6 +84,7 @@ import static org.apache.karaf.features.internal.resolver.ResourceUtils.getFeatu
 import static org.apache.karaf.features.internal.resolver.ResourceUtils.getUri;
 import static org.apache.karaf.features.internal.util.MapUtils.addToMapSet;
 import static org.apache.karaf.features.internal.util.MapUtils.apply;
+import static org.apache.karaf.features.internal.util.MapUtils.contains;
 import static org.apache.karaf.features.internal.util.MapUtils.copy;
 import static org.apache.karaf.features.internal.util.MapUtils.diff;
 import static org.apache.karaf.features.internal.util.MapUtils.flatten;
@@ -875,6 +876,7 @@ public class FeaturesServiceImpl implements FeaturesService {
         boolean noStart = options.contains(Option.NoAutoStartBundles);
         boolean verbose = options.contains(Option.Verbose);
         boolean simulate = options.contains(Option.Simulate);
+        boolean noManageBundles = options.contains(Option.NoAutoManageBundles);
 
         DeploymentState dstate = getDeploymentState();
         
@@ -911,10 +913,10 @@ public class FeaturesServiceImpl implements FeaturesService {
         Set<Resource> resourceLinkedToOldFeatures = new HashSet<Resource>();
         if (noStart) {
             for (Map.Entry<String, Set<Resource>> entry : featuresPerRegion.entrySet()) {
+                String region = entry.getKey();
                 for (Resource resource : entry.getValue()) {
                     String id = getFeatureId(resource);
-                    if (state.installedFeatures.containsKey(entry.getKey())
-                            && state.installedFeatures.get(entry.getKey()).contains(id)) {
+                    if (contains(state.installedFeatures, region, id)) {
                         addTransitive(resource, resourceLinkedToOldFeatures, resolver.getWiring());
                     }
                 }
@@ -926,19 +928,10 @@ public class FeaturesServiceImpl implements FeaturesService {
         //
         Deployment deployment = computeDeployment(dstate, resolver, state);
 
-        if (deployment.regions.isEmpty()) {
-            print("No deployment change.", verbose);
-            return;
-        }
-        //
-        // Log deployment
-        //
-        logDeployment(deployment, verbose);
-
         //
         // Compute the set of bundles to refresh
         //
-        Set<Bundle> toRefresh = new HashSet<Bundle>();
+        Set<Bundle> toRefresh = new TreeSet<Bundle>(new BundleComparator()); // sort is only used for display
         for (RegionDeployment regionDeployment : deployment.regions.values()) {
             toRefresh.addAll(regionDeployment.toDelete);
             toRefresh.addAll(regionDeployment.toUpdate.keySet());
@@ -950,6 +943,53 @@ public class FeaturesServiceImpl implements FeaturesService {
             toRefresh.removeAll(flatten(unmanagedBundles));
         }
 
+        // Automatically turn unmanaged bundles into managed bundles
+        // if they are required by a feature and no other unmanaged
+        // bundles have a requirement on it
+        Set<Bundle> toManage = new TreeSet<Bundle>(new BundleComparator()); // sort is only used for display
+        if (!noManageBundles) {
+            Set<Resource> features = resolver.getFeatures().keySet();
+            Set<? extends Resource> unmanaged = apply(flatten(unmanagedBundles), adapt(BundleRevision.class));
+            Set<Resource> requested = new HashSet<Resource>();
+            // Gather bundles required by a feature
+            for (List<Wire> wires : resolver.getWiring().values()) {
+                for (Wire wire : wires) {
+                    if (features.contains(wire.getRequirer()) && unmanaged.contains(wire.getProvider())) {
+                        requested.add(wire.getProvider());
+                    }
+                }
+            }
+            // Now, we know which bundles are completely unmanaged
+            unmanaged.removeAll(requested);
+            // Check if bundles have wires from really unmanaged bundles
+            for (List<Wire> wires : resolver.getWiring().values()) {
+                for (Wire wire : wires) {
+                    if (requested.contains(wire.getProvider()) && unmanaged.contains(wire.getRequirer())) {
+                        requested.remove(wire.getProvider());
+                    }
+                }
+            }
+            if (!requested.isEmpty()) {
+                Map<Long, String> bundleToRegion = new HashMap<Long, String>();
+                for (Map.Entry<String, Set<Long>> entry : dstate.bundlesPerRegion.entrySet()) {
+                    for (long id : entry.getValue()) {
+                        bundleToRegion.put(id, entry.getKey());
+                    }
+                }
+                for (Resource rev : requested) {
+                    Bundle bundle = ((BundleRevision) rev).getBundle();
+                    long id = bundle.getBundleId();
+                    addToMapSet(managedBundles, bundleToRegion.get(id), id);
+                    toManage.add(bundle);
+                }
+            }
+        }
+
+        //
+        // Log deployment
+        //
+        logDeployment(deployment, verbose);
+
         if (simulate) {
             if (!noRefresh && !toRefresh.isEmpty()) {
                 print("  Bundles to refresh:", verbose);
@@ -957,10 +997,18 @@ public class FeaturesServiceImpl implements FeaturesService {
                     print("    " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
                 }
             }
+            if (!toManage.isEmpty()) {
+                print("  Managing bundle:", verbose);
+                for (Bundle bundle : toManage) {
+                    print("    " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
+                }
+            }
             return;
         }
 
         Set<Bundle> toStart = new HashSet<Bundle>();
+        Set<Bundle> toResolve = new HashSet<Bundle>();
+        Set<Bundle> toStop = new HashSet<Bundle>();
 
         //
         // Execute deployment
@@ -994,9 +1042,42 @@ public class FeaturesServiceImpl implements FeaturesService {
         //
 
         //
+        // Find start levels to update
+        //
+        Map<Bundle, Integer> toUpdateStartLevel = new HashMap<Bundle, Integer>();
+        {
+            FrameworkStartLevel fsl = systemBundleContext.getBundle().adapt(FrameworkStartLevel.class);
+            for (Map.Entry<Resource, String> entry : resolver.getBundles().entrySet()) {
+                Resource resource = entry.getKey();
+                Bundle bundle = deployment.resToBnd.get(resource);
+                String region = entry.getValue();
+                BundleInfo bi = bundleInfos.get(region).get(getUri(resource));
+                if (bundle != null && bi != null) {
+                    int sl;
+                    if (bi.getStartLevel() > 0) {
+                        sl = bi.getStartLevel();
+                    } else {
+                        sl = fsl.getInitialBundleStartLevel();
+                    }
+                    BundleStartLevel bundleStartLevel = bundle.adapt(BundleStartLevel.class);
+                    if (bundleStartLevel.getStartLevel() != sl) {
+                        toUpdateStartLevel.put(bundle, sl);
+                        if (sl > fsl.getStartLevel()) {
+                            toStop.add(bundle);
+                        }
+                    }
+                    if (bi.isStart()) {
+                        toStart.add(bundle);
+                    } else {
+                        toStop.add(bundle);
+                    }
+                }
+            }
+        }
+
+        //
         // Stop bundles by chunks
         //
-        Set<Bundle> toStop = new HashSet<Bundle>();
         for (RegionDeployment regionDeployment : deployment.regions.values()) {
             toStop.addAll(regionDeployment.toUpdate.keySet());
             toStop.addAll(regionDeployment.toDelete);
@@ -1008,7 +1089,9 @@ public class FeaturesServiceImpl implements FeaturesService {
                 List<Bundle> bs = getBundlesToStop(toStop);
                 for (Bundle bundle : bs) {
                     print("  " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
-                    bundle.stop(STOP_TRANSIENT);
+                    // If the bundle start level will be changed, stop it persistently to
+                    // avoid a restart when the start level is actually changed
+                    bundle.stop(toUpdateStartLevel.containsKey(bundle) ? 0 : STOP_TRANSIENT);
                     toStop.remove(bundle);
                 }
             }
@@ -1132,12 +1215,22 @@ public class FeaturesServiceImpl implements FeaturesService {
                     toStart.add(bundle);
                     BundleInfo bi = bundleInfos.get(rde.getKey()).get(uri);
                     if (bi != null && bi.getStartLevel() > 0) {
+                        // TODO: this is wrong, as it will certainly start the bundle asynchronously
+                        // TODO:
                         bundle.adapt(BundleStartLevel.class).setStartLevel(bi.getStartLevel());
                     }
                 }
             }
         }
         //
+        // Update start levels
+        //
+        for (Map.Entry<Bundle, Integer> entry : toUpdateStartLevel.entrySet()) {
+            Bundle bundle = entry.getKey();
+            int sl = entry.getValue();
+            bundle.adapt(BundleStartLevel.class).setStartLevel(sl);
+        }
+        //
         // Install bundles
         //
         boolean hasToInstall = false;
@@ -1173,6 +1266,7 @@ public class FeaturesServiceImpl implements FeaturesService {
                     if (bi != null && bi.getStartLevel() > 0) {
                         bundle.adapt(BundleStartLevel.class).setStartLevel(bi.getStartLevel());
                     }
+                    toResolve.add(bundle);
                     if (resourceLinkedToOldFeatures.contains(resource)) {
                         toStart.add(bundle);
                     } else if (!noStart) {
@@ -1241,6 +1335,12 @@ public class FeaturesServiceImpl implements FeaturesService {
             }
         }
 
+        // Resolve bundles
+        toResolve.addAll(toStart);
+        toResolve.addAll(toRefresh);
+        removeFragmentsAndBundlesInState(toResolve, UNINSTALLED);
+        systemBundleContext.getBundle().adapt(FrameworkWiring.class).resolveBundles(toResolve);
+
         // Compute bundles to start
         removeFragmentsAndBundlesInState(toStart, UNINSTALLED | ACTIVE | STARTING);
         if (!toStart.isEmpty()) {
@@ -1345,6 +1445,10 @@ public class FeaturesServiceImpl implements FeaturesService {
     }
 
     protected void logDeployment(Deployment overallDeployment, boolean verbose) {
+        if (overallDeployment.regions.isEmpty()) {
+            print("No deployment change.", verbose);
+            return;
+        }
         print("Changes to perform:", verbose);
         for (Map.Entry<String, RegionDeployment> region : overallDeployment.regions.entrySet()) {
             RegionDeployment deployment = region.getValue();

http://git-wip-us.apache.org/repos/asf/karaf/blob/2e1dbb7b/features/core/src/main/java/org/apache/karaf/features/internal/service/ResourceComparator.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/ResourceComparator.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/ResourceComparator.java
new file mode 100644
index 0000000..bdf3458
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/ResourceComparator.java
@@ -0,0 +1,43 @@
+/*
+ * 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.internal.service;
+
+import java.util.Comparator;
+
+import org.apache.felix.resolver.Util;
+import org.osgi.framework.Version;
+import org.osgi.resource.Resource;
+
+public class ResourceComparator implements Comparator<Resource> {
+
+    @Override
+    public int compare(Resource o1, Resource o2) {
+        String bsn1 = Util.getSymbolicName(o1);
+        String bsn2 = Util.getSymbolicName(o2);
+        int c = bsn1.compareTo(bsn2);
+        if (c == 0) {
+            Version v1 = Util.getVersion(o1);
+            Version v2 = Util.getVersion(o2);
+            c = v1.compareTo(v2);
+            if (c == 0) {
+                c = o1.hashCode() - o2.hashCode();
+            }
+        }
+        return c;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2e1dbb7b/features/core/src/main/java/org/apache/karaf/features/internal/util/MapUtils.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/util/MapUtils.java b/features/core/src/main/java/org/apache/karaf/features/internal/util/MapUtils.java
index 0a21e29..d844c22 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/util/MapUtils.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/util/MapUtils.java
@@ -81,6 +81,11 @@ public class MapUtils {
         };
     }
 
+    public static <S, T> boolean contains(Map<S, Set<T>> mapset, S key, T val) {
+        Set<T> set = mapset.get(key);
+        return set != null && set.contains(val);
+    }
+
     public static <S, T> Set<T> flatten(Map<S, Set<T>> mapset) {
         Set<T> set = new HashSet<T>();
         for (Set<T> s : mapset.values()) {


[2/3] git commit: [KARAF-2923] Resolve optional dependencies to gather bundles to refresh correctly, but do not go to the user-defined repositories for optional requirements

Posted by gn...@apache.org.
[KARAF-2923] Resolve optional dependencies to gather bundles to refresh correctly, but do not go to the user-defined repositories for optional requirements

Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/6e36051b
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/6e36051b
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/6e36051b

Branch: refs/heads/master
Commit: 6e36051bc3ebe128d31cb14ce7ff9686cfd4fc0e
Parents: b123f9f
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Thu Apr 24 17:34:13 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Thu Apr 24 17:34:13 2014 +0200

----------------------------------------------------------------------
 .../internal/region/SubsystemResolveContext.java     | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/6e36051b/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolveContext.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolveContext.java b/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolveContext.java
index ef9c420..10be228 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolveContext.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolveContext.java
@@ -100,10 +100,13 @@ public class SubsystemResolveContext extends ResolveContext {
             if (res != null && !res.isEmpty()) {
                 caps.addAll(res);
             } else if (globalRepository != null) {
-                resMap = globalRepository.findProviders(Collections.singleton(requirement));
-                res = resMap != null ? resMap.get(requirement) : null;
-                if (res != null && !res.isEmpty()) {
-                    caps.addAll(res);
+                // Only bring in external resources for non optional requirements
+                if (!RESOLUTION_OPTIONAL.equals(requirement.getDirectives().get(RESOLUTION_DIRECTIVE))) {
+                    resMap = globalRepository.findProviders(Collections.singleton(requirement));
+                    res = resMap != null ? resMap.get(requirement) : null;
+                    if (res != null && !res.isEmpty()) {
+                        caps.addAll(res);
+                    }
                 }
             }
 
@@ -168,9 +171,7 @@ public class SubsystemResolveContext extends ResolveContext {
 
     @Override
     public boolean isEffective(Requirement requirement) {
-        String resolution = requirement.getDirectives().get(RESOLUTION_DIRECTIVE);
-        return requirement.getNamespace().equals(IDENTITY_NAMESPACE)
-                || !RESOLUTION_OPTIONAL.equals(resolution);
+        return true;
     }
 
     @Override