Atmosphere servlet classloading conflict with java - java

I am not sure how to title this question but I'll try to explain what the issue is.
I am currently testing out Atmosphere framework in a web application. I started by reading the documentation and then testing the chat-multiroom sample. I am running it in eclipse using tomcat 8.5. When the atmosphere servlet initializes it will scan a package for any classes that have certain annotations and if it finds the annothions it will add the class to a map using a path as the key. For this to work it must first scan its own packages looking for what annotations it should use and add them to a map of available annotations. This list has to be populated for the annotated classes to be initialised. The code for this looks like this:
public Class<? extends Processor> handleProcessor(Class<?> clazz) {
if (Processor.class.isAssignableFrom(clazz)) {
Class<Processor> p = (Class<Processor>) clazz;
if (logger.isTraceEnabled()) {
logger.trace("Processor {} associated with {}", p, p.getAnnotation(AtmosphereAnnotation.class).value());
}
annotations.put(p.getAnnotation(AtmosphereAnnotation.class).value(), p);
return p;
}
return null;
}
So it goes though every class it finds and checks if it implements Processor. Processeor is an interface provided by atmosphere imported with import org.atmosphere.annotation.Processor;
However when I debug this code it is instead compareing clazz with the jdk:s interface javax.annotation.processing.Processor instead of org.atmosphere.annotation.Processor. This is causing the map to be empty. This results in the endpoints are not loaded because there are no annotations to look for.
If I download the atmosphere code and copy it to my src folder it works correctly.
I am using Eclipse IDE at the moment and I am wondering if there is a way to configure the project or the tomcat server in some way to make it understand which interface it should use.

[EDIT]
After some more research the problem isn't due to the class comparision instead it is about how tomcat loads classes. Atmosphere relies on that the container loads the annotation classes and passes it into Atmosphere ServletContainerInitializer however tomcat will not pass the classes that exisit in the package jar files under the webapps lib folder. It will only pass in the classes that are in the webapps WEB-INF/classes folder and not the WEB-INF/lib folder. That is why it works if I add the Atmosphere src to the webapps src folder in eclipse.
[EDIT2]
It turns out I had disabled jar scanning in catalina.properties.
Enabling the jar scanning again solved the issue.

Related

Developing application with plugin support in Java

I have been researching on how to develop an application that can load plugins.
So far, I've seen that this can be done by defining an Interface, and have the plugins implement it.
However, my current issue is on how to load the plugins when they're packed in Jars. Is there a "best" way to do it?
The current logic I'm thinking of is to get each plugin and inside their Jar look for the class that implements the Interface. But I don't know how to do such lookup. I think that this logic may not be a good one, but I couldn't find any useful information on this specific topic.
**Edit1: **
Adding more information:
The intended plugins would be Jar files contained inside a subdirectory where the main application's Jar would be located, like this:
Application's folder
|- Main_Application.jar
|- Plugins
|- Plugin1.jar
|- Plugin2.jar
|- Steve's_plugin.jar
And so on.
What I expect is that the Application will be able to load all plugins inside the folder at runtime. So in the code, it would only be aware that the plugin's folder should exist and there should be Jars inside such folder.
Let's say I have a plugin interface like this:
interface Plugin
{
public void run();
}
Plugins would be identified by a class that implements such interface, like so
class Plugin1 implements Plugin
{
//attributes and other methods
#override
public void run()
{
//something happens here
}
}
class Plugin2 implements Plugin
{
//attributes and other methods
#override
public void run()
{
//something happens here
}
}
The Application should be compiled only once, and be able to load any Plugins added to the folder when it is executed.
For the Application to be able to load any Plugin, do I need to establish rules on the contents of the Jar, like package name and the class that implements the interface? Or it is expected that the class implementing the plugin interface could be in any package within the Jar, and have any name?
This is the more generic approach to what I would like to do with such plugins. In short, I'm planning to build an Application that will have tabs, and each plugin will provide the Interface and Functionality of each tab. I'm trying this because I want to be able to maintain each tab separately, and don't want to recompile the whole application because of changes in only one component that don't affect the others at all.
Get the list of plugin jars:
File[] jars = new File("Plugins").listFiles();
Then, use the code from this answer about loading all classes from a JAR file, but run it once for each file in jars whose name ends in ".jar". At the bottom of the loop body, after
Class c = cl.loadClass(className);
continue with
if (Plugin.class.isAssignableFrom(c)) {
Plugin plugin = (Plugin) c.newInstance();
// And then, do something with the plugin here
}
I share #Mifeet's concerns about security - you might want to use a SecurityManager to limit what the plugin code is allowed to do.
Very old question, but still relevant if some one searches.. Adding to the accepted answer,
Use OSGI framework
Refer Apache Felix for a reference implementation
If you wanted to have a light version of OSGi, try to use apache connect - pojosr

