/** * Creates a new {@link ClassLoader} that only exposes classes in packages declared by "Export-Package" * in the manifest. */ public ClassLoader getExportPackagesClassLoader() { return new PackageFilterClassLoader(this, Predicates.in(exportPackages)); } }
@Override protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { try { return bootstrapClassLoader.loadClass(name); } catch (ClassNotFoundException e) { if (!predicate.apply(getClassPackage(name))) { throw new ClassNotFoundException("Loading of class " + name + " not allowed"); } return super.loadClass(name, resolve); } }
@Override public URL getResource(String name) { URL resource = bootstrapClassLoader.getResource(name); if (resource != null) { return resource; } if (name.endsWith(".class") && !predicate.apply(getResourcePackage(name))) { return null; } return super.getResource(name); }
/** * Creates a new {@link ClassLoader} that only exposes classes in packages declared by "Export-Package" * in the manifest. */ public ClassLoader getExportPackagesClassLoader() { return new PackageFilterClassLoader(this, Predicates.in(exportPackages)); } }
@Override public URL getResource(String name) { URL resource = bootstrapClassLoader.getResource(name); if (resource != null) { return resource; } if (name.endsWith(".class") && !predicate.apply(getResourcePackage(name))) { return null; } return super.getResource(name); }
@Override protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { try { return bootstrapClassLoader.loadClass(name); } catch (ClassNotFoundException e) { if (!predicate.apply(getClassPackage(name))) { throw new ClassNotFoundException("Loading of class " + name + " not allowed"); } return super.loadClass(name, resolve); } }
static ClassLoader createParent(ClassLoader templateClassLoader) { // Find the ProgramClassLoader from the template ClassLoader ClassLoader programClassLoader = templateClassLoader; while (programClassLoader != null && !(programClassLoader instanceof ProgramClassLoader)) { programClassLoader = programClassLoader.getParent(); } // This shouldn't happen Preconditions.checkArgument(programClassLoader != null, "Cannot find ProgramClassLoader"); // Package filtered classloader of the template classloader, which only classes in "Export-Packages" are loadable. Manifest manifest = ((ProgramClassLoader) programClassLoader).getManifest(); Set<String> exportPackages = ManifestFields.getExportPackages(manifest); ClassLoader filteredTemplateClassLoader = new PackageFilterClassLoader(templateClassLoader, Predicates.in(exportPackages)); // The lib Classloader needs to be able to see all cdap api classes as well. // In this way, parent ClassLoader of the plugin ClassLoader will load class from the parent of the // template program class loader (which is a filtered CDAP classloader), // followed by template export-packages, then by a plugin lib jars. return new CombineClassLoader(programClassLoader.getParent(), filteredTemplateClassLoader); }
@Override public Enumeration<URL> getResources(String name) throws IOException { Enumeration<URL> resources = bootstrapClassLoader.getResources(name); if (resources.hasMoreElements()) { return resources; } if (name.endsWith(".class") && !predicate.apply(getResourcePackage(name))) { return Iterators.asEnumeration(Iterators.<URL>emptyIterator()); } return super.getResources(name); }
static ClassLoader createParent(ClassLoader templateClassLoader) { // Find the ProgramClassLoader from the template ClassLoader ClassLoader programClassLoader = templateClassLoader; while (programClassLoader != null && !(programClassLoader instanceof ProgramClassLoader)) { programClassLoader = programClassLoader.getParent(); } // This shouldn't happen Preconditions.checkArgument(programClassLoader != null, "Cannot find ProgramClassLoader"); // Package filtered classloader of the template classloader, which only classes in "Export-Packages" are loadable. Manifest manifest = ((ProgramClassLoader) programClassLoader).getManifest(); Set<String> exportPackages = ManifestFields.getExportPackages(manifest); ClassLoader filteredTemplateClassLoader = new PackageFilterClassLoader(templateClassLoader, Predicates.in(exportPackages)); // The lib Classloader needs to be able to see all cdap api classes as well. // In this way, parent ClassLoader of the plugin ClassLoader will load class from the parent of the // template program class loader (which is a filtered CDAP classloader), // followed by template export-packages, then by a plugin lib jars. return new CombineClassLoader(programClassLoader.getParent(), filteredTemplateClassLoader); }
@Override public Enumeration<URL> getResources(String name) throws IOException { Enumeration<URL> resources = bootstrapClassLoader.getResources(name); if (resources.hasMoreElements()) { return resources; } if (name.endsWith(".class") && !predicate.apply(getResourcePackage(name))) { return Iterators.asEnumeration(Iterators.<URL>emptyIterator()); } return super.getResources(name); }
@Test public void testCombineClassLoader() throws ClassNotFoundException { // Creates a CombineClassLoader with two delegates. // One allows "co.cask.cdap.api.app", the other allows "co.cask.cdap.api.annotation" ClassLoader parent = getClass().getClassLoader(); ClassLoader classLoader = new CombineClassLoader(null, new PackageFilterClassLoader(parent, Predicates.equalTo(Application.class.getPackage().getName())), new PackageFilterClassLoader(parent, Predicates.equalTo(Beta.class.getPackage().getName())) ); // Should be able to load classes from those two packages Assert.assertSame(ApplicationConfigurer.class, classLoader.loadClass(ApplicationConfigurer.class.getName())); Assert.assertSame(Property.class, classLoader.loadClass(Property.class.getName())); // For classes not in those packages would failed. try { classLoader.loadClass(Bytes.class.getName()); Assert.fail(); } catch (ClassNotFoundException e) { // Expected } }
@Test public void testPackageFilter() throws ClassNotFoundException { ClassLoader classLoader = new PackageFilterClassLoader(getClass().getClassLoader(), new Predicate<String>() { @Override public boolean apply(String input) { return input.startsWith("co.cask.cdap.api."); } }); // Load allowed class. It should gives the same class. Class<?> cls = classLoader.loadClass(Application.class.getName()); Assert.assertSame(Application.class, cls); // Try to load forbidden class. It should fail. try { classLoader.loadClass(SchemaGenerator.class.getName()); Assert.fail(); } catch (ClassNotFoundException e) { // Expected } // Load resource. Should succeed. Assert.assertNotNull(classLoader.getResource("logback-test.xml")); // Load class resource that is in the allowed package. Should succeed. String resourceName = Application.class.getName().replace('.', '/') + ".class"; URL url = classLoader.getResource(resourceName); Assert.assertNotNull(url); Assert.assertEquals(getClass().getClassLoader().getResource(resourceName), url); // Load class resource that is in allowed package. Should return null. resourceName = SchemaGenerator.class.getName().replace('.', '/') + ".class"; Assert.assertNull(classLoader.getResource(resourceName)); }