All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.osgi.container.ModuleRevisionBuilder Maven / Gradle / Ivy

There is a newer version: 1.9.22.1
Show newest version
/*******************************************************************************
 * Copyright (c) 2012, 2021 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.osgi.container;

import java.security.AllPermission;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import org.eclipse.osgi.internal.container.NamespaceList;
import org.eclipse.osgi.internal.container.NamespaceList.Builder;
import org.eclipse.osgi.internal.framework.FilterImpl;
import org.osgi.framework.AdminPermission;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.Version;
import org.osgi.framework.namespace.HostNamespace;
import org.osgi.framework.wiring.BundleRevision;
import org.osgi.resource.Namespace;

/**
 * A builder for creating module {@link ModuleRevision} objects.  A builder can only be used by
 * the module {@link ModuleContainer container} to build revisions when
 * {@link ModuleContainer#install(Module, String, ModuleRevisionBuilder, Object)
 * installing} or {@link ModuleContainer#update(Module, ModuleRevisionBuilder, Object) updating} a module.
 * 

* The builder provides the instructions to the container for creating a {@link ModuleRevision}. * They are not thread-safe; in the absence of external synchronization, they do not support concurrent access by multiple threads. * @since 3.10 */ public final class ModuleRevisionBuilder { private final static Class SINGLETON_MAP_CLASS = Collections.singletonMap(null, null).getClass(); private final static Class UNMODIFIABLE_MAP_CLASS = Collections.unmodifiableMap(Collections.emptyMap()).getClass(); /** * Provides information about a capability or requirement */ public static class GenericInfo { final static Function GETNAMESPACE = new Function() { public String apply(GenericInfo info) { return info.getNamespace(); } }; final String namespace; final Map directives; final Map attributes; final boolean mutable; GenericInfo(String namespace, Map directives, Map attributes, boolean mutable) { this.namespace = namespace; this.directives = directives; this.attributes = attributes; this.mutable = mutable; } /** * Returns the namespace of this generic info * @return the namespace */ public String getNamespace() { return namespace; } /** * Returns the directives of this generic info * @return the directives */ public Map getDirectives() { return directives; } /** * Returns the attributes of this generic info * @return the attributes */ public Map getAttributes() { return attributes; } } private String symbolicName = null; private Version version = Version.emptyVersion; private int types = 0; private final NamespaceList.Builder capabilityInfos = Builder.create(GenericInfo.GETNAMESPACE); private final NamespaceList.Builder requirementInfos = Builder.create(GenericInfo.GETNAMESPACE); private long id = -1; /** * Constructs a new module builder */ public ModuleRevisionBuilder() { // nothing } /** * Sets the symbolic name for the builder * @param symbolicName the symbolic name */ public void setSymbolicName(String symbolicName) { this.symbolicName = symbolicName; } /** * Sets the module version for the builder. * @param version the version */ public void setVersion(Version version) { this.version = version; } /** * Sets the module types for the builder. * @param types the module types */ public void setTypes(int types) { this.types = types; } /** * Sets the module ID for the builder. *

* This module ID will be used if this builder is used to * {@link ModuleContainer#install(Module, String, ModuleRevisionBuilder, Object) install} * a module. If the ID is not set then a module ID will be generated by the module * container at install time. If a module already exists with the specified ID * then an error will occur when attempting to install a new module with this * builder. *

* Note that the system module with location {@link Constants#SYSTEM_BUNDLE_LOCATION} * always gets module ID of zero. The builder for the system module is not * asked to provide the module ID for the system module at install time. * @param id the module ID to use. Must be >= 1. * @since 3.13 */ public void setId(long id) { if (id < 1) { throw new IllegalArgumentException("ID must be >=1."); //$NON-NLS-1$ } this.id = id; } void setInternalId(long id) { this.id = id; } /** * Adds a capability to this builder using the specified namespace, directives and attributes * @param namespace the namespace of the capability * @param directives the directives of the capability * @param attributes the attributes of the capability */ public void addCapability(String namespace, Map directives, Map attributes) { addGenericInfo(capabilityInfos, namespace, directives, attributes); } /** * Returns a snapshot of the capabilities for this builder * @return the capabilities */ public List getCapabilities() { return getCapabilities(null); } /** * Returns a snapshot of the capabilities in the given namespace for this * builder * * @param namespace The namespace of the capabilities to return or null to * return the capabilities from all namespaces. * @return the capabilities * @since 3.17 */ public List getCapabilities(String namespace) { return capabilityInfos.getNamespaceElements(namespace); } /** * Adds a requirement to this builder using the specified namespace, directives and attributes * @param namespace the namespace of the requirement * @param directives the directives of the requirement * @param attributes the attributes of the requirement */ public void addRequirement(String namespace, Map directives, Map attributes) { addGenericInfo(requirementInfos, namespace, directives, attributes); } /** * Returns a snapshot of the requirements for this builder * @return the requirements */ public List getRequirements() { return getRequirements(null); } NamespaceList.Builder getRequirementsBuilder() { return requirementInfos; } /** * Returns a snapshot of the requirements in the given namespace for this * builder * * @param namespace The namespace of the requirements to return or null to * return the requirements from all namespaces. * @return the requirements * @since 3.17 */ public List getRequirements(String namespace) { return requirementInfos.getNamespaceElements(namespace); } /** * Returns the symbolic name for this builder. * @return the symbolic name for this builder. */ public String getSymbolicName() { return symbolicName; } /** * Returns the module version for this builder. * @return the module version for this builder. */ public Version getVersion() { return version; } /** * Returns the module type for this builder. * @return the module type for this builder. */ public int getTypes() { return types; } /** * Returns the module id for this builder. A value of -1 * indicates that the module ID will be generated by the * module container at {@link ModuleContainer#install(Module, String, ModuleRevisionBuilder, Object) install} * time. * @return the module id for this builder. * @since 3.13 */ public long getId() { return id; } /** * Used by the container to build a new revision for a module. * This builder is used to build a new {@link Module#getCurrentRevision() current} * revision for the specified module. * @param module the module to build a new revision for * @param revisionInfo the revision info for the new revision, may be {@code null} * @return the new new {@link Module#getCurrentRevision() current} revision. */ ModuleRevision addRevision(Module module, Object revisionInfo) { ModuleRevisions revisions = module.getRevisions(); ModuleRevision revision = new ModuleRevision(symbolicName, version, types, capabilityInfos, requirementInfos, revisions, revisionInfo); revisions.addRevision(revision); module.getContainer().getAdaptor().associateRevision(revision, revisionInfo); try { checkFrameworkExtensionPermission(module, revision); module.getContainer().checkAdminPermission(module.getBundle(), AdminPermission.LIFECYCLE); } catch (SecurityException e) { revisions.removeRevision(revision); throw e; } return revision; } private void checkFrameworkExtensionPermission(Module module, ModuleRevision revision) { if (System.getSecurityManager() == null) { return; } if ((revision.getTypes() & BundleRevision.TYPE_FRAGMENT) != 0) { Collection systemNames = Collections.emptyList(); Module systemModule = module.getContainer().getModule(0); if (systemModule != null) { ModuleRevision systemRevision = systemModule.getCurrentRevision(); List hostCapabilities = systemRevision.getModuleCapabilities(HostNamespace.HOST_NAMESPACE); for (ModuleCapability hostCapability : hostCapabilities) { Object hostNames = hostCapability.getAttributes().get(HostNamespace.HOST_NAMESPACE); if (hostNames instanceof Collection) { systemNames = (Collection) hostNames; } else if (hostNames instanceof String) { systemNames = Arrays.asList(hostNames); } } } List hostRequirements = revision.getModuleRequirements(HostNamespace.HOST_NAMESPACE); for (ModuleRequirement hostRequirement : hostRequirements) { FilterImpl f = null; String filterSpec = hostRequirement.getDirectives().get(Namespace.REQUIREMENT_FILTER_DIRECTIVE); if (filterSpec != null) { try { f = FilterImpl.newInstance(filterSpec); String hostName = f.getPrimaryKeyValue(HostNamespace.HOST_NAMESPACE); if (hostName != null) { if (systemNames.contains(hostName)) { Bundle b = module.getBundle(); if (b != null && !b.hasPermission(new AllPermission())) { SecurityException se = new SecurityException( "Must have AllPermission granted to install an extension bundle: " + b); //$NON-NLS-1$ // TODO this is such a hack: making the cause a bundle exception so we can throw the right one later BundleException be = new BundleException(se.getMessage(), BundleException.SECURITY_ERROR, se); se.initCause(be); throw se; } module.getContainer().checkAdminPermission(module.getBundle(), AdminPermission.EXTENSIONLIFECYCLE); } } } catch (InvalidSyntaxException e) { // ignore } } } } } private void addGenericInfo(NamespaceList.Builder infos, String namespace, Map directives, Map attributes) { infos.add(new GenericInfo(namespace, directives, attributes, true)); } void basicAddCapability(String namespace, Map directives, Map attributes) { basicAddGenericInfo(capabilityInfos, namespace, directives, attributes); } void basicAddRequirement(String namespace, Map directives, Map attributes) { basicAddGenericInfo(requirementInfos, namespace, directives, attributes); } private static void basicAddGenericInfo(NamespaceList.Builder infos, String namespace, Map directives, Map attributes) { infos.add(new GenericInfo(namespace, unmodifiableMap(directives), unmodifiableMap(attributes), false)); } @SuppressWarnings("unchecked") static Map unmodifiableMap(Map map) { int size = map.size(); if (size == 0) { return Collections.emptyMap(); } if (size == 1) { if (map.getClass() != SINGLETON_MAP_CLASS) { Map.Entry entry = map.entrySet().iterator().next(); map = Collections.singletonMap(entry.getKey(), entry.getValue()); } } else { if (map.getClass() != UNMODIFIABLE_MAP_CLASS) { map = Collections.unmodifiableMap(map); } } return (Map) map; } void clear() { capabilityInfos.clear(); requirementInfos.clear(); id = -1; symbolicName = null; version = Version.emptyVersion; types = 0; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy