package org.bndtools.core.ui.resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bndtools.core.ui.icons.Icons;
import org.bndtools.utils.jface.BoldStyler;
import org.bndtools.utils.jface.ItalicStyler;
import org.bndtools.utils.resources.ResourceUtils;
import org.eclipse.jface.viewers.StyledString;
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.osgi.resource.FilterParser;
import aQute.bnd.osgi.resource.FilterParser.Expression;
import aQute.bnd.osgi.resource.FilterParser.Op;
import aQute.bnd.osgi.resource.FilterParser.RangeExpression;
import aQute.bnd.osgi.resource.FilterParser.SimpleExpression;
import aQute.bnd.osgi.resource.FilterParser.WithRangeExpression;
public class R5LabelFormatter {
static FilterParser filterParser = new FilterParser();
static Pattern EE_PATTERN = Pattern.compile("osgi.ee=([^\\)]*).*version=([^\\)]*)");
static final Map<String,Pattern> FILTER_PATTERNS;
static {
FILTER_PATTERNS = new HashMap<>();
FILTER_PATTERNS.put(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE, EE_PATTERN);
FILTER_PATTERNS.put(PackageNamespace.PACKAGE_NAMESPACE, Pattern.compile("osgi\\.wiring\\.package=([^\\)]*)"));
}
public static String getVersionAttributeName(String ns) {
String r;
if (ns == null)
r = null;
else if (ns.equals(IdentityNamespace.IDENTITY_NAMESPACE))
r = IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE;
else if (ns.equals(ContentNamespace.CONTENT_NAMESPACE))
r = null;
else if (ns.equals(BundleNamespace.BUNDLE_NAMESPACE))
r = BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE;
else if (ns.equals(HostNamespace.HOST_NAMESPACE))
r = HostNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE;
else if (ns.equals(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE))
r = ExecutionEnvironmentNamespace.CAPABILITY_VERSION_ATTRIBUTE;
else if (ns.equals(PackageNamespace.PACKAGE_NAMESPACE))
r = PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE;
else if (ns.equals(ExtenderNamespace.EXTENDER_NAMESPACE))
r = ExtenderNamespace.CAPABILITY_VERSION_ATTRIBUTE;
else if (ns.equals(ContractNamespace.CONTRACT_NAMESPACE))
r = ContractNamespace.CAPABILITY_VERSION_ATTRIBUTE;
else if (ns.equals(ServiceNamespace.SERVICE_NAMESPACE))
r = null;
else
r = null;
return r;
}
public static Pattern getFilterPattern(String ns) {
return FILTER_PATTERNS.get(ns);
}
/*
* Most namespaces have a "main" attribute that is the same as the namespace. For example, namespace
* osgi.wiring.package has an attribute "osgi.wiring.package" that specifies the package name.
*
* The main exception to this rule is the osgi.service namespace, which uses "objectClass".
*/
public static String getMainAttributeName(String ns) {
if (ServiceNamespace.SERVICE_NAMESPACE.equals(ns))
return ServiceNamespace.CAPABILITY_OBJECTCLASS_ATTRIBUTE;
return ns;
}
public static String getNamespaceImagePath(String ns) {
String r = "icons/bullet_green.png"; // generic green dot
if (BundleNamespace.BUNDLE_NAMESPACE.equals(ns) || HostNamespace.HOST_NAMESPACE.equals(ns))
r = Icons.path("bundle");
else if (ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE.equals(ns))
r = "icons/java.png";
else if (PackageNamespace.PACKAGE_NAMESPACE.equals(ns))
r = Icons.path("package");
else if (ServiceNamespace.SERVICE_NAMESPACE.equals(ns))
r = Icons.path("service");
else if (ExtenderNamespace.EXTENDER_NAMESPACE.equals(ns))
r = "icons/wand.png";
else if (ContractNamespace.CONTRACT_NAMESPACE.equals(ns))
r = "icons/contract.png";
else if ("osgi.whiteboard".equals(ns))
r = "icons/whiteboard.png";
else if (ns.startsWith("osgi.enroute"))
r = "enroute/enroute-color-16x16.png";
else if ("osgi.missing".equalsIgnoreCase(ns) || "donotresolve".equalsIgnoreCase(ns) || "compile-only".equalsIgnoreCase(ns))
r = "icons/prohibition.png";
return r;
}
public static void appendNamespaceWithValue(StyledString label, String ns, String value, boolean shorten) {
String prefix = ns;
if (shorten) {
if (IdentityNamespace.IDENTITY_NAMESPACE.equals(ns))
prefix = "id";
else if (BundleNamespace.BUNDLE_NAMESPACE.equals(ns))
prefix = "";
else if (HostNamespace.HOST_NAMESPACE.equals(ns))
prefix = "host";
else if (ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE.equals(ns))
prefix = "";
else if (PackageNamespace.PACKAGE_NAMESPACE.equals(ns))
prefix = "";
else if (ServiceNamespace.SERVICE_NAMESPACE.equals(ns))
prefix = "";
else if (ContractNamespace.CONTRACT_NAMESPACE.equals(ns))
prefix = "";
else if ("osgi.whiteboard".equals(ns))
prefix = "";
}
if (prefix.length() > 0)
label.append(prefix + "=", StyledString.QUALIFIER_STYLER);
label.append(value, BoldStyler.INSTANCE_DEFAULT);
}
public static void appendCapability(StyledString label, Capability cap, boolean shorten) {
String ns = cap.getNamespace();
Object nsValue = cap.getAttributes().get(getMainAttributeName(ns));
String versionAttributeName = getVersionAttributeName(ns);
if (nsValue != null) {
appendNamespaceWithValue(label, ns, nsValue.toString(), shorten);
if (versionAttributeName != null) {
Object version = cap.getAttributes().get(versionAttributeName);
if (version != null) {
label.append(", " + versionAttributeName, StyledString.QUALIFIER_STYLER);
label.append(" " + version.toString(), BoldStyler.INSTANCE_COUNTER);
}
}
} else {
label.append(ns, BoldStyler.INSTANCE_DEFAULT);
}
label.append(" ", StyledString.QUALIFIER_STYLER);
if (!cap.getAttributes().isEmpty()) {
boolean first = true;
for (Entry<String,Object> entry : cap.getAttributes().entrySet()) {
String key = entry.getKey();
if (!key.equals(ns) && !key.equals(versionAttributeName)) {
if (first)
label.append("[", StyledString.QUALIFIER_STYLER);
else
label.append(", ", StyledString.QUALIFIER_STYLER);
first = false;
label.append(key + "=", StyledString.QUALIFIER_STYLER);
label.append(entry.getValue() != null ? entry.getValue().toString() : "<null>", StyledString.QUALIFIER_STYLER);
}
}
if (!first)
label.append("]", StyledString.QUALIFIER_STYLER);
}
if (!cap.getDirectives().isEmpty()) {
label.append(" ");
boolean first = true;
for (Entry<String,String> directive : cap.getDirectives().entrySet()) {
label.append(directive.getKey() + ":=" + directive.getValue(), StyledString.QUALIFIER_STYLER);
if (!first)
label.append(", ", StyledString.QUALIFIER_STYLER);
}
}
}
public static void appendResourceLabel(StyledString label, Resource resource) {
Capability identity = ResourceUtils.getIdentityCapability(resource);
String name = ResourceUtils.getIdentity(identity);
if (name == null) {
if (resource != null) {
name = resource.toString();
} else {
name = "<unknown>";
}
}
label.append(name, BoldStyler.INSTANCE_DEFAULT);
Version version = ResourceUtils.getVersion(identity);
if (version != null)
label.append(" " + version, StyledString.COUNTER_STYLER);
}
public static void appendRequirementLabel(StyledString label, Requirement requirement, boolean shorten) {
String namespace = requirement.getNamespace();
String filter = requirement.getDirectives().get(Namespace.REQUIREMENT_FILTER_DIRECTIVE);
boolean optional = Namespace.RESOLUTION_OPTIONAL.equals(requirement.getDirectives().get(Namespace.REQUIREMENT_RESOLUTION_DIRECTIVE));
FilterParser fp = new FilterParser();
if (filter == null) {
if (namespace.contains("$")) {
Pattern pattern = Pattern.compile("\\{(.*?)\\}");
Matcher matcher = pattern.matcher(namespace);
label.append(namespace);
while (matcher.find()) {
int begin = matcher.start(1);
int end = matcher.end(1);
label.setStyle(begin, end - begin, BoldStyler.INSTANCE_DEFAULT);
}
} else {
label.append(namespace + ": <no filter>", ItalicStyler.INSTANCE_ERROR);
}
} else {
try {
Expression exp = fp.parse(filter);
if (exp instanceof WithRangeExpression) {
appendNamespaceWithValue(label, namespace, ((WithRangeExpression) exp).printExcludingRange(), shorten);
RangeExpression range = ((WithRangeExpression) exp).getRangeExpression();
if (range != null)
label.append(" ").append(formatRangeString(range), StyledString.COUNTER_STYLER);
} else if (ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE.equals(namespace)) {
Matcher matcher = EE_PATTERN.matcher(filter);
if (matcher.find()) {
String eename = matcher.group(1);
String version = matcher.group(2);
appendNamespaceWithValue(label, namespace, eename, true);
label.append(" ").append(version, StyledString.COUNTER_STYLER);
} else {
appendNamespaceWithValue(label, namespace, filter, true);
}
} else {
appendNamespaceWithValue(label, namespace, filter, true);
}
} catch (Exception e) {
label.append(namespace + ": ", StyledString.QUALIFIER_STYLER);
label.append("<parse error>", ItalicStyler.INSTANCE_ERROR);
}
}
boolean first = true;
for (Entry<String,String> directive : requirement.getDirectives().entrySet()) {
if (Namespace.REQUIREMENT_RESOLUTION_DIRECTIVE.equals(directive.getKey()) || Namespace.REQUIREMENT_FILTER_DIRECTIVE.equals(directive.getKey()))
continue; // deal with the filter: and resolution: directives separately
StringBuilder buf = new StringBuilder();
buf.append(first ? " " : ", ");
buf.append(directive.getKey()).append(":=").append(directive.getValue());
label.append(buf.toString(), StyledString.QUALIFIER_STYLER);
first = false;
}
if (optional) {
label.setStyle(0, label.length(), StyledString.QUALIFIER_STYLER);
label.append(" <optional>", ItalicStyler.INSTANCE_DEFAULT);
}
}
public static String formatRangeString(RangeExpression range) {
StringBuilder sb = new StringBuilder();
SimpleExpression low = range.getLow();
if (low == null) {
sb.append("[0");
} else {
if (low.getOp() == Op.GREATER)
sb.append("(");
else
sb.append("[");
sb.append(low.getValue());
}
sb.append(", ");
SimpleExpression high = range.getHigh();
if (high == null) {
sb.append("\u221e]"); // INFINITY Unicode: U+221E, UTF-8: E2 88 9E
} else {
sb.append(high.getValue());
if (high.getOp() == Op.LESS)
sb.append(")");
else
sb.append("]");
}
return sb.toString();
}
}