| package aQute.bnd.obr; |
| |
| import java.io.*; |
| import java.util.*; |
| import java.util.Map.Entry; |
| import java.util.jar.*; |
| import java.util.regex.*; |
| |
| import org.osgi.framework.Constants; |
| import org.osgi.framework.Version; |
| import org.osgi.framework.namespace.*; |
| import org.osgi.namespace.service.*; |
| import org.osgi.resource.*; |
| import org.osgi.service.repository.*; |
| |
| import aQute.bnd.header.*; |
| import aQute.bnd.osgi.*; |
| import aQute.bnd.osgi.resource.*; |
| import aQute.bnd.version.*; |
| import aQute.libg.cryptography.*; |
| import aQute.libg.map.*; |
| import aQute.service.reporter.*; |
| |
| public class OBRFragment { |
| |
| // The mime-type of an OSGi bundle |
| static final String MIME_TYPE_OSGI_BUNDLE = "application/vnd.osgi.bundle"; |
| static Pattern EE_PATTERN = Pattern.compile("[^.]-([\\d]+(?:\\.[\\d]+(?:\\.[\\d]+(?:\\.)?)?)?)"); |
| |
| @SuppressWarnings("deprecation") |
| public static Reporter parse(Jar jar, ResourceBuilder resource) throws Exception { |
| Manifest m = jar.getManifest(); |
| if (m == null) |
| return null; |
| |
| Domain d = Domain.domain(m); |
| d.setTranslation(jar); |
| Entry<String,Attrs> bundleSymbolicName = d.getBundleSymbolicName(); |
| |
| if (bundleSymbolicName == null) |
| return null; |
| |
| boolean singleton = "true".equals(bundleSymbolicName.getValue().get(Constants.SINGLETON_DIRECTIVE + ":")); |
| boolean isFragment = d.get(Constants.FRAGMENT_HOST) != null; |
| Version version = d.getBundleVersion() == null ? Version.emptyVersion : new Version(d.getBundleVersion()); |
| |
| CapReqBuilder identity = new CapReqBuilder(IdentityNamespace.IDENTITY_NAMESPACE); |
| identity.addAttribute(IdentityNamespace.IDENTITY_NAMESPACE, bundleSymbolicName.getKey()); |
| identity.addAttribute(IdentityNamespace.CAPABILITY_COPYRIGHT_ATTRIBUTE, d.translate(Constants.BUNDLE_COPYRIGHT)); |
| identity.addAttribute(IdentityNamespace.CAPABILITY_DESCRIPTION_ATTRIBUTE, |
| d.translate(Constants.BUNDLE_DESCRIPTION)); |
| identity.addAttribute(IdentityNamespace.CAPABILITY_DOCUMENTATION_ATTRIBUTE, |
| d.translate(Constants.BUNDLE_DOCURL)); |
| identity.addAttribute(IdentityNamespace.CAPABILITY_LICENSE_ATTRIBUTE, d.translate("Bundle-License")); |
| if (singleton) |
| identity.addAttribute(IdentityNamespace.CAPABILITY_SINGLETON_DIRECTIVE, "true"); |
| identity.addAttribute(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, |
| isFragment ? IdentityNamespace.TYPE_FRAGMENT |
| : IdentityNamespace.TYPE_BUNDLE); |
| identity.addAttribute(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, new Version(d.getBundleVersion())); |
| |
| resource.addCapability(identity); |
| |
| |
| if ( isFragment ) { |
| |
| // |
| // Fragment-Host |
| // |
| |
| Entry<String,Attrs> fragmentHost = d.getFragmentHost(); |
| CapReqBuilder fragment = new CapReqBuilder(HostNamespace.HOST_NAMESPACE); |
| String v = fragmentHost.getValue().get("version"); |
| if ( v == null) |
| v = "0"; |
| Version fragmentVersion = new Version(v); |
| String filter = filter(PackageNamespace.PACKAGE_NAMESPACE, fragmentHost.getKey(), fragmentHost.getValue()); |
| fragment.addDirective(HostNamespace.REQUIREMENT_FILTER_DIRECTIVE, filter.toString()); |
| resource.addRequirement(fragment); |
| } else { |
| |
| // |
| // Bundle-SymbolicName |
| // |
| |
| CapReqBuilder bundle = new CapReqBuilder(BundleNamespace.BUNDLE_NAMESPACE); |
| CapReqBuilder host = new CapReqBuilder(HostNamespace.HOST_NAMESPACE); |
| |
| bundle.addAttribute("version", version); |
| host.addAttribute("version", version); |
| |
| for (Entry<String,String> e : bundleSymbolicName.getValue().entrySet()) { |
| String key = e.getKey(); |
| if (key.endsWith(":")) { |
| String directive = key.substring(0, key.length() - 1); |
| if (Constants.FRAGMENT_ATTACHMENT_DIRECTIVE.equalsIgnoreCase(directive)) { |
| if (Constants.FRAGMENT_ATTACHMENT_NEVER.equalsIgnoreCase(e.getValue())) |
| host = null; |
| |
| } else if (!Constants.SINGLETON_DIRECTIVE.equalsIgnoreCase(directive)) { |
| bundle.addDirective(directive, e.getValue()); |
| } |
| if ( host != null ) |
| host.addDirective(directive, e.getValue()); |
| bundle.addDirective(directive, e.getValue()); |
| } else { |
| if ( host != null ) |
| host.addAttribute(key, e.getValue()); |
| bundle.addAttribute(key, e.getValue()); |
| } |
| } |
| if ( host != null) |
| resource.addCapability(host); |
| resource.addCapability(bundle); |
| } |
| |
| // |
| // Export-Package |
| // |
| |
| Parameters exports = d.getExportPackage(); |
| for (Entry<String,Attrs> entry : exports.entrySet()) { |
| CapReqBuilder exported = new CapReqBuilder(PackageNamespace.PACKAGE_NAMESPACE); |
| |
| String pkgName = Processor.removeDuplicateMarker(entry.getKey()); |
| exported.addAttribute(PackageNamespace.PACKAGE_NAMESPACE, pkgName); |
| |
| String versionStr = entry.getValue().get(Constants.VERSION_ATTRIBUTE); |
| Version v = Version.parseVersion(entry.getValue().get("version")); |
| |
| exported.addAttribute(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE, version); |
| |
| for (Entry<String,String> attribEntry : entry.getValue().entrySet()) { |
| String key = attribEntry.getKey(); |
| if (key.endsWith(":")) { |
| String directive = key.substring(0, key.length()-1); |
| exported.addDirective(directive, attribEntry.getValue()); |
| } else { |
| if ( key.equals("specification-version") || key.equals("version")) |
| exported.addAttribute("version", Version.parseVersion(attribEntry.getValue())); |
| else |
| exported.addAttribute(key, attribEntry.getValue()); |
| } |
| } |
| |
| exported.addAttribute(PackageNamespace.CAPABILITY_BUNDLE_SYMBOLICNAME_ATTRIBUTE, bundleSymbolicName.getKey()); |
| exported.addAttribute(PackageNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE, version); |
| |
| resource.addCapability(exported); |
| } |
| |
| // |
| // Import-Package |
| // |
| |
| Parameters imports = d.getImportPackage(); |
| for (Entry<String,Attrs> entry : imports.entrySet()) { |
| CapReqBuilder imported = new CapReqBuilder(PackageNamespace.PACKAGE_NAMESPACE); |
| String name = Processor.removeDuplicateMarker(entry.getKey()); |
| String filter = filter(PackageNamespace.PACKAGE_NAMESPACE, Processor.removeDuplicateMarker(entry.getKey()), entry.getValue()); |
| imported.addDirective(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter); |
| resource.addRequirement(imported); |
| } |
| |
| // |
| // Require-Bundle |
| // |
| |
| Parameters requires = d.getRequireBundle(); |
| for (Entry<String,Attrs> entry : requires.entrySet()) { |
| CapReqBuilder req = new CapReqBuilder(BundleNamespace.BUNDLE_NAMESPACE); |
| String bsn = Processor.removeDuplicateMarker(entry.getKey()); |
| String filter = filter(BundleNamespace.BUNDLE_NAMESPACE, bsn, entry.getValue()); |
| req.addDirective(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter); |
| resource.addRequirement(req); |
| } |
| |
| // |
| // Bundle-RequiredExecutionEnvironment |
| // |
| |
| Parameters brees = d.getBundleRequiredExecutionEnvironment(); |
| Formatter formatter = new Formatter(); |
| formatter.format("(|"); |
| |
| for ( Entry<String,Attrs> bree : brees.entrySet() ) { |
| String name = Processor.removeDuplicateMarker(bree.getKey()); |
| Matcher matcher = EE_PATTERN.matcher(name); |
| if ( matcher.matches()) { |
| name = matcher.group(1); |
| Version v = Version.parseVersion(matcher.group(2)); |
| formatter.format("%s", filter(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE, name, MAP.$("version", v.toString()))); |
| } |
| } |
| formatter.format(")"); |
| |
| CapReqBuilder breeReq = new CapReqBuilder(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE); |
| breeReq.addDirective(Namespace.REQUIREMENT_FILTER_DIRECTIVE, formatter.toString()); |
| |
| // |
| // Export-Service (deprecated) |
| // |
| |
| for (Entry<String,Attrs> export : d.getParameters(Constants.EXPORT_SERVICE).entrySet()) { |
| CapReqBuilder exportedService = new CapReqBuilder(ServiceNamespace.SERVICE_NAMESPACE); |
| String service = Processor.removeDuplicateMarker(export.getKey()); |
| exportedService.addAttribute(ServiceNamespace.SERVICE_NAMESPACE, service); |
| exportedService.addAttribute(ServiceNamespace.CAPABILITY_OBJECTCLASS_ATTRIBUTE, export.getValue().get("objectclass")); |
| resource.addCapability(exportedService); |
| } |
| |
| // |
| // Import-Service (deprecated) |
| // |
| |
| for (Entry<String,Attrs> imported : d.getParameters(Constants.IMPORT_SERVICE).entrySet()) { |
| CapReqBuilder importedService = new CapReqBuilder(ServiceNamespace.SERVICE_NAMESPACE); |
| String service = Processor.removeDuplicateMarker(imported.getKey()); |
| importedService.addDirective(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter(ServiceNamespace.SERVICE_NAMESPACE, service, imported.getValue())); |
| resource.addRequirement(importedService); |
| } |
| |
| // |
| // Provide-Capability |
| // |
| |
| for ( Entry<String,Attrs> rc : d.getProvideCapability().entrySet()) { |
| resource.addCapability( toCapability(rc.getKey(), rc.getValue())); |
| } |
| |
| // |
| // Require-Capability |
| // |
| |
| for ( Entry<String,Attrs> rc : d.getRequireCapability().entrySet()) { |
| resource.addCapability( toRequirement(rc.getKey(), rc.getValue())); |
| } |
| |
| |
| return null; |
| } |
| |
| private static Capability toRequirement(String key, Attrs value) { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| private static Capability toCapability(String key, Attrs value) { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| public static Reporter parse(File file, ResourceBuilder resource, String base) throws Exception { |
| Jar jar = new Jar(file); |
| try { |
| Reporter reporter = parse(jar, resource); |
| if (!reporter.isOk()) |
| return reporter; |
| |
| CapReqBuilder content = new CapReqBuilder(ContentNamespace.CONTENT_NAMESPACE); |
| String sha = SHA1.digest(file).asHex(); |
| content.addAttribute(ContentNamespace.CONTENT_NAMESPACE, sha); |
| content.addAttribute(ContentNamespace.CAPABILITY_SIZE_ATTRIBUTE, (long) file.length()); |
| content.addAttribute(ContentNamespace.CAPABILITY_MIME_ATTRIBUTE, MIME_TYPE_OSGI_BUNDLE); |
| |
| if (base != null) { |
| String path = file.getAbsolutePath(); |
| if (base.startsWith(path)) { |
| content.addAttribute(ContentNamespace.CAPABILITY_URL_ATTRIBUTE, path.substring(base.length()) |
| .replace(File.separatorChar, '/')); |
| } else { |
| reporter.error("Base path %s is not parent of file path: %s", base, file.getAbsolutePath()); |
| } |
| } |
| |
| resource.addCapability(content); |
| return reporter; |
| } |
| finally { |
| jar.close(); |
| } |
| } |
| |
| // TODO finish |
| private static String filter(String ns, String primary, Map<String,String> value) { |
| Formatter f = new Formatter(); |
| f.format("(&(%s=%s)", ns, primary); |
| for ( String key : value.keySet()) { |
| if ( key.equals("version") || key.equals("bundle-version")) { |
| VersionRange vr = new VersionRange(value.get(key)); |
| } else { |
| f.format("(%s=%s)", key, value.get(key)); |
| } |
| } |
| |
| f.format(")"); |
| return null; |
| } |
| |
| } |