You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by kw...@apache.org on 2019/12/06 12:05:11 UTC

[sling-org-apache-sling-installer-core] 01/01: SLING-8877 automatically register URL handlers for all UpdateHandler services

This is an automated email from the ASF dual-hosted git repository.

kwin pushed a commit to branch feature/url-handler
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-installer-core.git

commit 1867f9cc0037078c649aa56fa5e234aa011cc981
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Fri Dec 6 13:04:57 2019 +0100

    SLING-8877 automatically register URL handlers for all UpdateHandler
    services
---
 .../core/impl/InstallerResourceUrlHandler.java     | 82 ++++++++++++++++++++++
 .../installer/core/impl/OsgiInstallerImpl.java     |  5 +-
 .../installer/core/impl/UpdateHandlerTracker.java  | 82 ++++++++++++++++++++++
 .../core/impl/tasks/AbstractBundleTask.java        | 12 ++++
 .../core/impl/tasks/BundleInstallTask.java         |  1 +
 .../core/impl/tasks/BundleUpdateTask.java          |  1 +
 6 files changed, 181 insertions(+), 2 deletions(-)

diff --git a/src/main/java/org/apache/sling/installer/core/impl/InstallerResourceUrlHandler.java b/src/main/java/org/apache/sling/installer/core/impl/InstallerResourceUrlHandler.java
new file mode 100644
index 0000000..e2e1550
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/core/impl/InstallerResourceUrlHandler.java
@@ -0,0 +1,82 @@
+/*
+ * 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.sling.installer.core.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.apache.sling.installer.api.info.InfoProvider;
+import org.apache.sling.installer.api.info.ResourceGroup;
+import org.apache.sling.installer.api.tasks.ResourceState;
+import org.apache.sling.installer.core.impl.tasks.AbstractBundleTask;
+import org.osgi.service.url.AbstractURLStreamHandlerService;
+import org.osgi.service.url.URLStreamHandlerService;
+
+/**
+ * URL Handler for schemes used by the UpdateHandlers
+ * 
+ * @see <a href="https://osgi.org/specification/osgi.core/7.0.0/service.url.html#d0e42987">OSGi URL Handlers</a>
+ */
+public class InstallerResourceUrlHandler extends AbstractURLStreamHandlerService implements URLStreamHandlerService {
+
+    private final InfoProvider installerInfo;
+
+    public InstallerResourceUrlHandler(InfoProvider installerInfo) {
+        this.installerInfo = installerInfo;
+    }
+
+    private InputStream getInputStreamFromInstallerResourceUrl(URL url) throws IOException {
+        for (ResourceGroup resourceGroup : installerInfo.getInstallationState().getInstalledResources()) {
+            for (org.apache.sling.installer.api.info.Resource resource : resourceGroup.getResources()) {
+                String bundleLocation = AbstractBundleTask.getBundleLocation(resource);
+                if (url.toString().equals(bundleLocation) && resource.getState().equals(ResourceState.INSTALLED)) {
+                    return resource.getInputStream();
+                }
+            }
+        }
+        throw new IOException("Could not find OSGi installer resource with location " + url);
+    }
+
+    @Override
+    public URLConnection openConnection(URL url) throws IOException {
+        return new InputStreamConnection(url, getInputStreamFromInstallerResourceUrl(url));
+    }
+
+    private static final class InputStreamConnection extends URLConnection {
+
+        private final InputStream input;
+        
+        protected InputStreamConnection(URL url, InputStream input) {
+            super(url);
+            this.input = input;
+        }
+
+        @Override
+        public void connect() throws IOException {
+        }
+
+        @Override
+        public InputStream getInputStream() throws IOException {
+            return input;
+        }
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/installer/core/impl/OsgiInstallerImpl.java b/src/main/java/org/apache/sling/installer/core/impl/OsgiInstallerImpl.java
index b60685c..15ae3ed 100644
--- a/src/main/java/org/apache/sling/installer/core/impl/OsgiInstallerImpl.java
+++ b/src/main/java/org/apache/sling/installer/core/impl/OsgiInstallerImpl.java
@@ -70,6 +70,7 @@ import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.Version;
 import org.osgi.service.startlevel.StartLevel;
+import org.osgi.service.url.URLStreamHandlerService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -138,7 +139,7 @@ implements OsgiInstaller, ResourceChangeListener, RetryHandler, InfoProvider, Ru
     private SortingServiceTracker<ResourceTransformer> transformerTracker;
 
     /** A tracker for update handlers. */
-    private SortingServiceTracker<UpdateHandler> updateHandlerTracker;
+    private UpdateHandlerTracker updateHandlerTracker;
 
     /** A tracker for the factories. */
     private SortingServiceTracker<ResourceUpdater> updaterTracker;
@@ -236,7 +237,7 @@ implements OsgiInstaller, ResourceChangeListener, RetryHandler, InfoProvider, Ru
         // start service trackers
         this.factoryTracker = new SortingServiceTracker<>(ctx, InstallTaskFactory.class.getName(), this);
         this.transformerTracker = new SortingServiceTracker<>(ctx, ResourceTransformer.class.getName(), this);
-        this.updateHandlerTracker = new SortingServiceTracker<>(ctx, UpdateHandler.class.getName(), null);
+        this.updateHandlerTracker = new UpdateHandlerTracker(ctx, this);
         this.updaterTracker = new SortingServiceTracker<>(ctx, ResourceUpdater.class.getName(), this);
         this.factoryTracker.open();
         this.transformerTracker.open();
diff --git a/src/main/java/org/apache/sling/installer/core/impl/UpdateHandlerTracker.java b/src/main/java/org/apache/sling/installer/core/impl/UpdateHandlerTracker.java
new file mode 100644
index 0000000..67549cc
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/core/impl/UpdateHandlerTracker.java
@@ -0,0 +1,82 @@
+/*
+ * 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.sling.installer.core.impl;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.installer.api.UpdateHandler;
+import org.apache.sling.installer.api.info.InfoProvider;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.url.URLConstants;
+import org.osgi.service.url.URLStreamHandlerService;
+
+public class UpdateHandlerTracker extends SortingServiceTracker<UpdateHandler> {
+
+    private final InfoProvider infoProvider;
+    private final Map<ServiceReference, ServiceRegistration<URLStreamHandlerService>> urlHandlers;
+    public UpdateHandlerTracker(BundleContext ctx, InfoProvider infoProvider) {
+        super(ctx, UpdateHandler.class.getName(), null);
+        this.infoProvider = infoProvider;
+        this.urlHandlers = new HashMap<>();
+    }
+
+    @Override
+    public Object addingService(ServiceReference reference) {
+        final String[] schemes = PropertiesUtil.toStringArray(reference.getProperty(UpdateHandler.PROPERTY_SCHEMES));
+        if (schemes != null && schemes.length > 0) {
+            addUrlHandler(schemes);
+        }
+        return super.addingService(reference);
+    }
+
+    private ServiceRegistration<URLStreamHandlerService> addUrlHandler(String[] schemes) {
+        InstallerResourceUrlHandler service = new InstallerResourceUrlHandler(infoProvider);
+        Dictionary<String, String[]> properties = new Hashtable<>();
+        properties.put(URLConstants.URL_HANDLER_PROTOCOL, schemes);
+        return context.registerService(URLStreamHandlerService.class, service, properties);
+        
+    }
+    
+    private void removeUrlHandler(ServiceReference serviceReference) {
+        ServiceRegistration<URLStreamHandlerService> urlHandler = urlHandlers.get(serviceReference);
+        if (urlHandler != null) {
+            urlHandler.unregister();
+        }
+    }
+
+    @Override
+    public void removedService(ServiceReference reference, Object service) {
+        removeUrlHandler(reference);
+        super.removedService(reference, service);
+    }
+
+    @Override
+    public void close() {
+        for (ServiceReference serviceReference : urlHandlers.keySet()) {
+            removeUrlHandler(serviceReference);
+        }
+        super.close();
+    }
+}
diff --git a/src/main/java/org/apache/sling/installer/core/impl/tasks/AbstractBundleTask.java b/src/main/java/org/apache/sling/installer/core/impl/tasks/AbstractBundleTask.java
index 6c935f9..b5587c1 100644
--- a/src/main/java/org/apache/sling/installer/core/impl/tasks/AbstractBundleTask.java
+++ b/src/main/java/org/apache/sling/installer/core/impl/tasks/AbstractBundleTask.java
@@ -19,6 +19,8 @@
 package org.apache.sling.installer.core.impl.tasks;
 
 import org.apache.sling.installer.api.InstallableResource;
+import org.apache.sling.installer.api.info.Resource;
+import org.apache.sling.installer.api.tasks.TaskResource;
 import org.apache.sling.installer.api.tasks.TaskResourceGroup;
 import org.apache.sling.installer.core.impl.AbstractInstallTask;
 
@@ -27,10 +29,20 @@ import org.apache.sling.installer.core.impl.AbstractInstallTask;
  */
 public abstract class AbstractBundleTask extends AbstractInstallTask {
 
+    public final static String ATTRIBUTE_BUNDLE_LOCATION = "Bundle-Location";
+    
     public AbstractBundleTask(final TaskResourceGroup erl, final TaskSupport support) {
         super(erl, support);
     }
 
+    public static void setBundleLocation(TaskResource resource, String location) {
+        resource.setAttribute(ATTRIBUTE_BUNDLE_LOCATION, location);
+    }
+
+    public static String getBundleLocation(Resource resource) {
+        return (String) resource.getAttribute(ATTRIBUTE_BUNDLE_LOCATION);
+    }
+
     /**
      * Detect the start level for the resource.
      */
diff --git a/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleInstallTask.java b/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleInstallTask.java
index 7127e0a..6420eef 100644
--- a/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleInstallTask.java
+++ b/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleInstallTask.java
@@ -46,6 +46,7 @@ public class BundleInstallTask extends AbstractBundleTask {
         try {
             final Bundle b = this.getBundleContext().installBundle(getResource().getURL(), getResource().getInputStream());
             ctx.log("Installed bundle {} from resource {}", b, getResource());
+            setBundleLocation(getResource(), getResource().getURL());
             // optionally set the start level
             if ( startLevel > 0 ) {
                 final BundleStartLevel startLevelService = b.adapt(BundleStartLevel.class);
diff --git a/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleUpdateTask.java b/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleUpdateTask.java
index 8960ffc..4cd94bd 100644
--- a/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleUpdateTask.java
+++ b/src/main/java/org/apache/sling/installer/core/impl/tasks/BundleUpdateTask.java
@@ -102,6 +102,7 @@ public class BundleUpdateTask extends AbstractBundleTask {
             b.update(getResource().getInputStream());
             ctx.log("Updated bundle {} from resource {}", b, getResource());
 
+            setBundleLocation(getResource(), b.getLocation());
             // start level handling - after update to avoid starting the bundle
             // just before the update
             final BundleStartLevel startLevelService = b.adapt(BundleStartLevel.class);