/* * #%L * JBossOSGi Resolver API * %% * Copyright (C) 2010 - 2012 JBoss by Red Hat * %% * 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. * #L% */ package org.jboss.osgi.resolver.spi; import static org.jboss.osgi.metadata.OSGiMetaData.ANONYMOUS_BUNDLE_SYMBOLIC_NAME; import static org.jboss.osgi.resolver.ResolverMessages.MESSAGES; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.jboss.modules.Module; import org.jboss.modules.ModuleIdentifier; import org.jboss.osgi.metadata.OSGiMetaData; import org.jboss.osgi.metadata.OSGiMetaDataBuilder; import org.jboss.osgi.metadata.PackageAttribute; import org.jboss.osgi.metadata.Parameter; import org.jboss.osgi.metadata.ParameterizedAttribute; import org.jboss.osgi.resolver.MavenCoordinates; import org.jboss.osgi.resolver.ResourceBuilderException; import org.jboss.osgi.resolver.XCapability; import org.jboss.osgi.resolver.XIdentityCapability; import org.jboss.osgi.resolver.XRequirement; import org.jboss.osgi.resolver.XResource; import org.jboss.osgi.resolver.XResourceBuilder; import org.jboss.osgi.resolver.XResourceBuilderFactory; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.Version; import org.osgi.framework.namespace.AbstractWiringNamespace; import org.osgi.framework.namespace.BundleNamespace; import org.osgi.framework.namespace.ExecutionEnvironmentNamespace; import org.osgi.framework.namespace.HostNamespace; import org.osgi.framework.namespace.IdentityNamespace; import org.osgi.framework.namespace.PackageNamespace; /** * A builder for resolver resources * * @author thomas.diesler@jboss.com * @since 02-Jul-2010 */ public class AbstractResourceBuilder<T extends XResource> implements XResourceBuilder<T> { private final XResourceBuilderFactory<T> factory; private final T resource; public AbstractResourceBuilder(XResourceBuilderFactory<T> factory) { if (factory == null) throw MESSAGES.illegalArgumentNull("factory"); this.factory = factory; this.resource = factory.createResource(); } @Override public XResourceBuilder<T> addAttribute(String key, String value) { assertResourceCreated(); resource.getAttributes().put(key, value); return this; } @Override public XIdentityCapability addIdentityCapability(String symbolicName, Version version) { assertResourceCreated(); XIdentityCapability icap = (XIdentityCapability) addCapability(IdentityNamespace.IDENTITY_NAMESPACE, symbolicName); icap.getAttributes().put(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, version); return icap; } @Override public XIdentityCapability addIdentityCapability(ModuleIdentifier moduleId) { assertResourceCreated(); String nsvalue = moduleId.getName(); Version version; try { version = Version.parseVersion(moduleId.getSlot()); } catch (IllegalArgumentException ex) { version = Version.emptyVersion; } XIdentityCapability icap = (XIdentityCapability) addCapability(XResource.MODULE_IDENTITY_NAMESPACE, nsvalue); icap.getAttributes().put("type", XResource.TYPE_MODULE); icap.getAttributes().put("name", moduleId.getName()); icap.getAttributes().put("slot", moduleId.getSlot()); icap.getAttributes().put("version", version); return icap; } @Override public XIdentityCapability addIdentityCapability(MavenCoordinates mavenId) { assertResourceCreated(); String nsvalue = mavenId.getArtifactId(); Version version; try { version = Version.parseVersion(mavenId.getVersion()); } catch (IllegalArgumentException ex) { version = Version.emptyVersion; } XIdentityCapability icap = (XIdentityCapability) addCapability(XResource.MAVEN_IDENTITY_NAMESPACE, nsvalue); icap.getAttributes().put("type", mavenId.getType()); icap.getAttributes().put("groupId", mavenId.getGroupId()); icap.getAttributes().put("artifactId", mavenId.getArtifactId()); icap.getAttributes().put("version", version); if (mavenId.getClassifier() != null) icap.getAttributes().put("classifier", mavenId.getClassifier()); return icap; } @Override public XCapability addCapability(String namespace, Map<String, Object> atts, Map<String, String> dirs) { assertResourceCreated(); XCapability cap = factory.createCapability(resource, namespace, mutableAttributes(atts), mutableDirectives(dirs)); addCapability(cap); return cap; } @Override public XCapability addCapability(String namespace, String nsvalue) { return addCapability(namespace, Collections.singletonMap(namespace, (Object)nsvalue), null); } @Override public XRequirement addRequirement(String namespace, Map<String, Object> atts, Map<String, String> dirs) { assertResourceCreated(); XRequirement req = factory.createRequirement(resource, namespace, mutableAttributes(atts), mutableDirectives(dirs)); addRequirement(req); return req; } @Override public XRequirement addRequirement(String namespace, Filter filter) { assertResourceCreated(); Map<String, String> dirs = new LinkedHashMap<String, String>(); if (filter != null) dirs.put(AbstractWiringNamespace.REQUIREMENT_FILTER_DIRECTIVE, filter.toString()); return addRequirement(namespace, null, dirs); } @Override public XRequirement addRequirement(String namespace, String nsvalue) { assertResourceCreated(); Map<String, Object> atts = new LinkedHashMap<String, Object>(); if (nsvalue != null) atts.put(namespace, nsvalue); return addRequirement(namespace, atts, null); } @Override @SuppressWarnings("deprecation") public XResourceBuilder<T> loadFrom(OSGiMetaData metadata) throws ResourceBuilderException { assertResourceCreated(); try { String symbolicName = metadata.getBundleSymbolicName(); Version bundleVersion = metadata.getBundleVersion(); ParameterizedAttribute fragmentHost = metadata.getFragmentHost(); ParameterizedAttribute idparams = metadata.getBundleParameters(); Map<String, Object> idatts = getAttributes(idparams); Map<String, String> isdirs = getDirectives(idparams); if (symbolicName == null) symbolicName = ANONYMOUS_BUNDLE_SYMBOLIC_NAME; // Identity Capability XCapability icap = addIdentityCapability(symbolicName, bundleVersion); String identityType = fragmentHost != null ? IdentityNamespace.TYPE_FRAGMENT : IdentityNamespace.TYPE_BUNDLE; icap.getAttributes().put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, identityType); icap.getAttributes().putAll(idatts); icap.getDirectives().putAll(isdirs); // Bundle Capability if (IdentityNamespace.TYPE_BUNDLE.equals(identityType)) { XCapability cap = addCapability(BundleNamespace.BUNDLE_NAMESPACE, symbolicName); cap.getAttributes().put(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE, bundleVersion); cap.getAttributes().putAll(idatts); cap.getDirectives().putAll(isdirs); } // Host Capability String fragmentAttachemnt = isdirs.get(HostNamespace.CAPABILITY_FRAGMENT_ATTACHMENT_DIRECTIVE); if (fragmentHost == null && !HostNamespace.FRAGMENT_ATTACHMENT_NEVER.equals(fragmentAttachemnt)) { XCapability cap = addCapability(HostNamespace.HOST_NAMESPACE, symbolicName); cap.getAttributes().put(HostNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE, bundleVersion); cap.getAttributes().putAll(idatts); cap.getDirectives().putAll(isdirs); } // Host Requirement if (fragmentHost != null) { String hostName = fragmentHost.getAttribute(); XRequirement req = addRequirement(HostNamespace.HOST_NAMESPACE, hostName); req.getAttributes().putAll(getAttributes(fragmentHost)); req.getDirectives().putAll(getDirectives(fragmentHost)); } // Required Bundles List<ParameterizedAttribute> requireBundles = metadata.getRequireBundles(); if (requireBundles != null && !requireBundles.isEmpty()) { for (ParameterizedAttribute attr : requireBundles) { String bundleName = attr.getAttribute(); XRequirement req = addRequirement(BundleNamespace.BUNDLE_NAMESPACE, bundleName); req.getAttributes().putAll(getAttributes(attr)); req.getDirectives().putAll(getDirectives(attr)); } } // Required Execution Environment List<String> requiredEnvironments = metadata.getRequiredExecutionEnvironment(); if (requiredEnvironments != null && !requiredEnvironments.isEmpty()) { // Frameworks must convert a Bundle-RequiredExecutionEnvironment header to a requirement in the osgi.ee namespace Filter filter = OSGiMetaDataBuilder.convertExecutionEnvironmentHeader(requiredEnvironments); addRequirement(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE, filter); } // Export-Package List<PackageAttribute> exports = metadata.getExportPackages(); if (exports != null && !exports.isEmpty()) { for (PackageAttribute attr : exports) { String packageName = attr.getAttribute(); XCapability cap = addCapability(PackageNamespace.PACKAGE_NAMESPACE, packageName); cap.getAttributes().putAll(getAttributes(attr)); cap.getDirectives().putAll(getDirectives(attr)); // Add infered package capability attributes Map<String, Object> capatts = cap.getAttributes(); if (!capatts.containsKey(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE)) capatts.put(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, symbolicName); if (!capatts.containsKey(Constants.BUNDLE_VERSION_ATTRIBUTE)) capatts.put(Constants.BUNDLE_VERSION_ATTRIBUTE, bundleVersion); if (!capatts.containsKey(Constants.PACKAGE_SPECIFICATION_VERSION)) { Object vspec = capatts.get(Constants.VERSION_ATTRIBUTE); if (vspec != null) { try { Version version = Version.parseVersion(vspec.toString()); capatts.put(Constants.PACKAGE_SPECIFICATION_VERSION, version); } catch (RuntimeException ex) { // ignore } } } } } // Import-Package List<PackageAttribute> imports = metadata.getImportPackages(); if (imports != null && !imports.isEmpty()) { for (PackageAttribute attr : imports) { String packageName = attr.getAttribute(); XRequirement req = addRequirement(PackageNamespace.PACKAGE_NAMESPACE, packageName); req.getAttributes().putAll(getAttributes(attr)); req.getDirectives().putAll(getDirectives(attr)); } } // DynamicImport-Package List<PackageAttribute> dynamicImports = metadata.getDynamicImports(); if (dynamicImports != null && !dynamicImports.isEmpty()) { for (PackageAttribute attr : dynamicImports) { String packageName = attr.getAttribute(); Map<String, Object> atts = new LinkedHashMap<String, Object>(); Map<String, String> dirs = new LinkedHashMap<String, String>(); atts.put(PackageNamespace.PACKAGE_NAMESPACE, packageName); dirs.put(PackageNamespace.REQUIREMENT_RESOLUTION_DIRECTIVE, PackageNamespace.RESOLUTION_DYNAMIC); XRequirement req = addRequirement(PackageNamespace.PACKAGE_NAMESPACE, atts, dirs); req.getAttributes().putAll(getAttributes(attr)); req.getDirectives().putAll(getDirectives(attr)); } } // Provide-Capability List<ParameterizedAttribute> providedCapabilities = metadata.getProvidedCapabilities(); if (providedCapabilities != null && !providedCapabilities.isEmpty()) { for (ParameterizedAttribute attr : providedCapabilities) { String capname = attr.getAttribute(); XCapability cap = addCapability(capname, null, null); cap.getAttributes().putAll(getAttributes(attr)); cap.getDirectives().putAll(getDirectives(attr)); } } // Require-Capability List<ParameterizedAttribute> requiredCapabilities = metadata.getRequiredCapabilities(); if (requiredCapabilities != null && !requiredCapabilities.isEmpty()) { for (ParameterizedAttribute attr : requiredCapabilities) { String reqname = attr.getAttribute(); XRequirement req = addRequirement(reqname, null, null); req.getAttributes().putAll(getAttributes(attr)); req.getDirectives().putAll(getDirectives(attr)); } } resource.validate(); } catch (ResourceValidationException ex) { throw MESSAGES.resourceBuilderCannotInitializeResource(ex, ex.getOffendingInput()); } catch (RuntimeException ex) { throw MESSAGES.resourceBuilderCannotInitializeResource(ex, metadata.toString()); } return this; } @Override public XResourceBuilder<T> loadFrom(Module module) throws ResourceBuilderException { assertResourceCreated(); try { ModuleIdentifier moduleId = module.getIdentifier(); String symbolicName = moduleId.getName(); Version version; try { version = Version.parseVersion(moduleId.getSlot()); } catch (IllegalArgumentException ex) { version = Version.emptyVersion; } // Add identity capability XCapability icap = addCapability(IdentityNamespace.IDENTITY_NAMESPACE, symbolicName); icap.getAttributes().put(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, version); icap.getAttributes().put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, XResource.TYPE_MODULE); // Add bundle capability XCapability bcap = addCapability(BundleNamespace.BUNDLE_NAMESPACE, symbolicName); bcap.getAttributes().put(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, version); // Add a package capability for every exported path new OSGiMetaDataProcessor.ModuleExportPackagesCollector(module) { @Override protected void addPackage(String packageName) { addCapability(PackageNamespace.PACKAGE_NAMESPACE, packageName); } }.collectExportPackages(); resource.validate(); } catch (RuntimeException ex) { throw MESSAGES.resourceBuilderCannotInitializeResource(ex, resource.toString()); } return this; } @Override public T getResource() { resource.validate(); resource.setMutable(false); return resource; } private void addCapability(XCapability cap) { if (resource instanceof AbstractResource) { ((AbstractResource) resource).addCapability(cap); } } private void addRequirement(XRequirement req) { if (resource instanceof AbstractResource) { ((AbstractResource) resource).addRequirement(req); } } private Map<String, Object> getAttributes(ParameterizedAttribute patts) { Map<String, Object> atts = new LinkedHashMap<String, Object>(); if (patts != null) { for (String key : patts.getAttributes().keySet()) { Parameter param = patts.getAttribute(key); atts.put(key, param.getValue()); } } return atts; } private Map<String, String> getDirectives(ParameterizedAttribute patts) { Map<String, String> dirs = new LinkedHashMap<String, String>(); if (patts != null) { for (String key : patts.getDirectives().keySet()) { String value = patts.getDirectiveValue(key, String.class); dirs.put(key, value); } } return dirs; } private Map<String, Object> mutableAttributes(Map<String, Object> atts) { return new LinkedHashMap<String, Object>(atts != null ? atts : new LinkedHashMap<String, Object>()); } private Map<String, String> mutableDirectives(Map<String, String> dirs) { return new LinkedHashMap<String, String>(dirs != null ? dirs : new LinkedHashMap<String, String>()); } private void assertResourceCreated() { if (resource == null) throw MESSAGES.illegalStateResourceNotCreated(); } }