Apache Felix set Classloader to restrict class access on Android - java

I'm running Apache Felix as a bundle loader inside an Android app.
Since the Jaca SecurityManager isn't accessible there, I'm looking for a solution to prevent the bundles from accessing certain packages, like java.io.*.
The idea of just writing a custom classloader that will return null or throw an exception when such a class is requested seems the best, however, I can't find how to set a global classloader for all bundles managed by Felix.

Try setting this property:
org.osgi.framework.system.packages - Specifies a comma-delimited list
of packages that should be exported via the System Bundle from the
framework class loader. The framework will set this to a reasonable
default. If the value is specified, it replaces any default value.
By default, all java.* classes are visible to any bundle. If you override this, you can change that behaviour. Bundles trying to import the packages you did not include (such as java.io) will not be resolved during installation and hence will not be able to start.
See this for more information: http://felix.apache.org/site/apache-felix-framework-configuration-properties.html

Related

How to create a working OSGi bundle with optional package resolution?

I would like my bundle to be either configurable via System properties or via the OSGi Compendium Config Admin.
I am compiling my bundle against the org.osgi:osgi.cmpn:6.0.0 bundle, which as made clear in the OSGi Alliance blog is meant to be used at compile-time only, with the framework providing the actual implementations at runtime.
My code obviously needs to use the ConfigAdmin package (to handle the case in which the ConfigAdmin Service is present)... which means that if the runtime does not export the ConfigAdmin package, my bundle will not resolve properly.
But I wanted this resolution to be optional... so I added this to the manifest:
org.osgi.service.cm;resolution:=optional;version="[1.5,2)"
Now, the bundle will resolve but will crash at runtime with a java.lang.NoClassDefFoundError: org/osgi/service/cm/ManagedService even if the user will not actually use ConfigAdmin for configuration. So this forces the user to install the config-admin bundle just to make my bundle work.
I guess the secret here is to not instantiate any classes that force the JVM to load a class that uses the org.osgi.service.cm package... but I can't see how I can achieve that without ugly hacks with reflection...
Does anyone know how I can check if the package is available at runtime, and if not, avoid the java.lang.NoClassDefFoundError at runtime, making this package dependency truly optional?
The way to tell if the package is available at runtime is to attempt to load a class from it and be prepared for the NoClassDefFoundError. You could do this in a central place and then decide to avoid code paths which require the optional but absent package.
The PackageAdmin can be used to inspect package metadata of the system. It has been deprecated and you are expected to use the BundleWiring instead.
So, in your DS, you would have a dependency to the PackageAdmin/BundleWiring and check if the cm package is exported...

Tricky Classpath issue

Working on an existing application, it runs on Weblogic as a massive ear file.
There is custom code, written by my organization, as well as code written by the vendor that all runs on one classpath when weblogic starts up.
Some of our custom code uses spring 1.2, in the latest version of the vendors code, they use spring3. So we cannot get the ear to completely work unless we can get each component the spring version it needs in order to function. But since they are both using the classpath that weblogic is started on, either spring1.2 or spring 3.0 will be first depending on the order in the classpath.
Am I stuck? Missing something? I've never had to deal with classpaths at this level.
Thanks
Classloaders use a delegation model when loading a class. The classloader implementation first checks its cache to see if the requested class has already been loaded. This class verification improves performance in that its cached memory copy is used instead of repeated loading of a class from disk. If the class is not found in its cache, the current classloader asks its parent for the class. Only if the parent cannot load the class does the classloader attempt to load the class. If a class exists in both the parent and child classloaders, the parent version is loaded. This delegation model is followed to avoid multiple copies of the same form being loaded. Multiple copies of the same class can lead to a ClassCastException.
Think setting the following in weblogic.xml might help
prefer-web-inf-classes Element
The weblogic.xml Web application deployment descriptor contains a prefer-web-inf-classes element (a sub-element of the element). By default, this element is set to False. Setting this element to True subverts the classloader delegation model so that class definitions from the Web application are loaded in preference to class definitions in higher-level classloaders. This allows a Web application to use its own version of a third-party class, which might also be part of WebLogic Server. See "weblogic.xml Deployment Descriptor Elements".*
When using this feature, you must be careful not to mix instances created from the Web application's class definition with issuances created from the server's definition. If such instances are mixed, a ClassCastException results.
Refer to the URL below
Oracle Weblogic Server

System class loader in Play Framework 2

