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 <[email protected]> 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);