How to use interfaces declared in an external JAR in a JSF application hosted in a local TomCat server

I have a JSF 2 application that depends on a external JAR file. Such a JAR file is generated by other project in the same Eclipse workingset. This architecture was chosen for the sake of modularity, so I have some domain core services in a JAR. My application depend on that JAR file and uses it in order to provide end user services.
In the JSF2 application I have a simple managed bean, as seen below:
package ufprJSF;
import java.util.Collection;
import javax.faces.bean.*;
import unidades.dominio.Cargo;
import unidades.dominio.repository.CargoRepository;
#ManagedBean
public class CargoBean {
private CargoRepository cargoRepository;
private Collection<Cargo> todos;
public Collection<Cargo> getTodos() {
return todos;
}
public String listarTodos() {
return "cargos?faces-redirect=true";
}
}
The home page of the application shows a menu that has some links, one of them linked to the listarTodos() method of the above presented bean. That method just redirects to another page of the application.
If I try to run the application in a local TomCat 8 server, I receive:
HTTP Status 404 - /ufprJSF/index.xhtml
type Status report
message /ufprJSF/index.xhtml
description The requested resource is not available.
Apache Tomcat/8.0.14
The index.xhtml does not use the above bean, it just shows a menu with a link to listarTodos() method of that bean. The console shows the following (among many other lines in the stack):
Caused by: java.lang.ClassNotFoundException: unidades.dominio.repository.CargoRepository
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1293)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1145)
... 33 more
The project compiles, so during the compile time, the referenced interface is found, what leads me to believe that the dependencies of the JSF2 application are correctly setup. The JAR that contains such a type shows under Referenced Libraries node in the Eclipse package explorer.
If I simply comment line 12 as below
...
#ManagedBean
public class CargoBean {
// private CargoRepository cargoRepository;
private Collection<Cargo> todos;
...
The runtime problem disapears. However, my bean depends on the CargoRepository interface to do what it has to do, so I have to find a way of using that JAR in my JSF2 application.
Any help on this issue will be greatly appreciated!
Thanks in advance!
Check if the Jar library exists in the deployed applications WEB-INF/lib directory.

Using Libraries in Vaadin: com.vaadin.server.ServiceException

Iam trying to use the matlabcontrol library in vaadin. I basically want use vaadin as a GUI for better configuration of the variables.
I have a test GUI running, everything works fine, until I try to add matlabcontrol specific variables or calls. I did add the library and the matlab interface works great when testing.
I will show you an abstract example:
public class UI_Matlab extends CustomComponent {
public UI_Matlab{
Label matlabRox = new Label("Matlab rocks!");
setCompositionRoot(matlabRox);
}
}
This works fine as expected!
But when I change it too:
public class UI_Matlab extends CustomComponent {
public UI_Matlab{
MatlabProxyFactory factory = new MatlabProxyFactory();
Label matlabRox = new Label("Matlab rocks!");
setCompositionRoot(matlabRox);
}
}
I already get:
"HTTP Status 500 - com.vaadin.server.ServiceException: java.lang.NoClassDefFoundError: matlabcontrol/MatlabProxyFactory"
Additional Information:
Vaadin 7.0
Tomcat v7.0
Eclipse Kepler
matlabcontrol 4.1.0 (edited)
The widget is trying to load additional classes it is depending on (MatlabProxyFactory) and cannot find them (NoClassDefFoundError is like a ClassNotFoundException, but one level "deeper", like a field or return type of the class you are loading cannot be found).
--> Check your build path or whether what you are deploying is complete wrt. dependencies.
I found the answere in another post:
External project dependency in Vaadin
They describe it a little different, so I will add what I did.
What "hiergiltdiestfu" probably meant worked out well, but I accidently was checking the project classpath.
The solution is to add the libraries to the server classpath, which means you have to add it to the tomcat classpath in my case.
Open the following in eclipse:
Run > Run Configurations > Apache Tomcat > (your Tomcat instance) > Classpath
Then add to user entries the library of your need.

Jar not using contained classes or namespace collision

I'm using netbeans to generate a web service client from a WSDL doc.
The client works fine until we put it in our production environment. The jars were generated against javax.ws.xxxxx classes from jaxws-api.jar and jaxb-api.jar, which we placed in out production classpath.
In our production environment we have other code that depends on xfire libraries. When we attempt to instantiate SubmissionAPI(), we are getting a NoClassDefFound Exception. I'm pasting the stack trace below.
UBLSoapTest class appears to call the correct 'Service' class, but the 'Service' class
is calling org.codehaus.xfire.jaxws.Provider.
I've checked the source for javax.xml.ws.Service, and it has 'import javax.xml.ws.spi.Provider;'
We've tried assembling the jar with the javax.xxxx classes inside and still get the same result. I suspect we need to set a classpath in the manifest file, but I'm not sure what needs to be there.
FAIL: Exception: java.lang.NoClassDefFoundError: Could not initialize class
org.codehaus.xfire.jaxws.JAXWSHelper
org.codehaus.xfire.jaxws.ServiceDelegate.<init>(ServiceDelegate.java:33)
org.codehaus.xfire.jaxws.ServiceDelegate.<init>(ServiceDelegate.java:53)
org.codehaus.xfire.jaxws.Provider.createServiceDelegate(Provider.java:32)
javax.xml.ws.Service.<init>(Service.java:56)
org.ubl.soap.test.SubmissionAPI.<init>(SubmissionAPI.java:44)
I'm a bit at a loss of even where to look from here.
We've tried setting classpath in the manifest, with little success.
The basic jar structures we've tries are:
/org/xxxx
/META-INF/xxx
and
/org/xxx
/META-INF/xxx
/javax/xxx
and
/org/xxx
/META-INF/xxx
/jaxws-api.jar
/jaxb.jar
It seems that you are missing the impl jar for JAX-WS. If you are relying on Codehaus to provide the impl, you might want to make sure their impl works. According to their site, it's a newly supported component.
The alternative is to provide your own impl jar and put it in the class path so JAX-WS interfaces are found there. But usually the app server where you deploy your web service app should include the impl in its class path.

Same class different version, dependencies, NoSuchMethod

I am working on a web project that has 2 different dependencies being pulled into war file of the same class
(different versions, different package)
One is :
com.google.common.collect, and the other is Guava API package. When I run this service on websphere application server, it throws NoSuchMethodFound Exception at ImmutableList.copyOf. It clearly is loading the earlier class instead of the class from Guava which has the required functions.
I cannot change any dependency, how ever is it possible for me to override a particular dependency by other using maven?
How should I solve this problem?
If you have control over the WebSphere installation, you can also try this:
locate the jre lib directory of your application server (/WebSphere/AppServer/java/jre/lib)
create a directory 'endorsed' put your required jars into this directory( Guava API).
The jars in this directory will be loaded first and override what you have in you war file.
This is not recommended but you can use it as patch to override the conflicting classes.
The first matched class found on the classpath is used. Therefore if you can specify the classpath in different ways to try and influence what class is picked up. (i.e. specify the class that you want loaded first in the classpath). This is not a good practice because the Java specification does not guarntee to use the classpath order.
A better solution would be to manage the classloading yourself in the code. This can be done by
`ClassLoader myClassLoader = new MyClassLoader(libPath);
Object1 obj1 = myClassLoader .loadClass("com.google.common.collect", true);'
Now if a classloader attempts to load classes from a library, the dependent classes would be loaded by the same classloader that does not have access to the other libraries and dependencies.
Note: That if you use this and want to move to OSGi in the future you will incure some pain having to remove this code. Therefore try to limit it's use or switch to OSGi early!

Categories

Resources