JBoss AS Classloader implementation? - jboss5.x

I'm migrating a small tool I wrote for our application that was working on WAS and WLS to JBoss AS 5.1. Basically, the tools helps me to troubleshoot classloading issues: it discovers the classloading hierarchy of a specified class, at runtime, and finds out all classes and jars loaded by each classloader. It is a fairly simple tool - it just uses the Classloader.getPArent() method to get the classloader hierarchy.
The trick that made it work for WLS and WAS was that their classloader implementations either had a 'getClassPath()' method which returned a full list of all classpath entries, or they were instances of the URLClassloader class, and I could use its 'getURLs()' method to get the same info.
Now, it looks like JBoss internal classloaders do not follow the same pattern - so I was wondering if there is some other way to get the same information somehow?
Basically, I want to get a full picture of the classloading hierarchy and which classloader loads which classes/jars at runtime. It has to be a runtime information - because I want to be able to find out this information for any instance of a class, be it a servlet, an EJB, a util class or JSP - so that I could see where in the classloader hierarchy those objects are, what their sibling loaded resources are and what their parent classloaders are.
Thanks!
Marina

In fact this dued to VFS used by JBoss, I've written a post relating this issue and the corresponding solution.

Related

Drools doesn't work with spring-boot-devtools

When we have spring-boot-devtools on pom.xml the drools rules dont work. There are no error but the drools rules dont get fired at all. After excluding the spring-boot-devtools the drools rule start working.
There's a documented issue about a classloading problem while using spring-boot devtools together with drools: DROOLS-1540
As specified in spring-boot reference documentation you can add jars to the devtools "reloading" classloader as a workaround.
META-INF/spring-devtools.properties
restart.include.drools-core=/drools-core-7.0.0.Final.jar
restart.include.drools-compiler=/drools-compiler-7.0.0.Final.jar
restart.include.kie-api=/kie-api-7.0.0.Final.jar
restart.include.kie-ci=/kie-ci-7.0.0.Final.jar
restart.include.kie-internal=/kie-internal-7.0.0.Final.jar
Be careful to use YOUR exacts jar and eventually add other libraries directly referenced in your rules files.
(for moderator) flgged Drools rule does't working in Spring Boot Controller but working in Junit Test as duplicated of this question and removed the answer on that post
Really strange problem indeed. As far as I can tell, there are 2 issues here:
Apparently, the KieFileSystem doesn't play well with org.springframework.boot.devtools.restart.classloader.RestartClassLoader. Even if I tried passing the DRL as a String, it didn't take it.
Even if I managed to get a populated KieBase using a kmodule.xml file, the rules were still not firing. My guess is that the classloader at some points changes the definition of the classes, so when you insert a Product object, its class is no longer the same as the Product class that is being used by the DRL. Another possibility is that there are multiple classloaders in play. Take a look at this question and at this document.
Unfortunately, I was not able to find a way to make it work. I hope the information I've provided helps you.

Run Eclipse RCP application with Java instrumentation

Using Java instrumentation, we can access a class that is loaded by the Java classloader from the JVM and modify its bytecode by inserting our custom code, all these done at runtime. We need not worry about security, these are governed by the same security context applicable for Java classes and respective classloaders.
We are able to access some java application using this as they run in same classloader.
Now what we are trying to do is to access eclipse RCP application using java instrumentation but in RCP each bundle has its own classloader and our instrumentation code runs with java application classloader.
when we are accessing it, it is throwing "Workbench has not been created yet" exception whereas the workbench is up and running.(I hope this is because of diffrent classloaders for both of them).
I have tried doing thing from here but to no success.
Is there any way we can work RCP application out with java instrumentation.
When you instrument a class, the references of the inserted code are resolved by the ClassLoader of the modified class. If that class loader does not delegate to the application loader, e.g. because it is rule based and doesn’t know your instrumentation specific classes you can’t enforce delegation.
What you can do:
Use access override to define classes in the scope of the loader of the instrumented class. Since defineClass is final the bundle class loader can’t intercept it. However, the references of these injected classes are again resolved by the bundle loader so you have to add all required instrumentation classes this way.
Since the bundle class loader will do the parent loader delegation for the official Java API classes, you can instrument one of the core Java classes to add a helper method which will be called by the instrumented classes and delegates to your instrumentation classes which must have been added to the boostrap loader
You can use the trick described in the answer you have already linked to put a MethodHandle into the system properties. The instrumented classes can retrieve and invoke it as MethodHandle is a core class which will be correctly resolved by the bundle loader and the underlying method can be invoked without having access to its defining class (assuming that parameter and return types are all either primitive types or core classes).

