blob: 1af351889a7a6a23a3f9a519509092a062c2739e [file] [log] [blame]
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;
}
}