/* * Licensed 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.aries.subsystem.core.internal; import java.io.InputStream; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.aries.util.io.IOUtils; import org.osgi.framework.Bundle; import org.osgi.framework.Version; import org.osgi.framework.startlevel.BundleStartLevel; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.BundleWiring; import org.osgi.namespace.service.ServiceNamespace; import org.osgi.resource.Capability; import org.osgi.resource.Requirement; import org.osgi.resource.Resource; import org.osgi.service.coordinator.Coordination; import org.osgi.service.subsystem.SubsystemException; public class BundleResourceInstaller extends ResourceInstaller { /* * Maps a BundleResource to a BundleRevision for the purpose of tracking * any service requirements or capabilities. The instance is given to the * Subsystems data structure as the constituent object. * * The resource variable is allowed to be null so this class can be used * when removing constituents from the data structure; however, note that * service capabilities and requirements will not be available. */ static class BundleConstituent implements BundleRevision { private final Resource resource; private final BundleRevision revision; public BundleConstituent(Resource resource, BundleRevision revision) { if (resource instanceof BundleRevision) { try { this.resource = new BundleRevisionResource((BundleRevision)resource); } catch (SubsystemException e) { throw e; } catch (Exception e) { throw new SubsystemException(e); } } else this.resource = resource; this.revision = revision; } @Override public List<Capability> getCapabilities(String namespace) { List<Capability> result = new ArrayList<Capability>(revision.getCapabilities(namespace)); if (resource != null && (namespace == null || ServiceNamespace.SERVICE_NAMESPACE.equals(namespace))) for (Capability capability : resource.getCapabilities(ServiceNamespace.SERVICE_NAMESPACE)) result.add(new BasicCapability.Builder() .namespace(capability.getNamespace()) .attributes(capability.getAttributes()) .directives(capability.getDirectives()) // Use the BundleRevision as the resource so it can be identified as a // runtime resource within the system repository. .resource(revision) .build()); return Collections.unmodifiableList(result); } @Override public List<Requirement> getRequirements(String namespace) { List<Requirement> result = new ArrayList<Requirement>(revision.getRequirements(namespace)); if (resource != null && (namespace == null || ServiceNamespace.SERVICE_NAMESPACE.equals(namespace))) for (Requirement requiremnet : resource.getRequirements(ServiceNamespace.SERVICE_NAMESPACE)) result.add(new BasicRequirement.Builder() .namespace(requiremnet.getNamespace()) .attributes(requiremnet.getAttributes()) .directives(requiremnet.getDirectives()) // Use the BundleRevision as the resource so it can be identified as a // runtime resource within the system repository. .resource(revision) .build()); return Collections.unmodifiableList(result); } @Override public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof BundleConstituent)) return false; BundleConstituent that = (BundleConstituent)o; return revision.equals(that.revision); } @Override public int hashCode() { int result = 17; result = 31 * result + revision.hashCode(); return result; } @Override public Bundle getBundle() { return revision.getBundle(); } public Resource getResource() { return resource; } public BundleRevision getRevision() { return revision; } @Override public String getSymbolicName() { return revision.getSymbolicName(); } @Override public Version getVersion() { return revision.getVersion(); } @Override public List<BundleCapability> getDeclaredCapabilities(String namespace) { return revision.getDeclaredCapabilities(namespace); } @Override public List<BundleRequirement> getDeclaredRequirements(String namespace) { return revision.getDeclaredRequirements(namespace); } @Override public int getTypes() { return revision.getTypes(); } @Override public BundleWiring getWiring() { return revision.getWiring(); } @Override public String toString() { return revision.toString(); } } public BundleResourceInstaller(Coordination coordination, Resource resource, BasicSubsystem subsystem) { super(coordination, resource, subsystem); } public Resource install() { BundleRevision revision; if (resource instanceof BundleRevision) { revision = (BundleRevision)resource; } else if (resource instanceof BundleRevisionResource) { revision = ((BundleRevisionResource)resource).getRevision(); } else { try { revision = installBundle(); } catch (Exception e) { throw new SubsystemException(e); } } addReference(revision); addConstituent(new BundleConstituent(resource, revision)); return revision; } private BundleRevision installBundle() throws Exception { final Bundle bundle; Method getContent = resource.getClass().getMethod("getContent"); getContent.setAccessible(true); InputStream is = (InputStream)getContent.invoke(resource); ThreadLocalSubsystem.set(provisionTo); try { bundle = provisionTo.getRegion().installBundleAtLocation(getLocation(), is); } finally { ThreadLocalSubsystem.remove(); // Although Region.installBundle ultimately calls BundleContext.install, // which closes the input stream, an exception may occur before this // happens. Also, the Region API does not guarantee the stream will // be closed. IOUtils.close(is); } // Set the start level of all bundles managed (i.e. installed) by the // subsystems implementation to 1 in case the framework's default bundle // start level has been changed. Otherwise, start failures will occur // if a subsystem is started at a lower start level than the default. // Setting the start level does no harm since all managed bundles are // started transiently anyway. bundle.adapt(BundleStartLevel.class).setStartLevel(1); return bundle.adapt(BundleRevision.class); } }