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);