package aQute.bnd.osgi; import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; import java.util.Map.Entry; import java.util.Set; import java.util.TreeSet; import aQute.bnd.header.Attrs; import aQute.bnd.osgi.Descriptors.PackageRef; import aQute.bnd.osgi.resource.FilterParser; import aQute.bnd.osgi.resource.FilterParser.Expression; import aQute.bnd.osgi.resource.FilterParser.ExpressionVisitor; import aQute.bnd.osgi.resource.FilterParser.Op; import aQute.bnd.osgi.resource.FilterParser.Or; import aQute.bnd.osgi.resource.FilterParser.PatternExpression; import aQute.bnd.osgi.resource.FilterParser.SimpleExpression; public class PermissionGenerator { public static enum Parameter { ADMIN { @Override public void generate(StringBuilder sb, Builder builder) { sb.append("(org.osgi.framework.AdminPermission)\n"); } }, CAPABILITIES { @Override public void generate(StringBuilder sb, Builder builder) { for (String namespace : builder.getProvideCapability().keySet()) { if (!Processor.isDuplicate(namespace)) { sb.append("(org.osgi.framework.CapabilityPermission \"") .append(namespace) .append("\" \"provide\")\n"); } } for (String namespace : builder.getRequireCapability().keySet()) { if (!Processor.isDuplicate(namespace)) { sb.append("(org.osgi.framework.CapabilityPermission \"") .append(namespace) .append("\" \"require\")\n"); } } } }, PACKAGES { @Override public void generate(StringBuilder sb, Builder builder) { if (builder.getImports() != null) { for (PackageRef imp : builder.getImports().keySet()) { if (!imp.isJava()) { sb.append("(org.osgi.framework.PackagePermission \""); sb.append(imp); sb.append("\" \"import\")\n"); } } } if (builder.getExports() != null) { for (PackageRef exp : builder.getExports().keySet()) { sb.append("(org.osgi.framework.PackagePermission \""); sb.append(exp); sb.append("\" \"export\")\n"); } } } }, SERVICES { @Override public void generate(StringBuilder sb, Builder builder) { for (String declaredService : getDeclaredServices(builder)) { sb.append("(org.osgi.framework.ServicePermission \"") .append(declaredService) .append("\" \"register\")\n"); } for (String referencedService : getReferencedServices(builder)) { sb.append("(org.osgi.framework.ServicePermission \"") .append(referencedService) .append("\" \"get\")\n"); } } }; public abstract void generate(StringBuilder sb, Builder builder); } public static final String KEY = "permissions"; public static Set<String> getDeclaredServices(Builder builder) { Set<String> declaredServices = new TreeSet<>(); for (Entry<String,Attrs> entry : builder.getProvideCapability().entrySet()) { if (Processor.removeDuplicateMarker(entry.getKey()).equals("osgi.service")) { Attrs attrs = entry.getValue(); String ifaces = attrs.get("objectClass"); if (ifaces != null) { for (String iface : ifaces.split(",")) { declaredServices.add(iface.trim()); } } } } return declaredServices; } private static final String MATCH_ALL = "*"; private static final String VALID_WILDCARD = ".*"; static final class FindReferencedServices extends ExpressionVisitor<Set<String>> { public FindReferencedServices() { super(Collections.<String> emptySet()); } @Override public Set<String> visit(SimpleExpression expr) { if ("objectClass".equals(expr.getKey())) { if (expr.getOp() == Op.EQUAL) { String v = expr.getValue(); if (!v.contains(MATCH_ALL) || v.equals(MATCH_ALL)) { return Collections.singleton(v); } else if (v.endsWith(VALID_WILDCARD) && !v.substring(0, v.length() - 2).contains(MATCH_ALL)) { return Collections.singleton(v); } else { // All other matchings have no meaning to us, the user // should generate them by hand return Collections.emptySet(); } } else { // All other matchings have no meaning, so match nothing return Collections.emptySet(); } } return Collections.emptySet(); } @Override public Set<String> visit(PatternExpression expr) { // Simply use the default visit method for simple expressions, since // the patterns are also supported in the permissions return visit((SimpleExpression) expr); } @Override public Set<String> visit(Or expr) { Set<String> matches = new HashSet<>(); for (Expression expression : expr.getExpressions()) { matches.addAll(expression.visit(this)); } return matches; } @Override public Set<String> visitTrue() { return Collections.singleton(MATCH_ALL); } } public static Set<String> getReferencedServices(Builder builder) { Set<String> referencedServices = new TreeSet<>(); for (Entry<String,Attrs> entry : builder.getRequireCapability().entrySet()) { if (Processor.removeDuplicateMarker(entry.getKey()).equals("osgi.service")) { Attrs attrs = entry.getValue(); String filter = attrs.get("filter:"); if (filter != null && !filter.isEmpty()) { FilterParser filterParser = new FilterParser(); Expression expr = filterParser.parse(filter); referencedServices.addAll(expr.visit(new FindReferencedServices())); } } } if (referencedServices.contains(MATCH_ALL)) { return Collections.singleton(MATCH_ALL); } else { return referencedServices; } } private static EnumSet<Parameter> parseParams(Builder builder, final String... args) { EnumSet<Parameter> parameters = EnumSet.noneOf(Parameter.class); // Skip the key name, so start at index 1 for (int ix = 1; ix < args.length; ix++) { String name = args[ix].toUpperCase(); try { parameters.add(Parameter.valueOf(name)); } catch (IllegalArgumentException ex) { builder.error("Could not parse argument for ${permissions}: %s", args[ix]); } } return parameters; } private final Builder builder; private final Set<Parameter> parameters; public PermissionGenerator(Builder builder, final String... args) { assert args.length > 0 && KEY.equals(args[0]); this.builder = builder; this.parameters = parseParams(builder, args); } public String generate() { StringBuilder sb = new StringBuilder(); for (Parameter param : parameters) { param.generate(sb, builder); } return sb.toString(); } }