I am currently using this configuration to set the classloader in my hazelcast instance.
Config config = new XmlConfigBuilder(HAZELCAST_CONFIG).build();
config.setInstanceName(HAZELCAST_INSTANCE_NAME);
config.setClassLoader(MyClassA.class.getClassLoader());
This works for a map that has MyClassA elements.
Is it possible, having only one hazelcast instance, to configure the classloader in order to include all the classes of my project?
I am in an OSGI environment with multiple bundles.
The issue with having visibility to classes from multiple bundles is that different bundles can contain classes with matching names but different implementations. For example, bundle A could have class org.example.Foo version 1.0 but bundle B could have class org.example.Foo version 2.0.
I recommend creating a bundle that defines exactly which types should be visible to Hazelcast. It does this simply by importing packages with controlled version ranges. You can now use the ClassLoader of this bundle with Hazelcast.
Unfortunately there is not a standard way to directly access the ClassLoader of a bundle in OSGi. However you can in just a few lines of code write a ClassLoader that delegates to the Bundle.loadClass method from its loadClass method.
Related
I have a java application which is implemented to find providers of an interface using java.util.serviceLoader. When I a add a new provider jar at runtime to the classpath of the application the application is not finding it. If I restart the application the application finds the provider jar. Are there any options for java application to find the provider jar at runtime as I think that is what java serviceLoader is supposed to do.
I am following the instructions in this page.
http://cr.openjdk.java.net/~mr/jigsaw/spec/api/java/util/ServiceLoader.html
Deploying service providers on the class path
Explanation can be found here Creating Extensible Applications (at the end of the tutorial):
Limitations of the ServiceLoader API
The ServiceLoader API is useful, but it has limitations. For example, it is impossible to derive a class from the ServiceLoader class, so you cannot modify its behavior. You can use custom ClassLoader subclasses to change how classes are found, but ServiceLoader itself cannot be extended. Also, the current ServiceLoader class cannot tell your application when new providers are available at runtime. Additionally, you cannot add change-listeners to the loader to find out whether a new provider was placed into an application-specific extension directory.
Seems to apply to Java 8. Don't know if this has changed in the later editions.
I'm using Hazelcast 3.6.2 and cant get the classloader to work when in a multi-bundle environment. What is the approach on this? Setting the classloader in the config only works if the class to load is in the same bundle. In my case the class to load is in another bundle than the one creating the hazelcast instance.I world like you to use the HazelcastOsgiService and HazelcastOsgiInstance.
Any input is appreciated.
You have to provide your own classloader trick by writing a Delegating ClassLoader that keeps track of installed bundles. I did one of those "hacks" in the past to test it. You can find some code for the same issue, solved using a custom Serializer, on github (https://github.com/noctarius/hazelcast-mapreduce-demo/blob/master/musicdb-model/src/main/java/com/hazelcast/example/musicdb/server/ModelMapReduceActivator.java), anyhow Hazelcast does not yet officially support that out of the box.
My project has a set of custom defined annotations that could be present in any bundle deployed in the OSGi 4.3 framework. I want to find any class with these annotations in the classpath. I tried using BundleWiring.listResources(...) and Bundle.loadClass(...) for each class found. I have done some tests with an small set of bundles and it needs almost 200MB of Permanent Generation JVM memory space because all classes are loaded.
Is there a way to free loaded classes PermGen memory space when the program realizes that they does not have these annotations?
Is there a better way to look for annotated classes in an OSGi framework?
I think you should not do annotation scanning as it slows down startup and needs a lot of memory. JEE application servers do annotation scanning at startup to make lazy programmers happy and the result is very annoying (e.g. scan for JPA or EJB annotations).
I guess you are implementing a technology where you can define the rules. I suggest that you should define rules that are similar to these:
Annotate your class
Have a MANIFEST header where the annotated class must be listed.
An even better solution can be to use a custom capability namespace with specified attributes. E.g.:
Provide-Capability: myNamespace;classes=com.foo.myClass1,com.foo.myClass2
In your technology, you should write a BundleTracker that calls:
BundleWiring.getCapabilities("myNamespace");
If the namespace is present, you can find the classes that should be processed.
If you implemented the technology, you can consider an extension to Bnd to fill that MANIFEST header automatically. That extension can be used than when bnd is started from the command line or from build tools like maven.
Btw.: You can use ASM to parse the class bytecode or use the built in possibility of Java to build up AST. Although those could work to solve the memory issue, I still think that you should define the list of classes directly in the MANIFEST header as it makes things much more clear. You can read the MANIFEST headers, you can check the capabilities on webconsole but you cannot do the same with bytecode.
Usually, classpath scanning for annotations is a bad idea in an OSGi context, as the classpath is more like a graph. However, there are situations where this can be useful. Hence, OSGi encourages the usage of the Whiteboard Pattern.
What you could possibly do is register each of these classes as services in the OSGi registry. Then, create a separate bundle that just tracks these services and transforms/manipulates them in some way. For example, this project scans for all classes annotated with #Path and #Provider annotations, and transforms them into Jersey REST APIs.
Bundle A depends on Bundle XStream.
However Bundle XStream also needs access to classes in Bundle A, otherwise I can't do object deserialization ala (BundleA.class)xstream.fromXml(xmlString)
Now what I did is to Import-Package in Bundle XStream on my BundleA packages and exported them in BundleA, but since BundleA uses XStream as well, Eclipse detects a "cyclic reference". It all seems to run fine, but I don't see the point of this Eclipse error then?
How else would I solve this in osgi?
Generally, you should try to get a clear client-server package relation among your bundles. So if possible at all, you should get rid of the cyclic reference. In your situation that is possible.
In contrast to what you indicate, your XStream bundle is able to do de-serialization of objects from another bundle if you are able to tell the functionality to use a different class loader for loading the classes indicated in the stream. Since it seems you are using XStream, you can use:
xstream.setClassLoader(bundleAClassLoader);
where bundleAClassLoader is a class loader that has access to your domain classes (the class loader of bundle A). The Import-Package for the XStream bundle is in that case not necessary.
I am using JCS to store the ldap search results which should be shared by multiple EJB. I have created a singleton class to initialize JCS only once but due to EJB's classloader, it's been initialized multiple times with its own copy. so search resources are not shared.
How are you guys resolving issue where you need to share the cache across multiple beans?
I am looking for cache within JVM. (Not the remote e.g memcached etc.).
Glassfish is used as an application server.
I haven't been able to test it yet, but I think that one of the techniques explained in the "Circumventing Class Loader Isolation" chapter of the Application Development Guide for the version of Glassfish you are using may solve you problem.
Short version, at least valid for versions 2-3-4 : use the Common Classloader (what exactly this common classloader does and its relation to the other classloaders is explained in the same manual). There are several ways to do this:
copy the jar to domain-dir/lib
or copy the jar to as-install/lib
or run asadmin add-library --type common /path/to/your.jar (will only work in version 4 iirc)
There are several questions here on SO that are related to "Circumventing Class Loader Isolation" (just use that search term), look there for examples and more discussion.
Simply put, the singleton will likely "live" where your caching implementation class lives, as that's the classloader in the hierarchy that "owns" the class.
So, if each EJB is separately deployed, with their own copy of the cache lib jar, they'll each get their own copy.
If your beans are deployed in a composite EAR, sharing a single instance of the lib jar, then that cache will be shared across the beans in the EAR.
If you remove the lib from the deployment completely, and put it outside the container ($DOMAIN/lib/ext for example), then that cache will be shared by EVERYTHING in the domain (EJBs, EARs, WARs, etc.).