package test.component; import java.io.BufferedReader; import java.io.File; import java.io.FileWriter; import java.io.InputStreamReader; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import aQute.bnd.osgi.Builder; import aQute.bnd.osgi.Constants; import aQute.bnd.osgi.Jar; import aQute.bnd.osgi.PermissionGenerator; import aQute.bnd.osgi.Resource; import aQute.bnd.test.BndTestCase; public class PermissionGeneratorTest extends BndTestCase { private static Set<String> getPermissionsGeneratedFor(String permissionFile) throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.*_basic"); b.setProperty("Private-Package", "test.component"); b.setProperty("Export-Package", "test.api"); File tmpFile = File.createTempFile("bndtest", "permissions.perm"); FileWriter fileWriter = new FileWriter(tmpFile); fileWriter.write(permissionFile); fileWriter.close(); b.setProperty("-includeresource", "{OSGI-INF/permissions.perm=" + tmpFile.getAbsolutePath() + "}"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Resource resource = jar.getResource("OSGI-INF/permissions.perm"); BufferedReader r = new BufferedReader(new InputStreamReader(resource.openInputStream())); Set<String> permissions = new TreeSet<String>(); String line = null; while ((line = r.readLine()) != null) { if (!line.isEmpty()) { assertTrue("Found duplicate permission: " + line, permissions.add(line)); System.err.println("Permission read: " + line); } } tmpFile.delete(); return permissions; } private static Set<String> filterAndSubtract(Set<String> input, String regex) { Set<String> result = new TreeSet<>(); Pattern pattern = Pattern.compile(regex); for (Iterator<String> it = input.iterator(); it.hasNext();) { String string = it.next(); Matcher matcher = pattern.matcher(string); if (matcher.matches()) { it.remove(); result.add(matcher.group(1)); } } return result; } private static void assertNotingLeft(Set<String> permissions) { assertEquals("No other permissions expected", Collections.emptySet(), permissions); } private static void assertPackageAvailable(Set<String> permissions) { Set<String> importedPackages = filterAndSubtract(permissions, "^\\(org.osgi.framework.PackagePermission \"([^\"]+)\" \"import\"\\)$"); Set<String> exportedPackages = filterAndSubtract(permissions, "^\\(org.osgi.framework.PackagePermission \"([^\"]+)\" \"export\"\\)$"); /* @formatter:off */ assertEquals("Imported packages", new TreeSet<>(Arrays.asList("aQute.bnd.annotation.metatype", "aQute.bnd.differ", "aQute.bnd.header", "aQute.bnd.osgi", "aQute.bnd.service.diff", "aQute.bnd.test", "aQute.lib.io", "aQute.service.reporter", "javax.xml.namespace", "javax.xml.parsers", "javax.xml.xpath", "junit.framework", "org.osgi.framework", "org.osgi.service.component", "org.osgi.service.event", "org.osgi.service.log", "org.w3c.dom", "org.xml.sax")), importedPackages); assertEquals("Exported packages", new TreeSet<>(Arrays.asList("test.api")), exportedPackages); /* @formatter:on */ } private static void assertServicesAvailable(Set<String> permissions) { Set<String> registeredServices = filterAndSubtract(permissions, "^\\(org.osgi.framework.ServicePermission \"([^\"]+)\" \"register\"\\)$"); Set<String> requiredServices = filterAndSubtract(permissions, "^\\(org.osgi.framework.ServicePermission \"([^\"]+)\" \"get\"\\)$"); /* @formatter:off */ assertEquals("Registered services", new TreeSet<>(Arrays.asList("java.lang.Runnable", "java.io.Serializable", "java.lang.Object")), registeredServices); assertEquals("Required services", new TreeSet<>(Arrays.asList("org.osgi.service.log.LogService")), requiredServices); /* @formatter:on */ } private static void assertCapabilitiesAvailable(Set<String> permissions) { Set<String> requiredCapabilities = filterAndSubtract(permissions, "^\\(org.osgi.framework.CapabilityPermission \"([^\"]+)\" \"require\"\\)$"); Set<String> providedCapabilities = filterAndSubtract(permissions, "^\\(org.osgi.framework.CapabilityPermission \"([^\"]+)\" \"provide\"\\)$"); /* @formatter:off */ assertEquals("Provided capabilities", new TreeSet<>(Arrays.asList("osgi.service")), providedCapabilities); assertEquals("Required capabilities", new TreeSet<>(Arrays.asList("osgi.extender", "osgi.service")), requiredCapabilities); /* @formatter:on */ } private static void assertAdminAvailable(Set<String> permissions) { Set<String> adminCapabilities = filterAndSubtract(permissions, "^\\((org.osgi.framework.AdminPermission)\\)$"); assertEquals("Admin capabilities", 1, adminCapabilities.size()); } public static void testJustPackages() throws Exception { Set<String> permissions = getPermissionsGeneratedFor("${permissions;packages}"); assertPackageAvailable(permissions); assertNotingLeft(permissions); } public static void testJustServices() throws Exception { Set<String> permissions = getPermissionsGeneratedFor("${permissions;services}"); assertServicesAvailable(permissions); assertNotingLeft(permissions); } public static void testJustCapabilities() throws Exception { Set<String> permissions = getPermissionsGeneratedFor("${permissions;capabilities}"); assertCapabilitiesAvailable(permissions); assertNotingLeft(permissions); } public static void testJustAdmin() throws Exception { Set<String> permissions = getPermissionsGeneratedFor("${permissions;admin}"); assertAdminAvailable(permissions); assertNotingLeft(permissions); } public static void testConcatenatedPermissionsNoAdmin() throws Exception { Set<String> permissions = getPermissionsGeneratedFor( "${permissions;packages}${permissions;services}${permissions;capabilities}"); assertPackageAvailable(permissions); assertServicesAvailable(permissions); assertCapabilitiesAvailable(permissions); assertNotingLeft(permissions); } public static void testInlinePermissionsNoAdmin() throws Exception { Set<String> permissions = getPermissionsGeneratedFor("${permissions;packages;services;capabilities}"); assertPackageAvailable(permissions); assertServicesAvailable(permissions); assertCapabilitiesAvailable(permissions); assertNotingLeft(permissions); } public static void testInlinePermissions() throws Exception { Set<String> permissions = getPermissionsGeneratedFor("${permissions;packages;services;capabilities;admin}"); assertPackageAvailable(permissions); assertServicesAvailable(permissions); assertCapabilitiesAvailable(permissions); assertAdminAvailable(permissions); assertNotingLeft(permissions); } public static void testCustomCapabilityParsing() throws Exception { Builder b = new Builder(); b.setProperty("Require-Capability", "osgi.service;filter:=\"(objectClass=*)\""); Set<String> services = PermissionGenerator.getReferencedServices(b); assertEquals(Collections.singleton("*"), services); b.setProperty("Require-Capability", "osgi.service;filter:=\"(!(objectClass=*))\""); services = PermissionGenerator.getReferencedServices(b); assertEquals(Collections.emptySet(), services); b.setProperty("Require-Capability", "osgi.service;filter:=\"(!(objectClass=test.Helper))\""); services = PermissionGenerator.getReferencedServices(b); assertEquals(Collections.emptySet(), services); b.setProperty("Require-Capability", "osgi.service;filter:=\"(objectClass=test.*)\""); services = PermissionGenerator.getReferencedServices(b); assertEquals(Collections.singleton("test.*"), services); b.setProperty("Require-Capability", "osgi.service;filter:=\"(|(objectClass=test.*)(objectClass=test2.*))\""); services = PermissionGenerator.getReferencedServices(b); assertEquals(new HashSet<String>(Arrays.asList("test.*", "test2.*")), services); b.setProperty("Require-Capability", "osgi.service;filter:=\"(|(objectClass=test.*)(!(objectClass=test2.*)))\""); services = PermissionGenerator.getReferencedServices(b); assertEquals(Collections.singleton("test.*"), services); // In the following cases, there is no way to determine the permissions // needed, so nothing is generated. In these cases it is up to the user // to generate the permission b.setProperty("Require-Capability", "osgi.service;filter:=\"(objectClass=test2.*Helper)\""); services = PermissionGenerator.getReferencedServices(b); assertEquals(Collections.emptySet(), services); b.setProperty("Require-Capability", "osgi.service;filter:=\"(objectClass=test*.*)\""); services = PermissionGenerator.getReferencedServices(b); assertEquals(Collections.emptySet(), services); b.setProperty("Require-Capability", "osgi.service;filter:=\"(other=prop)\""); services = PermissionGenerator.getReferencedServices(b); assertEquals(Collections.emptySet(), services); b.setProperty("Require-Capability", "osgi.service;filter:=\"(&(objectClass=test.*)(objectClass=*Helper))\""); services = PermissionGenerator.getReferencedServices(b); assertEquals(Collections.emptySet(), services); b.setProperty("Require-Capability", "osgi.service;filter:=\"(!(&(objectClass=test.*)(objectClass=*Helper)))\""); services = PermissionGenerator.getReferencedServices(b); assertEquals(Collections.emptySet(), services); } }