Introduce runtime manager
[lgpl/argeo-commons.git] / org.argeo.init / src / org / argeo / init / a2 / ProvisioningManager.java
index 6d842650c2620fd2d26249bf69d7d741a37aa3fd..80006264c6cbb4b4acb7bd894a6142b16ab4b87f 100644 (file)
@@ -1,5 +1,8 @@
 package org.argeo.init.a2;
 
+import static org.argeo.init.a2.A2Source.SCHEME_A2;
+import static org.argeo.init.a2.A2Source.SCHEME_A2_REFERENCE;
+
 import java.io.File;
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
@@ -9,7 +12,6 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -25,7 +27,6 @@ import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.Version;
-import org.osgi.framework.launch.Framework;
 import org.osgi.framework.wiring.FrameworkWiring;
 
 /** Loads provisioning sources into an OSGi context. */
@@ -54,8 +55,8 @@ public class ProvisioningManager {
                                        updatedBundles.add(bundle);
                        }
                }
-               FrameworkWiring frameworkWiring = bc.getBundle(0).adapt(FrameworkWiring.class);
-               frameworkWiring.refreshBundles(updatedBundles);
+//             FrameworkWiring frameworkWiring = bc.getBundle(0).adapt(FrameworkWiring.class);
+//             frameworkWiring.refreshBundles(updatedBundles);
        }
 
        public void registerSource(String uri) {
@@ -65,14 +66,22 @@ public class ProvisioningManager {
                        // XOR
                        Map<String, List<String>> properties = queryToMap(u);
                        Map<String, String> xOr = new HashMap<>();
+                       List<String> includes = null;
+                       List<String> excludes = null;
                        for (String key : properties.keySet()) {
                                List<String> lst = properties.get(key);
-                               if (lst.size() != 1)
-                                       throw new IllegalArgumentException("Invalid XOR definitions in " + uri);
-                               xOr.put(key, lst.get(0));
+                               if (A2Source.INCLUDE.equals(key)) {
+                                       includes = new ArrayList<>(lst);
+                               } else if (A2Source.EXCLUDE.equals(key)) {
+                                       excludes = new ArrayList<>(lst);
+                               } else {
+                                       if (lst.size() != 1)
+                                               throw new IllegalArgumentException("Invalid XOR definitions in " + uri);
+                                       xOr.put(key, lst.get(0));
+                               }
                        }
 
-                       if (A2Source.SCHEME_A2.equals(u.getScheme())) {
+                       if (SCHEME_A2.equals(u.getScheme()) || SCHEME_A2_REFERENCE.equals(u.getScheme())) {
                                if (u.getHost() == null || "".equals(u.getHost())) {
                                        String baseStr = u.getPath();
                                        if (File.separatorChar == '\\') {// MS Windows
@@ -80,12 +89,31 @@ public class ProvisioningManager {
                                        }
                                        Path base = Paths.get(baseStr);
                                        if (Files.exists(base)) {
-                                               FsA2Source source = new FsA2Source(base, xOr);
+                                               FsA2Source source = new FsA2Source(base, xOr, SCHEME_A2_REFERENCE.equals(u.getScheme()),
+                                                               includes, excludes);
                                                source.load();
                                                addSource(source);
                                                OsgiBootUtils.info("Registered " + uri + " as source");
+
+                                               // OS specific / native
+                                               String localRelPath = A2Contribution.localOsArchRelativePath();
+                                               Path localLibBase = base.resolve(A2Contribution.LIB).resolve(localRelPath);
+                                               if (Files.exists(localLibBase)) {
+                                                       FsA2Source libSource = new FsA2Source(localLibBase, xOr,
+                                                                       SCHEME_A2_REFERENCE.equals(u.getScheme()), includes, excludes);
+                                                       libSource.load();
+                                                       addSource(libSource);
+                                                       OsgiBootUtils.info("Registered OS-specific " + uri + " as source (" + localRelPath + ")");
+                                               }
+                                       } else {
+                                               OsgiBootUtils.debug("Source " + base + " does not exist, ignoring.");
                                        }
+                               } else {
+                                       throw new UnsupportedOperationException(
+                                                       "Remote installation is not yet supported, cannot add source " + u);
                                }
+                       } else {
+                               throw new IllegalArgumentException("Unkown scheme: for source " + u);
                        }
                } catch (Exception e) {
                        throw new A2Exception("Cannot add source " + uri, e);
@@ -130,21 +158,34 @@ public class ProvisioningManager {
                        Version moduleVersion = module.getVersion();
                        A2Branch osgiBranch = osgiContext.findBranch(module.getBranch().getComponent().getId(), moduleVersion);
                        if (osgiBranch == null) {
-//                             Bundle bundle = bc.installBundle(module.getBranch().getCoordinates(),
-//                                             moduleSource.newInputStream(module.getLocator()));
                                Bundle bundle = moduleSource.install(bc, module);
-                               if (OsgiBootUtils.isDebug())
-                                       OsgiBootUtils.debug("Installed bundle " + bundle.getLocation() + " with version " + moduleVersion);
+                               // TODO make it more dynamic, based on OSGi APIs
+                               osgiContext.registerBundle(bundle);
+//                             if (OsgiBootUtils.isDebug())
+//                                     OsgiBootUtils.debug("Installed bundle " + bundle.getLocation() + " with version " + moduleVersion);
                                return bundle;
                        } else {
                                A2Module lastOsgiModule = osgiBranch.last();
                                int compare = moduleVersion.compareTo(lastOsgiModule.getVersion());
-                               if (compare > 0) {// update
+                               if (compare >= 0) {// update (also if same version)
                                        Bundle bundle = (Bundle) lastOsgiModule.getLocator();
-//                                     bundle.update(moduleSource.newInputStream(module.getLocator()));
+                                       if (bundle.getBundleId() == 0)// ignore framework bundle
+                                               return null;
                                        moduleSource.update(bundle, module);
-                                       OsgiBootUtils.info("Updated bundle " + bundle.getLocation() + " to version " + moduleVersion);
+                                       // TODO make it more dynamic, based on OSGi APIs
+                                       // TODO remove old module? Or keep update history?
+                                       osgiContext.registerBundle(bundle);
+                                       if (compare == 0)
+                                               OsgiBootUtils
+                                                               .debug("Updated bundle " + bundle.getLocation() + " to same version " + moduleVersion);
+                                       else
+                                               OsgiBootUtils.info("Updated bundle " + bundle.getLocation() + " to version " + moduleVersion);
                                        return bundle;
+                               } else {
+                                       if (OsgiBootUtils.isDebug())
+                                               OsgiBootUtils.debug("Did not install as bundle module " + module
+                                                               + " since a module with higher version " + lastOsgiModule.getVersion()
+                                                               + " is already installed for branch " + osgiBranch);
                                }
                        }
                } catch (Exception e) {
@@ -217,46 +258,46 @@ public class ProvisioningManager {
                }
        }
 
-       public static void main(String[] args) {
-               if (args.length == 0)
-                       throw new IllegalArgumentException("Usage: <path to A2 base>");
-               Map<String, String> configuration = new HashMap<>();
-               configuration.put("osgi.console", "2323");
-               configuration.put("org.osgi.framework.bootdelegation",
-                               "com.sun.jndi.ldap,com.sun.jndi.ldap.sasl,com.sun.security.jgss,com.sun.jndi.dns,com.sun.nio.file,com.sun.nio.sctp,sun.nio.cs");
-               Framework framework = OsgiBootUtils.launch(configuration);
-               try {
-                       ProvisioningManager pm = new ProvisioningManager(framework.getBundleContext());
-                       Map<String, String> xOr = new HashMap<>();
-                       xOr.put("osgi", "equinox");
-                       xOr.put("swt", "rap");
-                       FsA2Source context = new FsA2Source(Paths.get(args[0]), xOr);
-                       context.load();
-                       pm.addSource(context);
-                       if (framework.getBundleContext().getBundles().length == 1) {// initial
-                               pm.install(null);
-                       } else {
-                               pm.update();
-                       }
-
-                       Thread.sleep(2000);
-
-                       Bundle[] bundles = framework.getBundleContext().getBundles();
-                       Arrays.sort(bundles, (b1, b2) -> b1.getSymbolicName().compareTo(b2.getSymbolicName()));
-                       for (Bundle b : bundles)
-                               if (b.getState() == Bundle.RESOLVED || b.getState() == Bundle.STARTING || b.getState() == Bundle.ACTIVE)
-                                       System.out.println(b.getSymbolicName() + " " + b.getVersion());
-                               else
-                                       System.err.println(b.getSymbolicName() + " " + b.getVersion() + " (" + b.getState() + ")");
-               } catch (Exception e) {
-                       e.printStackTrace();
-               } finally {
-                       try {
-                               framework.stop();
-                       } catch (Exception e) {
-                               e.printStackTrace();
-                       }
-               }
-       }
+//     public static void main(String[] args) {
+//             if (args.length == 0)
+//                     throw new IllegalArgumentException("Usage: <path to A2 base>");
+//             Map<String, String> configuration = new HashMap<>();
+//             configuration.put("osgi.console", "2323");
+//             configuration.put("org.osgi.framework.bootdelegation",
+//                             "com.sun.jndi.ldap,com.sun.jndi.ldap.sasl,com.sun.security.jgss,com.sun.jndi.dns,com.sun.nio.file,com.sun.nio.sctp,sun.nio.cs");
+//             Framework framework = OsgiBootUtils.launch(configuration);
+//             try {
+//                     ProvisioningManager pm = new ProvisioningManager(framework.getBundleContext());
+//                     Map<String, String> xOr = new HashMap<>();
+//                     xOr.put("osgi", "equinox");
+//                     xOr.put("swt", "rap");
+//                     FsA2Source context = new FsA2Source(Paths.get(args[0]), xOr);
+//                     context.load();
+//                     pm.addSource(context);
+//                     if (framework.getBundleContext().getBundles().length == 1) {// initial
+//                             pm.install(null);
+//                     } else {
+//                             pm.update();
+//                     }
+//
+//                     Thread.sleep(2000);
+//
+//                     Bundle[] bundles = framework.getBundleContext().getBundles();
+//                     Arrays.sort(bundles, (b1, b2) -> b1.getSymbolicName().compareTo(b2.getSymbolicName()));
+//                     for (Bundle b : bundles)
+//                             if (b.getState() == Bundle.RESOLVED || b.getState() == Bundle.STARTING || b.getState() == Bundle.ACTIVE)
+//                                     System.out.println(b.getSymbolicName() + " " + b.getVersion());
+//                             else
+//                                     System.err.println(b.getSymbolicName() + " " + b.getVersion() + " (" + b.getState() + ")");
+//             } catch (Exception e) {
+//                     e.printStackTrace();
+//             } finally {
+//                     try {
+//                             framework.stop();
+//                     } catch (Exception e) {
+//                             e.printStackTrace();
+//                     }
+//             }
+//     }
 
 }