You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicemix.apache.org by gn...@apache.org on 2008/04/01 15:41:47 UTC

svn commit: r643395 - in /servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features: Feature.java internal/FeatureImpl.java internal/FeaturesServiceImpl.java internal/RepositoryImpl.java

Author: gnodet
Date: Tue Apr  1 06:41:40 2008
New Revision: 643395

URL: http://svn.apache.org/viewvc?rev=643395&view=rev
Log:
SMX4KNL-25: Improve features service

Modified:
    servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/Feature.java
    servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/internal/FeatureImpl.java
    servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/internal/FeaturesServiceImpl.java
    servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/internal/RepositoryImpl.java

Modified: servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/Feature.java
URL: http://svn.apache.org/viewvc/servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/Feature.java?rev=643395&r1=643394&r2=643395&view=diff
==============================================================================
--- servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/Feature.java (original)
+++ servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/Feature.java Tue Apr  1 06:41:40 2008
@@ -26,6 +26,8 @@
 
     String getName();
 
+    List<String> getDependencies();
+
     List<String> getBundles();
 
     Map<String, Map<String, String>> getConfigurations();

Modified: servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/internal/FeatureImpl.java
URL: http://svn.apache.org/viewvc/servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/internal/FeatureImpl.java?rev=643395&r1=643394&r2=643395&view=diff
==============================================================================
--- servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/internal/FeatureImpl.java (original)
+++ servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/internal/FeatureImpl.java Tue Apr  1 06:41:40 2008
@@ -29,6 +29,7 @@
 public class FeatureImpl implements Feature {
 
     private String name;
+    private List<String> dependencies = new ArrayList<String>();
     private List<String> bundles = new ArrayList<String>();
     private Map<String, Map<String,String>> configs = new HashMap<String, Map<String,String>>();
 
@@ -40,12 +41,20 @@
         return name;
     }
 
+    public List<String> getDependencies() {
+        return dependencies;
+    }
+
     public List<String> getBundles() {
         return bundles;
     }
 
     public Map<String, Map<String, String>> getConfigurations() {
         return configs;
+    }
+
+    public void addDependency(String dependency) {
+        dependencies.add(dependency);
     }
 
     public void addBundle(String bundle) {

Modified: servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/internal/FeaturesServiceImpl.java
URL: http://svn.apache.org/viewvc/servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/internal/FeaturesServiceImpl.java?rev=643395&r1=643394&r2=643395&view=diff
==============================================================================
--- servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/internal/FeaturesServiceImpl.java (original)
+++ servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/internal/FeaturesServiceImpl.java Tue Apr  1 06:41:40 2008
@@ -16,7 +16,9 @@
  */
 package org.apache.servicemix.gshell.features.internal;
 
+import java.io.BufferedInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
@@ -25,17 +27,27 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.servicemix.gshell.features.Feature;
 import org.apache.servicemix.gshell.features.FeaturesService;
 import org.apache.servicemix.gshell.features.Repository;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
 import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.Version;
+import org.osgi.framework.BundleException;
 import org.osgi.service.cm.Configuration;
 import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.prefs.BackingStoreException;
+import org.osgi.service.prefs.Preferences;
 import org.osgi.service.prefs.PreferencesService;
 import org.springframework.osgi.context.BundleContextAware;
 
@@ -50,12 +62,15 @@
 
     private static final String ALIAS_KEY = "_alias_factory_pid";
 
+    private static final Log LOGGER = LogFactory.getLog(FeaturesServiceImpl.class);
+
     private BundleContext bundleContext;
     private ConfigurationAdmin configAdmin;
     private PreferencesService preferences;
     private Set<URL> urls;
     private Map<URL, RepositoryImpl> repositories = new HashMap<URL, RepositoryImpl>();
     private Map<String, Feature> features;
+    private Set<String> installed = new HashSet<String>();
 
     public BundleContext getBundleContext() {
         return bundleContext;
@@ -90,6 +105,11 @@
     }
 
     public void addRepository(URL url) throws Exception {
+        internalAddRepository(url);
+        saveState();
+    }
+
+    protected void internalAddRepository(URL url) throws Exception {
         RepositoryImpl repo = new RepositoryImpl(url);
         repositories.put(url, repo);
         features = null;
@@ -101,6 +121,11 @@
     }
 
     public void removeRepository(URL url) {
+        internalRemoveRepository(url);
+        saveState();
+    }
+
+    public void internalRemoveRepository(URL url) {
         Repository repo = repositories.remove(url);
         features = null;
     }
@@ -115,6 +140,9 @@
         if (f == null) {
             throw new Exception("No feature named '" + name + "' available");
         }
+        for (String dependency : f.getDependencies()) {
+            installFeature(dependency);
+        }
         for (String config : f.getConfigurations().keySet()) {
             Dictionary<String,String> props = new Hashtable<String, String>(f.getConfigurations().get(config));
             String[] pid = parsePid(config);
@@ -127,14 +155,51 @@
             }
             cfg.update(props);
         }