OSGi Karaf Scala UnsupportedAudioFileException

this is my first post here. I'm currently working on a simple http audio servlet in Scala on Apache-Karaf 3.0.0. I'm deploying it as a feature from inside some bundles, which I've built using a maven project. I'm using the 'javax.sound.sampled' library to get the audio, and I'm loading the file from the AudioSystem with 'java.io.File'.
val file = new File("audioFile.wav")
val audioStream = AudioSystem.getAudioInputStream(file)
This is obviously not the actual code, as I've stripped out all of the trivial bits. But this is where it fails, on the 'getAudioInputStream' call.
When I deploy this code to Karaf it fails with 'UnsupportedAudioFileException'. The file does exist, and is readable, I've already validated this. Also, I've made sure that this code can be run under the following.
- Scala 2.10.2, 2.10.3
- Java 1.7.0_45 ( This is the same JRE as my Karaf program is using )
- SBT 0.12.4 ( With the different Scala versions )
The only place this fails is when I deploy it to Karaf. I don't know if Karaf has cut out some random audio support, or what is going on, because this otherwise works when deployed through SBT or using the Scala command line. I've also looked into alternative libraries, but to no avail. Most other solutions seem to be based around actually playing the audio through a sound driver, which is useless to me. I need the actual byte data.
Also, keep in mind that just sending the file over is also useless me. Another requirement is that I need to be able to be able to merge multiple audio files in to one seamless audio stream. I already have this done, I just need to port it to OSGi, and for some reason I am now getting this error. I don't know if Karaf has something to do with it, or if my building it through a Maven project has broken something. I've looked around, and have found very little hint as to where the problem might be.
The audio files I'm using are of Waveform audio. 8,000 sampling rate, 16 bits per sample. I don't think this would actually make a difference, but I'm no expert on audio formats.
My pom.xml dependencies are as follows. The only plugin I'm using is the Scala compiler, and of course my root pom.xml is using the org.apache.felix maven-bundle-plugin. There's really not much magic going on here, yet the mystery remains.
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.10.3</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
Any clues would be greatly appreciated, thank you.
I think AudioSystem is not fully OSGi ready. This is what I found in the Aries Spy Fly dcoumentation.
Not sure what exactly you have to do to make it work but this might help.
https://aries.apache.org/modules/spi-fly.html
Special Cases
SPI Fly can be used for most SPI provider/lookup systems that use the TCCL pattern to obtain implementations. However in some cases, some special treatment is needed. This special treatment is often needed when the API itself does not match the name of the resources in META-INF/services, java.util.ServiceLoader is such a case, however SPI-Fly has built-in knowledge of ServiceLoader. Known APIs that require special treatment are listed below:
javax.sound.sampled.AudioSystem: This class uses sun.misc.Service under the covers (via com.sun.media.sound.JDK13Services) which is a predecessor to java.util.ServiceLoader. There is no special treatment for sun.misc.Service in SPI Fly (yet), but the AudioSystem.getAudioInputStream() API can be made to work by explicitly listing it in the provider bundle (the one that contains the relevant META-INF/services resources): SPI-Provider: javax.sound.sampled.AudioSystem on the consumer side you can use SPI-Consumer: javax.sound.sampled.AudioSystem#getAudioInputStream
Christian's answer is correct but I wanted to provide an updated link to the spifly documentation page. Specifically:
Java's java.util.ServiceLoader.load(), other similar methods such as
sun.misc.Service.providers() and also other static finder methods such
as the FactoryFinder.find() methods try to locate 'service'
implementations by looking for resources in the META-INF/services
directory of all the jars visible to the Thread Context ClassLoader
(TCCL).
There are a number of issues with the above mechanisms when used in
OSGi:
The Thread Context ClassLoader is not defined in general in an OSGi context. It can and has to be set by the caller and OSGi cannot
generally enforce that.
A bundle can't Import-Package META-INF/services as potentially many bundles will contain this pseudo-package and the OSGi framework
will only bind a single exporter to an importer for a given package.
Instantiating an SPI provider generally requires access to internal implementation classes, by exporting these classes an
implementing bundle would break its encapsulation.
Even if an implementation class was exported, importing this class in a consumer bundle would bind it to the specific implementation
package provided, which violates the principle of loose coupling.
Bundles have a dynamic life-cycle which means that provided services could disappear when a bundle is updated or uninstalled. The
java.util.ServiceLoader API does not provide a mechanism to inform
service consumers of such an event.
The SPI Fly project makes it possible to use existing code that uses
ServiceLoader.load() and similar mechanisms under OSGi.
Please note that as of 2016-05-20 new versions of the com.googlecode.soundlibs artifacts were uploaded to the maven central repository. These new versions of the artifacts are proper OSGi bundles. This will help everyone who needs to use the Java Sound API within an OSGi container
I created a simple example project on github that demonstrates how to play an MP3 file inside an OSGi container using the Java Sound API. Checkout the branch static-weaving and dynamic-weaving to see the respective solutions.

