aQute.bnd.osgi.resource.CapReqBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of biz.aQute.bndlib Show documentation
Show all versions of biz.aQute.bndlib Show documentation
bndlib: A Swiss Army Knife for OSGi
package aQute.bnd.osgi.resource;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import org.osgi.framework.Constants;
import org.osgi.framework.Version;
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;
import org.osgi.namespace.contract.ContractNamespace;
import org.osgi.namespace.extender.ExtenderNamespace;
import org.osgi.namespace.service.ServiceNamespace;
import org.osgi.resource.Capability;
import org.osgi.resource.Namespace;
import org.osgi.resource.Requirement;
import org.osgi.resource.Resource;
import org.osgi.service.repository.ContentNamespace;
import aQute.bnd.header.Attrs;
import aQute.bnd.header.Parameters;
import aQute.bnd.osgi.Processor;
import aQute.bnd.version.VersionRange;
import aQute.lib.converter.Converter;
import aQute.libg.filters.AndFilter;
import aQute.libg.filters.Filter;
import aQute.libg.filters.LiteralFilter;
import aQute.libg.filters.SimpleFilter;
public class CapReqBuilder {
private final String namespace;
private Resource resource;
private final Map attributes = new HashMap();
private final Map directives = new HashMap();
public CapReqBuilder(String namespace) {
this.namespace = namespace;
}
public CapReqBuilder(String ns, Attrs attrs) throws Exception {
this.namespace = ns;
for (Entry entry : attrs.entrySet()) {
String key = entry.getKey();
if (key.endsWith(":"))
addDirective(key.substring(0, key.length() - 1), entry.getValue());
else
addAttribute(key, entry.getValue());
}
}
public CapReqBuilder(Resource resource, String namespace) {
this(namespace);
setResource(resource);
}
public static CapReqBuilder clone(Capability capability) throws Exception {
CapabilityBuilder builder = new CapabilityBuilder(capability.getNamespace());
builder.addAttributes(capability.getAttributes());
builder.addDirectives(capability.getDirectives());
return builder;
}
public static CapReqBuilder clone(Requirement requirement) throws Exception {
RequirementBuilder builder = new RequirementBuilder(requirement.getNamespace());
builder.addAttributes(requirement.getAttributes());
builder.addDirectives(requirement.getDirectives());
return builder;
}
public String getNamespace() {
return namespace;
}
public Resource getResource() {
return resource;
}
public CapReqBuilder setResource(Resource resource) {
this.resource = resource;
return this;
}
public CapReqBuilder addAttribute(String name, Object value) throws Exception {
if (value == null)
return this;
if (value.getClass().isArray()) {
value = Converter.cnv(List.class, value);
}
if ("version".equals(name)) {
value = toVersions(value);
}
attributes.put(name, value);
return this;
}
public boolean isVersion(Object value) {
if (value instanceof Version)
return true;
if (value instanceof Collection) {
if (((Collection< ? >) value).isEmpty())
return true;
return isVersion(((Collection< ? >) value).iterator().next());
}
if (value.getClass().isArray()) {
if (Array.getLength(value) == 0)
return true;
return isVersion(((Object[]) value)[0]);
}
return false;
}
public CapReqBuilder addAttributes(Map< ? extends String, ? extends Object> attributes) throws Exception {
for (Entry< ? extends String, ? extends Object> e : attributes.entrySet()) {
addAttribute(e.getKey(), e.getValue());
}
return this;
}
public CapReqBuilder addDirective(String name, String value) {
if (value == null)
return this;
directives.put(ResourceUtils.stripDirective(name), value);
return this;
}
public CapReqBuilder addDirectives(Attrs directives) {
for (Entry e : directives.entrySet()) {
String key = Attrs.toDirective(e.getKey());
if (key != null)
addDirective(key, e.getValue());
}
return this;
}
public CapReqBuilder addDirectives(Map directives) {
for (Entry e : directives.entrySet()) {
addDirective(e.getKey(), e.getValue());
}
return this;
}
public Capability buildCapability() {
if (resource == null)
throw new IllegalStateException("Cannot build Capability with null Resource.");
return new CapabilityImpl(namespace, resource, directives, attributes);
}
public Capability buildSyntheticCapability() {
return new CapabilityImpl(namespace, resource, directives, attributes);
}
public Requirement buildRequirement() {
if (resource == null)
throw new IllegalStateException(
"Cannot build Requirement with null Resource. use buildSyntheticRequirement");
return new RequirementImpl(namespace, resource, directives, attributes);
}
public Requirement buildSyntheticRequirement() {
return new RequirementImpl(namespace, null, directives, attributes);
}
public static final CapReqBuilder createPackageRequirement(String pkgName, String range) {
Filter filter;
SimpleFilter pkgNameFilter = new SimpleFilter(PackageNamespace.PACKAGE_NAMESPACE, pkgName);
if (range != null)
filter = new AndFilter().addChild(pkgNameFilter)
.addChild(new LiteralFilter(Filters.fromVersionRange(range)));
else
filter = pkgNameFilter;
return new CapReqBuilder(PackageNamespace.PACKAGE_NAMESPACE)
.addDirective(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter.toString());
}
public static CapReqBuilder createBundleRequirement(String bsn, String range) {
Filter filter;
SimpleFilter bsnFilter = new SimpleFilter(IdentityNamespace.IDENTITY_NAMESPACE, bsn);
if (range != null)
filter = new AndFilter().addChild(bsnFilter).addChild(new LiteralFilter(Filters.fromVersionRange(range)));
else
filter = bsnFilter;
return new CapReqBuilder(IdentityNamespace.IDENTITY_NAMESPACE)
.addDirective(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter.toString());
}
public static CapReqBuilder createSimpleRequirement(String ns, String name, String range) {
Filter filter;
SimpleFilter bsnFilter = new SimpleFilter(ns, name);
if (range != null)
filter = new AndFilter().addChild(bsnFilter).addChild(new LiteralFilter(Filters.fromVersionRange(range)));
else
filter = bsnFilter;
return new CapReqBuilder(ns).addDirective(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter.toString());
}
public CharSequence and(Object... exprs) {
StringBuilder sb = new StringBuilder();
sb.append("(&");
for (Object expr : exprs) {
sb.append("(").append(toFilter(expr)).append(")");
}
sb.append(")");
return sb;
}
public CharSequence or(Object... exprs) {
StringBuilder sb = new StringBuilder();
sb.append("(|");
for (Object expr : exprs) {
sb.append("(").append(toFilter(expr)).append(")");
}
sb.append(")");
return sb;
}
public CharSequence not(Object expr) {
StringBuilder sb = new StringBuilder();
sb.append("(!(").append(toFilter(expr)).append(")");
return sb;
}
private CharSequence toFilter(Object expr) {
if (expr instanceof CharSequence)
return (CharSequence) expr;
if (expr instanceof Filter) {
return expr.toString();
}
if (expr instanceof VersionRange) {
return ((VersionRange) expr).toFilter();
}
return expr.toString();
}
public CapReqBuilder filter(CharSequence f) {
return addDirective("filter", f.toString());
}
public static List getRequirementsFrom(Parameters rr) throws Exception {
List requirements = new ArrayList();
for (Entry e : rr.entrySet()) {
requirements.add(getRequirementFrom(Processor.removeDuplicateMarker(e.getKey()), e.getValue()));
}
return requirements;
}
public static Requirement getRequirementFrom(String namespace, Attrs attrs) throws Exception {
CapReqBuilder builder = createCapReqBuilder(namespace, attrs);
return builder.buildSyntheticRequirement();
}
public static CapReqBuilder createCapReqBuilder(String namespace, Attrs attrs) throws Exception {
CapReqBuilder builder = new CapReqBuilder(namespace);
for (Entry entry : attrs.entrySet()) {
String key = entry.getKey();
if (key.endsWith(":")) {
key = key.substring(0, key.length() - 1);
builder.addDirective(key, entry.getValue());
} else {
builder.addAttribute(key, entry.getValue());
}
}
return builder;
}
public static List getCapabilitiesFrom(Parameters rr) throws Exception {
List capabilities = new ArrayList<>();
for (Entry e : rr.entrySet()) {
capabilities.add(getCapabilityFrom(Processor.removeDuplicateMarker(e.getKey()), e.getValue()));
}
return capabilities;
}
public static Capability getCapabilityFrom(String namespace, Attrs attrs) throws Exception {
CapReqBuilder builder = createCapReqBuilder(namespace, attrs);
return builder.buildSyntheticCapability();
}
public CapReqBuilder from(Capability c) throws Exception {
addAttributes(c.getAttributes());
addDirectives(c.getDirectives());
return this;
}
public CapReqBuilder from(Requirement r) throws Exception {
addAttributes(r.getAttributes());
addDirectives(r.getDirectives());
return this;
}
public static Capability copy(Capability c, Resource r) throws Exception {
CapReqBuilder from = new CapReqBuilder(c.getNamespace()).from(c);
if (r == null)
return from.buildSyntheticCapability();
else
return from.setResource(r).buildCapability();
}
public static Requirement copy(Requirement c, Resource r) throws Exception {
CapReqBuilder from = new CapReqBuilder(c.getNamespace()).from(c);
if (r == null)
return from.buildSyntheticRequirement();
else
return from.setResource(r).buildRequirement();
}
/**
* In bnd, we only use one map for both directives & attributes. This method
* will properly dispatch them AND take care of typing
*
* @param attrs
* @throws Exception
*/
public void addAttributesOrDirectives(Attrs attrs) throws Exception {
for (Entry e : attrs.entrySet()) {
String directive = Attrs.toDirective(e.getKey());
if (directive != null) {
addDirective(directive, e.getValue());
} else {
Object typed = attrs.getTyped(e.getKey());
if (typed instanceof aQute.bnd.version.Version) {
typed = new Version(typed.toString());
}
addAttribute(e.getKey(), typed);
}
}
}
public void addFilter(String ns, String name, String version, Attrs attrs) {
List parts = new ArrayList();
parts.add("(" + ns + "=" + name + ")");
if (version != null && VersionRange.isOSGiVersionRange(version)) {
VersionRange range = VersionRange.parseOSGiVersionRange(version);
parts.add(range.toFilter());
}
String mandatory = attrs.get(Constants.MANDATORY_DIRECTIVE + ":");
if (mandatory != null) {
String mandatoryAttrs[] = mandatory.split("\\s*,\\s*");
Arrays.sort(mandatoryAttrs);
for (String mandatoryAttr : mandatoryAttrs) {
String value = attrs.get(mandatoryAttr);
if (value != null) {
parts.add("(" + mandatoryAttr + "=" + escapeFilterValue(value) + ")");
}
}
}
StringBuilder sb = new StringBuilder();
if (parts.size() > 0)
sb.append("(&");
for (String s : parts) {
sb.append(s);
}
if (parts.size() > 0)
sb.append(")");
addDirective(Namespace.REQUIREMENT_FILTER_DIRECTIVE, sb.toString());
}
/**
* If value must contain one of the characters reverse solidus ('\' \u005C),
* asterisk ('*' \u002A), parentheses open ('(' \u0028) or parentheses close
* (')' \u0029), then these characters should be preceded with the reverse
* solidus ('\' \u005C) character. Spaces are significant in value. Space
* characters are defined by Character.isWhiteSpace().
*
*/
static Pattern ESCAPE_FILTER_VALUE_P = Pattern.compile("[\\\\()*]");
public static String escapeFilterValue(String value) {
return ESCAPE_FILTER_VALUE_P.matcher(value).replaceAll("\\\\$0");
}
public void and(String... s) {
String previous = directives == null ? null : directives.get(Namespace.REQUIREMENT_FILTER_DIRECTIVE);
StringBuilder filter = new StringBuilder();
if (previous != null) {
filter.append("(&").append(previous);
}
for (String subexpr : s)
filter.append(subexpr);
if (previous != null) {
filter.append(")");
}
addDirective(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter.toString());
}
public boolean isPackage() {
return PackageNamespace.PACKAGE_NAMESPACE.equals(getNamespace());
}
public boolean isHost() {
return HostNamespace.HOST_NAMESPACE.equals(getNamespace());
}
public boolean isBundle() {
return BundleNamespace.BUNDLE_NAMESPACE.equals(getNamespace());
}
public boolean isService() {
return ServiceNamespace.SERVICE_NAMESPACE.equals(getNamespace());
}
public boolean isContract() {
return ContractNamespace.CONTRACT_NAMESPACE.equals(getNamespace());
}
public boolean isIdentity() {
return IdentityNamespace.IDENTITY_NAMESPACE.equals(getNamespace());
}
public boolean isContent() {
return ContentNamespace.CONTENT_NAMESPACE.equals(getNamespace());
}
public boolean isEE() {
return ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE.equals(getNamespace());
}
public boolean isExtender() {
return ExtenderNamespace.EXTENDER_NAMESPACE.equals(getNamespace());
}
public Attrs toAttrs() {
Attrs attrs = new Attrs();
if (attributes != null) {
for (Entry e : attributes.entrySet()) {
Object value = e.getValue();
if (e.getKey().equals("version") || value instanceof Version)
value = toBndVersions(value);
attrs.putTyped(e.getKey(), value);
}
}
if (directives != null)
for (Entry e : directives.entrySet()) {
attrs.put(e.getKey() + ":", e.getValue());
}
return attrs;
}
private Object toBndVersions(Object value) {
if (value instanceof aQute.bnd.version.Version)
return value;
if (value instanceof Version)
return new aQute.bnd.version.Version(value.toString());
if (value instanceof String)
return new aQute.bnd.version.Version((String) value);
if (value instanceof Collection) {
List bnds = new ArrayList<>();
for (Object m : (Collection< ? >) value) {
bnds.add((aQute.bnd.version.Version) toBndVersions(m));
}
return bnds;
}
throw new IllegalArgumentException("cannot convert " + value + " to a bnd Version(s) object as requested");
}
private Object toVersions(Object value) {
if (value instanceof Version)
return value;
if (value instanceof aQute.bnd.version.Version)
return new Version(value.toString());
if (value instanceof String)
try {
return new Version((String) value);
} catch (Exception e) {
return value;
}
if (value instanceof Collection) {
Collection< ? > v = (Collection< ? >) value;
if (v.isEmpty())
return value;
if (v.iterator().next() instanceof Version)
return value;
List osgis = new ArrayList<>();
for (Object m : (Collection< ? >) value) {
osgis.add((Version) toVersions(m));
}
return osgis;
}
throw new IllegalArgumentException(
"cannot convert " + value + " to a org.osgi.framework Version(s) object as requested");
}
public static RequirementBuilder createRequirementFromCapability(Capability cap) {
RequirementBuilder req = new RequirementBuilder(cap.getNamespace());
StringBuilder sb = new StringBuilder("(&");
for (Entry e : cap.getAttributes().entrySet()) {
Object v = e.getValue();
if (v instanceof Version || e.getKey().equals("version")) {
VersionRange r = new VersionRange(v.toString());
String filter = r.toFilter();
sb.append(filter);
} else
sb.append("(").append(e.getKey()).append("=").append(v).append(")");
}
sb.append(")");
req.and(sb.toString());
return req;
}
}