-        for (String bundle : f.getBundles()) {
-            Bundle b = getBundleContext().installBundle(bundle, null);
+        for (String bundleLocation : f.getBundles()) {
+            Bundle b = installBundleIfNeeded(bundleLocation);
             b.start();
         }
+        installed.add(name);
+        saveState();
+    }
+
+    protected Bundle installBundleIfNeeded(String bundleLocation) throws IOException, BundleException {
+        LOGGER.debug("Checking " + bundleLocation);
+        InputStream is = new BufferedInputStream(new URL(bundleLocation).openStream());
+        try {
+            is.mark(256 * 1024);
+            JarInputStream jar = new JarInputStream(is);
+            Manifest m = jar.getManifest();
+            String sn = m.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
+            String vStr = m.getMainAttributes().getValue(Constants.BUNDLE_VERSION);
+            Version v = vStr == null ? Version.emptyVersion : Version.parseVersion(vStr);
+            boolean install = true;
+            for (Bundle b : bundleContext.getBundles()) {
+                if (b.getSymbolicName().equals(sn)) {
+                    vStr = (String) b.getHeaders().get(Constants.BUNDLE_VERSION);
+                    Version bv = vStr == null ? Version.emptyVersion : Version.parseVersion(vStr);
+                    if (v.equals(bv)) {
+                        LOGGER.debug("  found installed bundle: " + b);
+                        return b;
+                    }
+                }
+            }
+            try {
+                is.reset();
+            } catch (IOException e) {
+                is.close();
+                is = new BufferedInputStream(new URL(bundleLocation).openStream());
+            }
+            LOGGER.debug("Installing bundle " + bundleLocation);
+            return getBundleContext().installBundle(bundleLocation, is);
+        } finally {
+            is.close();
+        }
     }
 
     public void uninstallFeature(String name) throws Exception {
-        //To change body of implemented methods use File | Settings | File Templates.
+        // TODO
+        //saveState();
     }
 
     public String[] listFeatures() {
@@ -148,7 +213,7 @@
     }
 
     public String[] listInstalledFeatures() {
-        return new String[0];  //To change body of implemented methods use File | Settings | File Templates.
+        return installed.toArray(new String[installed.size()]);
     }
 
     protected Feature getFeature(String name) {
@@ -169,17 +234,20 @@
     }
 
     public void start() throws Exception {
-        if (urls != null) {
-            for (URL url : urls) {
-                addRepository(url);
+        if (!loadState()) {
+            if (urls != null) {
+                for (URL url : urls) {
+                    internalAddRepository(url);
+                }
             }
+            saveState();
         }
     }
 
     public void stop() throws Exception {
         urls = new HashSet<URL>(repositories.keySet());
         while (!repositories.isEmpty()) {
-            removeRepository(repositories.keySet().iterator().next());
+            internalRemoveRepository(repositories.keySet().iterator().next());
         }
     }
 
@@ -206,6 +274,52 @@
         } else {
             return configurationAdmin.getConfiguration(pid, null);
         }
+    }
+    
+    protected void saveState() {
+        try {
+            Preferences prefs = preferences.getUserPreferences("FeaturesServiceState");
+            saveSet(prefs.node("repositories"), repositories.keySet());
+            saveSet(prefs.node("features"), installed);
+            prefs.flush();
+        } catch (Exception e) {
+            LOGGER.error("Error persisting FeaturesService state", e);
+        }
+    }
+
+    protected boolean loadState() {
+        try {
+            Preferences prefs = preferences.getUserPreferences("FeaturesServiceState");
+            if (prefs.nodeExists("repositories")) {
+                Set<String> repositories = loadSet(prefs.node("repositories"));
+                for (String repo : repositories) {
+                    internalAddRepository(new URL(repo));
+                }
+                installed = loadSet(prefs.node("features"));
+                return true;
+            }
+        } catch (Exception e) {
+            LOGGER.error("Error loading FeaturesService state", e);
+        }
+        return false;
+    }
+
+    protected void saveSet(Preferences node, Set set) throws BackingStoreException {
+        List l = new ArrayList(set);
+        node.clear();
+        node.putInt("count", l.size());
+        for (int i = 0; i < l.size(); i++) {
+            node.put("item." + i, l.get(i).toString());
+        }
+    }
+
+    protected Set<String> loadSet(Preferences node) {
+        Set<String> l = new HashSet<String>();
+        int count = node.getInt("count", 0);
+        for (int i = 0; i < count; i++) {
+            l.add(node.get("item." + i, null));
+        }
+        return l;
     }
 
 }

Modified: servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/internal/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/internal/RepositoryImpl.java?rev=643395&r1=643394&r2=643395&view=diff
==============================================================================
--- servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/internal/RepositoryImpl.java (original)
+++ servicemix/smx4/kernel/trunk/gshell/gshell-features/src/main/java/org/apache/servicemix/gshell/features/internal/RepositoryImpl.java Tue Apr  1 06:41:40 2008
@@ -66,6 +66,11 @@
                 Element e = (Element) nodes.item(i);
                 String name = e.getAttribute("name");
                 FeatureImpl f = new FeatureImpl(name);
+                NodeList featureNodes = e.getElementsByTagName("feature");
+                for (int j = 0; j < featureNodes.getLength(); j++) {
+                    Element b = (Element) featureNodes.item(j);
+                    f.addDependency(b.getTextContent());
+                }
                 NodeList configNodes = e.getElementsByTagName("config");
                 for (int j = 0; j < configNodes.getLength(); j++) {
                     Element c = (Element) configNodes.item(j);