/* * 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 org.apache.aries.subsystem.ContentHandler; import org.apache.aries.subsystem.core.archive.ProvisionResourceHeader; import org.osgi.framework.ServiceReference; import org.osgi.framework.namespace.IdentityNamespace; import org.osgi.framework.wiring.BundleRevision; import org.osgi.resource.Resource; import org.osgi.service.subsystem.SubsystemConstants; import org.osgi.service.subsystem.SubsystemException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class ResourceUninstaller { private static final Logger logger = LoggerFactory.getLogger(ResourceUninstaller.class); public static ResourceUninstaller newInstance(Resource resource, BasicSubsystem subsystem) { String type = ResourceHelper.getTypeAttribute(resource); if (SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION.equals(type) || SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE.equals(type) || SubsystemConstants.SUBSYSTEM_TYPE_FEATURE.equals(type)) { return new SubsystemResourceUninstaller(resource, subsystem); } else if (IdentityNamespace.TYPE_BUNDLE.equals(type) || IdentityNamespace.TYPE_FRAGMENT.equals(type)) { return new BundleResourceUninstaller(resource, subsystem); } else { ServiceReference<ContentHandler> handlerRef = CustomResources.getCustomContentHandler(subsystem, type); if (handlerRef != null) { return new CustomResourceUninstaller(resource, type, subsystem, handlerRef); } else { throw new SubsystemException("No uninstaller exists for resource type: " + type); } } } protected static void removeConstituent(BasicSubsystem subsystem, Resource resource) { Activator.getInstance().getSubsystems().removeConstituent(subsystem, resource); } protected static void removeReference(BasicSubsystem subsystem, Resource resource) { Activator.getInstance().getSubsystems().removeReference(subsystem, resource); } protected final BasicSubsystem provisionTo; protected final Resource resource; protected final BasicSubsystem subsystem; public ResourceUninstaller(Resource resource, BasicSubsystem subsystem) { if (resource == null) throw new NullPointerException("Missing required parameter: resource"); if (subsystem == null) throw new NullPointerException("Missing required parameter: subsystem"); this.resource = resource; this.subsystem = subsystem; if (isTransitive()) provisionTo = Utils.findFirstSubsystemAcceptingDependenciesStartingFrom(subsystem); else provisionTo = subsystem; } public abstract void uninstall(); protected boolean isExplicit() { // The operation is explicit if it was requested by a user, in which // case the resource and subsystem are the same. if (resource.equals(subsystem)) return true; // The operation is explicit if it was requested by a scoped subsystem // on a resource within the same region. if (subsystem.isScoped()) { if (Utils.isBundle(resource)) return subsystem.getRegion().contains(((BundleRevision)resource).getBundle()); // TODO This is insufficient. The unscoped subsystem could be a // dependency in another region, which would make it implicit. return !((BasicSubsystem)resource).isScoped(); } return false; } protected boolean isTransitive() { ProvisionResourceHeader header = subsystem.getDeploymentManifest().getProvisionResourceHeader(); if (header == null) return false; return header.contains(resource); } protected boolean isResourceUninstallable() { int referenceCount = Activator.getInstance().getSubsystems().getSubsystemsReferencing(resource).size(); if (referenceCount == 0) return true; if (isExplicit()) { logger.error("Explicitly uninstalling resource still has dependencies: {}", resource); return true; } return false; } protected void removeConstituent() { removeConstituent(subsystem, resource); } protected void removeReference() { removeReference(subsystem, resource); } }