I'm using Play 2.2.2, and I have an external jar that tries to load an XML resource from the same jar's root. It does so using System.class.getClassLoader().getResource("/Blabla.xml").
This fails, since apparently Play has a weird hierarchy of classloaders: ReloadableClassLoader and several parents. This hierarchy doesn't include the system class loader, nor the extensions and bootstrap classloaders.
How is this possible?
I found out that using ClassLoader.getSystemClassLoader() returns a classloader hierarchy that resembles the standard classloading hierarchy. But I would prefer not to touch the external jar mentioned above, and make System.class.getClassLoader().getResource("/Blabla.xml") work.
How can I make System.class.getClassLoader().getResource("/Blabla.xml") return the standard system classloader?
Play's classloader set-up is rather complex due to the compile-reload mechanism in development mode. Rather than trying to use the normal System.class.getClassLoader() you may want to use built-in API methods to get to a resource or to the classloader.

Using SnakeYaml under OSGi?

Does SnakeYaml work within an OSGi framework? I've modified the MANIFEST & such so that it deploys correctly, but but trying to load a document into a JavaBean object structure is failing with "Class not found" exceptions.
Thanks.
Sometimes it is as simple as adding manifest headers to make a jar play nice in the OSGi sandbox. Sometimes jars/libraries do "naughty" things in the context of OSGi. A golden rule is to avoid using "Class.forName()" due to the way OSGi uses classloaders, otherwise perfectly valid in a single class loader environment. I pulled down the source to SnakeYaml and they're bean based loader makes use of Class.forName.
The good news is that there appears to be a constructor, CustomClassLoaderConstructor, that let's you use your own classloader and you use this when you make the core Yaml parser object. The key is getting the right class loader. You'll want to use the classloader of the bundle in which you're using Yaml BUT you'll need to make sure than ANY CLASS that will be created is imported into that bundle. The import will make sure all of the objects needed are in the classloader tree that OSGi creates.
See this question for created a classloader based on a bundle.
For anyone that stumbles across this, newer versions of snakeyaml are already a osgi bundle. No need to fiddle at file MANIFEST.MF.
You must just use a CustomClassLoaderConstructor like this:
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.CustomClassLoaderConstructor;
CustomClassLoaderConstructor constructor = new CustomClassLoaderConstructor(this.getClass().getClassLoader());
Config config = new Yaml(constructor).loadAs(in, Config.class);
Code tested with org.yaml.snakeyaml;bundle-version="1.25.0"

Implementing dynamic plugins in Java

I'd like to implement a dynamic plugin feature in a Java application. Ideally:
The application would define an interface Plugin with a method like getCapabilities().
A plugin would be a JAR pluginX.jar containing a class PluginXImpl implementing Plugin (and maybe some others).
The user would put pluginX.jar in a special directory or set a configuration parameter pointing to it. The user should not necessarily have to include pluginX.jar in their classpath.
The application would find PluginXImpl (maybe via the JAR manifest, maybe by reflection) and add it to a registry.
The client could get an instance of PluginXImpl, e.g., by invoking a method like getPluginWithCapabilities("X"). The user should not necessarily have to know the name of the plugin.
I've got a sense I should be able to do this with peaberry, but I can't make any sense of the documentation. I've invested some time in learning Guice, so my preferred answer would not be "use Spring Dynamic Modules."
Can anybody give me a simple idea of how to go about doing this using Guice/peaberry, OSGi, or just plain Java?
This is actually quite easy using plain Java means:
Since you don't want the user to configure the classpath before starting the application, I would first create a URLClassLoader with an array of URLs to the files in your plugin directory. Use File.listFiles to find all plugin jars and then File.toURI().toURL() to get a URL to each file. You should pass the system classloader (ClassLoader.getSystemClassLoader()) as a parent to your URLClassLoader.
If the plugin jars contain a configuration file in META-INF/services as described in the API documentation for java.util.ServiceLoader, you can now use ServiceLoader.load(Plugin.class, myUrlClassLoader) to obatin a service loader for your Plugin interface and call iterator() on it to get instances of all configured Plugin implementations.
You still have to provide your own wrapper around this to filter plugin capabilites, but that shouldn't be too much trouble, I suppose.
OSGI would be fine if you want to replace the plugins during runtime i.g. for bugfixes in a 24/7 environment. I played a while with OSGI but it took too much time, because it wasn't a requirement, and you need a plan b if you remove a bundle.
My humble solution then was, providing a properties files with the class names of plugin descriptor classes and let the server call them to register (including quering their capabilities).
This is obvious suboptimal but I can't wait to read the accepted answer.
Any chance you can leverage the Service Provider Interface?
The best way to implement plug-ins with Guice is with Multibindings. The linked page goes into detail on how to use multibindings to host plugins.
Apologize if you know this, but check out the forName method of Class. It is used at least in JDBC to dynamically load the DBMS-specific driver classes runtime by class name.
Then I guess it would not be difficult to enumerate all class/jar files in a directory, load each of them, and define an interface for a static method getCapabilities() (or any name you choose) that returns their capabilities/description in whatever terms and format that makes sense for your system.

Categories

Resources