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 17:26:36 UTC

[3/4] git commit: [KARAF-2888] Support updates on the FeaturesService bundle itself

[KARAF-2888] Support updates on the FeaturesService bundle itself

This is done by updating the bundle separately and writing a file with resolution request so that when the service is restarted, the full resolution will happen

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

Branch: refs/heads/master
Commit: 400e9407db1bce65bfd5c9a5070893f4536b6e0a
Parents: c01c51d
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri Apr 25 17:09:18 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Apr 25 17:13:14 2014 +0200

----------------------------------------------------------------------
 .../internal/service/FeaturesServiceImpl.java   | 109 +++++++++++++++++--
 .../features/internal/service/StateStorage.java |  12 +-
 2 files changed, 106 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/400e9407/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 da27397..5d40440 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
@@ -16,6 +16,9 @@
  */
 package org.apache.karaf.features.internal.service;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
@@ -52,6 +55,8 @@ import org.apache.karaf.features.RepositoryEvent;
 import org.apache.karaf.features.internal.download.StreamProvider;
 import org.apache.karaf.features.internal.region.SubsystemResolver;
 import org.apache.karaf.features.internal.util.ChecksumUtils;
+import org.apache.karaf.features.internal.util.JsonReader;
+import org.apache.karaf.features.internal.util.JsonWriter;
 import org.apache.karaf.features.internal.util.Macro;
 import org.apache.karaf.features.internal.util.MapUtils;
 import org.apache.karaf.features.internal.util.MultiException;
@@ -82,6 +87,7 @@ import static org.apache.felix.resolver.Util.getSymbolicName;
 import static org.apache.felix.resolver.Util.getVersion;
 import static org.apache.karaf.features.internal.resolver.ResourceUtils.getFeatureId;
 import static org.apache.karaf.features.internal.resolver.ResourceUtils.getUri;
+import static org.apache.karaf.features.internal.service.StateStorage.toStringStringSetMap;
 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;
@@ -197,6 +203,55 @@ public class FeaturesServiceImpl implements FeaturesService {
         this.updateSnaphots = updateSnaphots;
         this.globalRepository = globalRepository;
         loadState();
+        checkResolve();
+
+    }
+
+    private void checkResolve() {
+        if (bundle == null) {
+            return; // Most certainly in unit tests
+        }
+        File resolveFile = bundle.getBundleContext().getDataFile("resolve");
+        if (!resolveFile.exists()) {
+            return;
+        }
+        Map<String, Object> request;
+        try(
+            FileInputStream fis = new FileInputStream(resolveFile)
+        ) {
+            request = (Map<String, Object>) JsonReader.read(fis);
+        } catch (IOException e) {
+            LOGGER.warn("Error reading resolution request", e);
+            return;
+        }
+        Map<String, Set<String>> requestedFeatures = toStringStringSetMap((Map) request.get("features"));
+        Collection<String> opts = (Collection<String>) request.get("options");
+        EnumSet<Option> options = EnumSet.noneOf(Option.class);
+        for (String opt : opts) {
+            options.add(Option.valueOf(opt));
+        }
+        // Resolve
+        try {
+            doInstallFeaturesInThread(requestedFeatures, copyState(), options);
+        } catch (Exception e) {
+            LOGGER.warn("Error updating state", e);
+        }
+    }
+
+    private void writeResolve(Map<String, Set<String>> requestedFeatures, EnumSet<Option> options) throws IOException {
+        File resolveFile = bundle.getBundleContext().getDataFile("resolve");
+        Map<String, Object> request = new HashMap<>();
+        List<String> opts = new ArrayList<>();
+        for (Option opt : options) {
+            opts.add(opt.toString());
+        }
+        request.put("features", requestedFeatures);
+        request.put("options", opts);
+        try(
+                FileOutputStream fos = new FileOutputStream(resolveFile);
+        ) {
+            JsonWriter.write(fos, request);
+        }
     }
 
     //
