--- /dev/null
+package org.argeo.osgi.boot.a2;
+
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.argeo.osgi.boot.OsgiBootException;
+import org.argeo.osgi.boot.OsgiBootUtils;
+import org.eclipse.osgi.launch.EquinoxFactory;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+import org.osgi.framework.launch.Framework;
+import org.osgi.framework.launch.FrameworkFactory;
+import org.osgi.framework.wiring.FrameworkWiring;
+
+public class ProvisioningManager {
+ BundleContext bc;
+ OsgiContext osgiContext;
+ List<ProvisioningSource> sources = Collections.synchronizedList(new ArrayList<>());
+
+ public ProvisioningManager(BundleContext bc) {
+ this.bc = bc;
+ osgiContext = new OsgiContext(bc);
+ osgiContext.load();
+ }
+
+ void addSource(ProvisioningSource context) {
+ sources.add(context);
+ }
+
+ void installWholeSource(ProvisioningSource context) {
+ Set<Bundle> updatedBundles = new HashSet<>();
+ for (A2Contribution contribution : context.contributions.values()) {
+ for (A2Component component : contribution.components.values()) {
+ A2Module module = component.last().last();
+ Bundle bundle = installOrUpdate(module);
+ if (bundle != null)
+ updatedBundles.add(bundle);
+ }
+ }
+ FrameworkWiring frameworkWiring = bc.getBundle(0).adapt(FrameworkWiring.class);
+ frameworkWiring.refreshBundles(updatedBundles);
+ }
+
+ public void registerSource(String uri) {
+ try {
+ URI u = new URI(uri);
+ if ("a2".equals(u.getScheme())) {
+ if (u.getHost() == null || "".equals(u.getHost())) {
+ Path base = Paths.get(u.getPath());
+ FsA2Source source = new FsA2Source(base);
+ source.load();
+ addSource(source);
+ }
+ }
+ } catch (Exception e) {
+ throw new OsgiBootException("Cannot add source " + uri, e);
+ }
+ }
+
+ public boolean registerDefaultSource() {
+ String frameworkLocation = bc.getProperty("osgi.framework");
+ try {
+ URI frameworkLocationUri = new URI(frameworkLocation);
+ if ("file".equals(frameworkLocationUri.getScheme())) {
+ Path frameworkPath = Paths.get(frameworkLocationUri);
+ if (frameworkPath.getParent().getFileName().toString().equals(A2Contribution.BOOT)) {
+ Path base = frameworkPath.getParent().getParent();
+ URI baseUri = new URI("a2", null, null, 0, base.toString(), null, null);
+ registerSource(baseUri.toString());
+ OsgiBootUtils.info("Registered " + baseUri + " as default source");
+ return true;
+ }
+ }
+ } catch (Exception e) {
+ OsgiBootUtils.error("Cannot register default source based on framework location " + frameworkLocation, e);
+ }
+ return false;
+ }
+
+ public void install(String spec) {
+ if (spec == null) {
+ for (ProvisioningSource source : sources) {
+ installWholeSource(source);
+ }
+ }
+ }
+
+ /** @return the new/updated bundle, or null if nothign was done. */
+ Bundle installOrUpdate(A2Module module) {
+ try {
+ ProvisioningSource moduleSource = module.getBranch().getComponent().getContribution().getSource();
+ 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()));
+ 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
+ Bundle bundle = (Bundle) lastOsgiModule.getLocator();
+ bundle.update(moduleSource.newInputStream(module.getLocator()));
+ OsgiBootUtils.info("Updated bundle " + bundle.getLocation() + " to version " + moduleVersion);
+ return bundle;
+ }
+ }
+ } catch (Exception e) {
+ OsgiBootUtils.error("Could not install module " + module, e);
+ }
+ return null;
+ }
+
+ public Collection<Bundle> update() {
+ boolean fragmentsUpdated = false;
+ Set<Bundle> updatedBundles = new HashSet<>();
+ bundles: for (Bundle bundle : bc.getBundles()) {
+ for (ProvisioningSource source : sources) {
+ String componentId = bundle.getSymbolicName();
+ Version version = bundle.getVersion();
+ A2Branch branch = source.findBranch(componentId, version);
+ if (branch == null)
+ continue bundles;
+ A2Module module = branch.last();
+ Version moduleVersion = module.getVersion();
+ int compare = moduleVersion.compareTo(version);
+ if (compare > 0) {// update
+ try (InputStream in = source.newInputStream(module.getLocator())) {
+ bundle.update(in);
+ String fragmentHost = bundle.getHeaders().get(Constants.FRAGMENT_HOST);
+ if (fragmentHost != null)
+ fragmentsUpdated = true;
+ OsgiBootUtils.info("Updated bundle " + bundle.getLocation() + " to version " + moduleVersion);
+ updatedBundles.add(bundle);
+ } catch (Exception e) {
+ OsgiBootUtils.error("Cannot update with module " + module, e);
+ }
+ }
+ }
+ }
+ FrameworkWiring frameworkWiring = bc.getBundle(0).adapt(FrameworkWiring.class);
+ if (fragmentsUpdated)// refresh all
+ frameworkWiring.refreshBundles(null);
+ else
+ frameworkWiring.refreshBundles(updatedBundles);
+ return updatedBundles;
+ }
+
+ private static Framework launch() {
+ // start OSGi
+ FrameworkFactory frameworkFactory = new EquinoxFactory();
+ Map<String, String> configuration = new HashMap<>();
+ configuration.put("osgi.console", "2323");
+ Framework framework = frameworkFactory.newFramework(configuration);
+ try {
+ framework.start();
+ } catch (BundleException e) {
+ throw new OsgiBootException("Cannot start OSGi framework", e);
+ }
+ return framework;
+ }
+
+ public static void main(String[] args) {
+ Framework framework = launch();
+ try {
+ ProvisioningManager pm = new ProvisioningManager(framework.getBundleContext());
+ FsA2Source context = new FsA2Source(Paths.get(
+ "/home/mbaudier/dev/git/apache2/argeo-commons/dist/argeo-node/target/argeo-node-2.1.74-SNAPSHOT/argeo-node/share/osgi"));
+ context.load();
+ if (framework.getBundleContext().getBundles().length == 1) {// initial
+ pm.install(null);
+ } else {
+ pm.update();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ // framework.stop();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+}