How to add jars properly to a eclipse bundle

I got a little problem. I want to use hibernate in an eclipse rcp. (i'm new to osgi and eclipse rcp). So I added the jar into the plugin-project folder and the build path and the bundle build path, but when I try to use hibernate from my bundle, it crashes with a ClassNotFoundException.
What is the proper way to do this?
Pls look at eclipse buddy policy. This might help you if you are facing class not getting loaded because of osgi classloading.
Hibernate, and many other classic Java programs (ab)use dynamic class loading to to connect the different parts. They classes they use are read from a file and then loaded with Class.forName. This is fundamentally not-modular since these classes are by definition implementation classes, which should be hidden.
Since OSGi is a modularity framework it puts fences around a module (a bundle) and refuses to load anything that is not properly exported and imported. So if Hibernate does its Class.forName it will run right into this fence, as it should be to get the advantages of modularity.
Eclipse Buddy policy is like a huge hole in this fence, moving things back tot he bad old classpath: linear search. With a buddy policy, Eclipse will just start searching if there is a class somewhere that has that name. Since this ignores versions, you can no longer rely on proper version handling. The good news is that it works most of the time. The bad news is that you loose privacy and when it does not work you get weird errors.
With Hibernate, only solution is to not use the text file setup but use the API and give Hibernate the actual classes. In those cases Hibernate will use the class loader of those classes and that works. In OSGi, as long as you follow the Java language rules there are no problems.
To handle the kind of problems that class loading hacks address OSGi uses services.

Using latest Xerces with Eclipse RCP application

I'm trying to use Xerces 2.11.0 in an Eclipse RCP application, but from everything I've tried, I'm at a loss to figure out how. To complicate matters, I'm also trying to use Batik 1.7.
I've created my own bundles for Xerces and the xml-apis, I've added the additional W3C DOM interfaces that Batik uses to my xml-apis bundle.
The first problem that occurs within Batik
java.lang.NoClassDefFoundError: org/w3c/dom/ElementTraversal
The fundamental reason for this appears to be because org.w3c.dom is contained in the JRE and exposed through org.eclipse.osgi (the system.bundle). This appears to trump any other bundle that wants to provide the package.
Trying to influence the system using require-bundle with my bundle before any others or using import-package with an explicit version leads to errors like
java.lang.LinkageError: loader constraint violation: loader
(instance of org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader)
previously initiated loading for a different type with name
"org/w3c/dom/Document"
Changing the org.osgi.framework.system.packages and org.osgi.framework.bootdelegation parameters to remove org.w3c.dom and adding my bundle to osgi.framework.extensions, leads to erros like
java.lang.LinkageError: loader constraint violation in interface itable
initialization: when resolving method
"javax.xml.parsers.DocumentBuilder.setErrorHandler(
Lorg/xml/sax/ErrorHandler;)V" the class loader
(instance of org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader)
of the current class, org/apache/log4j/xml/DOMConfigurator, and the
class loader (instance of <bootloader>) for resolved class,
javax/xml/parsers/DocumentBuilder, have different Class objects for the
type rrorHandler;)V used in the signature
I've also tried using the java.endorsed.dirs, which makes things break very quickly.
Any ideas what I've missed or may be doing wrong?
We used to have similar problems using DOM level 3 on jdk 1.4 and I think endorsed dirs is the only solution that works because you need to override the DOM APIs in the jdk.
We couldn't face going down this route again so instead ripped out references to ElementTraversal and built Xerces by hand and the problem goes away. If Batik uses ElementTraversal that's not an option though.
I think I've found a solution.
I've modified my xml-apis bundle so that it is a fragment, hosted by the system.bundle.
I've also modified my Xerces bundle to import the packages rather than requiring the xml-apis bundle (which was done originally to convince xerces to use the right packages).
From the testing I've done, this appears to be sufficient to allow each of the bundles to locate the same implementation of org.w3c.dom packages, which contains all the correct classes.