@@ -1025,16 +1080,52 @@ public class FeaturesServiceImpl implements FeaturesService {
         // #10: send events
         //
 
-        // TODO: handle update on the features service itself
+        //
+        // Handle updates on the FeaturesService bundle
+        //
         RegionDeployment rootRegionDeployment = deployment.regions.get(ROOT_REGION);
-        if (rootRegionDeployment != null &&
-                (rootRegionDeployment.toUpdate.containsKey(bundle)
-                        || rootRegionDeployment.toDelete.contains(bundle))) {
-
-            LOGGER.warn("Updating or uninstalling of the FeaturesService is not supported");
-            rootRegionDeployment.toUpdate.remove(bundle);
-            rootRegionDeployment.toDelete.remove(bundle);
-
+        // We don't support uninstalling the bundle
+        if (rootRegionDeployment != null && rootRegionDeployment.toDelete.contains(bundle)) {
+            throw new UnsupportedOperationException("Uninstalling the FeaturesService bundle is not supported");
+        }
+        // If the bundle needs to be updated, do the following:
+        //  - create flag files to indicate the resolution must be continued after restart
+        //  - update the checksum and save the state
+        //  - compute bundles wired to the FeaturesService bundle that will be refreshed
+        //  - stop the bundle
+        //  - update the bundle
+        //  - refresh wired bundles
+        //  - start the bundle
+        //  - exit
+        // When restarting, the resolution will be attempted again
+        if (rootRegionDeployment != null && rootRegionDeployment.toUpdate.containsKey(bundle)) {
+            writeResolve(requestedFeatures, options);
+            // If the bundle is updated because of a different checksum,
+            // save the new checksum persistently
+            if (deployment.bundleChecksums.containsKey(bundle.getBundleId())) {
+                synchronized (lock) {
+                    this.state.bundleChecksums.put(bundle.getBundleId(), deployment.bundleChecksums.get(bundle.getBundleId()));
+                    saveState();
+                }
+            }
+            Resource resource = rootRegionDeployment.toUpdate.get(bundle);
+            String uri = getUri(resource);
+            print("The FeaturesService bundle needs is being updated with " + uri, verbose);
+            toRefresh.clear();
+            toRefresh.add(bundle);
+            computeBundlesToRefresh(toRefresh,
+                    dstate.bundles.values(),
+                    Collections.<Resource, Bundle>emptyMap(),
+                    Collections.<Resource, List<Wire>>emptyMap());
+            bundle.stop(Bundle.STOP_TRANSIENT);
+            try (
+                InputStream is = getBundleInputStream(resource, providers)
+            ) {
+                bundle.update(is);
+            }
+            refreshPackages(toRefresh);
+            bundle.start();
+            return;
         }
 
         //

http://git-wip-us.apache.org/repos/asf/karaf/blob/400e9407/features/core/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java
index 8168994..e6adab0 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java
@@ -70,7 +70,7 @@ public abstract class StateStorage {
     protected abstract InputStream getInputStream() throws IOException;
     protected abstract OutputStream getOutputStream() throws IOException;
 
-    protected Map<String, Set<String>> toStringStringSetMap(Map<?,?> map) {
+    static Map<String, Set<String>> toStringStringSetMap(Map<?,?> map) {
         Map<String, Set<String>> nm = new HashMap<>();
         for (Map.Entry entry : map.entrySet()) {
             nm.put(entry.getKey().toString(), toStringSet((Collection) entry.getValue()));
@@ -78,7 +78,7 @@ public abstract class StateStorage {
         return nm;
     }
 
-    protected Map<String, Set<Long>> toStringLongSetMap(Map<?,?> map) {
+    static  Map<String, Set<Long>> toStringLongSetMap(Map<?,?> map) {
         Map<String, Set<Long>> nm = new HashMap<>();
         for (Map.Entry entry : map.entrySet()) {
             nm.put(entry.getKey().toString(), toLongSet((Collection) entry.getValue()));
@@ -86,7 +86,7 @@ public abstract class StateStorage {
         return nm;
     }
 
-    protected Set<String> toStringSet(Collection<?> col) {
+    static  Set<String> toStringSet(Collection<?> col) {
         Set<String> ns = new TreeSet<>();
         for (Object o : col) {
             ns.add(o.toString());
@@ -94,7 +94,7 @@ public abstract class StateStorage {
         return ns;
     }
 
-    protected Set<Long> toLongSet(Collection<?> set) {
+    static  Set<Long> toLongSet(Collection<?> set) {
         Set<Long> ns = new TreeSet<>();
         for (Object o : set) {
             ns.add(toLong(o));
@@ -102,7 +102,7 @@ public abstract class StateStorage {
         return ns;
     }
 
-    protected Map<Long, Long> toLongLongMap(Map<?,?> map) {
+    static  Map<Long, Long> toLongLongMap(Map<?,?> map) {
         Map<Long, Long> nm = new HashMap<>();
         for (Map.Entry entry : map.entrySet()) {
             nm.put(toLong(entry.getKey()), toLong(entry.getValue()));
@@ -110,7 +110,7 @@ public abstract class StateStorage {
         return nm;
     }
 
-    protected Map<String, Long> toStringLongMap(Map<?,?> map) {
+    static Map<String, Long> toStringLongMap(Map<?,?> map) {
         Map<String, Long> nm = new HashMap<>();
         for (Map.Entry entry : map.entrySet()) {
             nm.put(entry.getKey().toString(), toLong(entry.getValue()));