Weblogic 11 G : Altering default class loading - classloader

I have one query regarding Weblogic server 11 G class loading infrastructure.
Lets say I have two application jars named A.jar and B.jar loaded in classpath during server start up.
Both jar contains class say LoadMe.class and sever loads LoadMe.class from jar A.jar by default.
Now I want to alter above default behavior and want to load that class from B.jar instead of A.jar.
How can I do that?
Any help will be appreciated.

Whenever you use LoadMe class for the first time the ClassLoader will try to resolve the dependency using the CLASSPATH.
Now if you have to load the class from B.jar, then you will have to explicitly place path to that jar first and A.jar second in the CLASSPATH. So the ClassLoader will pick the class from B.jar first.
Try this link for more on ClassLoaders
Read this and change the classpath and the problem should be solved
Setting classpath in WebLogic 11G
UPDATE:
System.out.println("Classpath dependency for LoadClass: ");
URLClassLoader classLoader = (URLClassLoader)LoadMe.class.getClassLoader();
System.out.println(Arrays.toString(classLoader.getURLs()));
System.out.println("Classpath dependency for Context: ");
URLClassLoader classLoader1 = (URLClassLoader)Thread.currentThread().getContextClassLoader());
System.out.println(Arrays.toString(classLoader.getURLs()));

Related

How can I prevent war libraries slf4j to collide with my project slf4j?

I am trying to deploy the reddog rdap-server war file into an embedded Jetty in my project. But everytime I am getting this eror:
java.lang.LinkageError: loader constraint violation: when resolving method "org.slf4j.impl.StaticLoggerBinder.getLoggerFactory()Lorg/slf4j/ILoggerFactory;" the class loader (instance of org/eclipse/jetty/webapp/WebAppClassLoader) of the current class, org/slf4j/LoggerFactory, and the class loader (instance of sun/misc/Launcher$AppClassLoader) for the method's defining class, org/slf4j/impl/StaticLoggerBinder, have different Class objects for the type org/slf4j/ILoggerFactory used in the signature
Problem is, the war file already contains slf4j. Any suggestions?
I tried to change my maven pom to "provider, which didn't help.
Use WebAppContext's (which it seems like from your error, and the mention of WebAppClassLoader).
Don't modify the Server or System classes lists on the WebAppContext or the WebAppClassLoader.
Don't set the WebAppContext.setParentLoaderPriority(boolean) field.
That's it.
Now you have the ClassLoader Isolation you are looking for.

how to force weblogic to load classes from web-inf/lib

This question originates from the question here
Essentially I would like the slf4j jar to be loaded from my war's web-inf\lib and NOT from weblogic's legacy jars.
NOTE - am deploying a WAR and NOT an EAR file.
In weblogic.xml tried the following :
<wls:container-descriptor>
<wls:prefer-application-resources>
<wls:resource-name>org.slf4j.*</wls:resource-name>
<wls:resource-name>ch.qos.*</wls:resource-name>
</wls:prefer-application-resources>
</wls:container-descriptor>
However weblogic is still loading these classes from its legacy jars and not from my application's web-inf\lib
Could someone suggest any other approach ?
those tags are only for the resources, you need the Filtering Classloader :
<wls:prefer-application-packages>
<wls:package-name>org.slf4j</wls:package-name>
<wls:package-name>ch.qos</wls:package-name>
</wls:prefer-application-packages>
Another approach is to use: prefer-web-inf-classes
(you cannot use both)
More info: https://docs.oracle.com/cd/E24329_01/web.1211/e24368/classloading.htm#WLPRG315

embedded jetty ignoring classes packaged in my war

I'm trying to run jetty in embedded mode. It appears to be ignoring all the classes bundled in my war file, whether under WFB-INF/classes or WEB-INF/lib.
My startup code:
package rfd;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.xml.XmlConfiguration;
public class RfdWar
{
public static void main(String[] args) throws Exception
{
System.setProperty("org.eclipse.jetty.LEVEL", "DEBUG");
Server server = new Server(8080);
org.eclipse.jetty.webapp.Configuration.ClassList classlist = org.eclipse.jetty.webapp.Configuration.ClassList.setServerDefault(server);
classlist.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration", "org.eclipse.jetty.plus.webapp.EnvConfiguration", "org.eclipse.jetty.plus.webapp.PlusConfiguration");
Resource jettyEnv = Resource.newSystemResource("jetty-env.xml");
XmlConfiguration conf = new XmlConfiguration(jettyEnv.getInputStream());
Object obj = conf.configure();
WebAppContext context = (WebAppContext)obj;
context.setWar("/tmp/thewar.war");
context.setContextPath("/");
context.setParentLoaderPriority(true);
server.setHandler(context);
server.start();
server.join();
}
}
My command line:
export JETTYHOME=<my_jetty_home>
JHL=$JETTYHOME/lib
export CLASSPATH=.:$JHL/jetty-server-9.2.10.v20150310.jar:$JHL/jetty-util-9.2.10.v20150310.jar:$JHL/jetty-http-9.2.10.v20150310.jar:$JHL/servlet-api-3.1.jar:$JHL/jetty-io-9.2.10.v20150310.jar:$JHL/jetty-webapp-9.2.10.v20150310.jar:$JHL/jetty-servlet-9.2.10.v20150310.jar:$JHL/jetty-security-9.2.10.v20150310.jar:$JHL/jetty-xml-9.2.10.v20150310.jar:$JHL/jetty-plus-9.2.10.v20150310.jar:$JHL/jetty-jndi-9.2.10.v20150310.jar:$JHL/jsp/javax.servlet.jsp-2.3.2.jar:$JHL/jsp/javax.servlet.jsp-api-2.3.1.jar
java rfd.RfdWar
The server does launch correctly and definitely reads web.xml packaged in the war. But when I try accessing the URL I'm getting an error that my class, that's packaged with the war, is missing.
Is there anything else I need to do to tell jetty to honor the classes packaged in the war?
This command ...
context.setParentLoaderPriority(true);
Basically says that when the webapp is attempting to load a class, the server classpath is checked first, then the webapp's classpath.
So if you happen to have the same classes in both places, the server version will be used, ignoring the one on the webapp.
Set this to false to get honest servlet spec behavior, with all of the WebApp classloader isolation.
Also, this is wrong, in many different ways.
Resource jettyEnv = Resource.newSystemResource("jetty-env.xml");
XmlConfiguration conf = new XmlConfiguration(jettyEnv.getInputStream());
Object obj = conf.configure();
WebAppContext context = (WebAppContext)obj;
The proper way to get jetty-env.xml to be loaded is to use the establish the WebApp and ClassList Configuration that performs this function from within the appropriate classloader and thread scope.
See documentation at https://www.eclipse.org/jetty/documentation/current/jndi-embedded.html
And prior answer at Can't get jetty to read jetty-env.xml

How to access EJB services from a grails standalone client

I've been having problems to access to my EJB services from a standalone client i've developed on grails 2.0.3. The EJB services are deployed on a glassfish server (Java). I tested this code on a netbeans tester class to access the EJBs:
Properties p = new Properties();
p.put("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory");
p.setProperty("java.naming.factory.url.pkgs", "com.sun.enterprise.naming");
p.setProperty("java.naming.factory.state", "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
p.setProperty("org.omg.CORBA.ORBInitialHost", INTEGRATION_IP);
p.setProperty("org.omg.CORBA.ORBInitialPort", CORBA_PORT);
ctx = new InitialContext(p);
try {
this.admAuth = (AdmAuthenticationRemote) this.ctx.lookup(Tester.AUTHENTICATION_SERVICE_JNDI);
}catch(Exception e){
...
}
This Tester.AUTHENTICATION_SERVICE_JNDI is a variable tha contains the path to the deployed service, in this case something like "java:global/..." that represents the address to the service that is being requested. This way of accessing the services works perfectly from the tester, but when i try to do the same from grails doesn't works. I am able to create the context the same way, but when i invoke the ctx.lookup() call i get an exception:
Message: Lookup failed for 'java:global/...' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory,
java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming}
Cause: javax.naming.NamingException: Unable to acquire SerialContextProvider for SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory,
java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming}
[Root exception is java.lang.RuntimeException: Orb initialization erorr]
The main exception is a naming exception, which means that it failed in the ctx.lookup(), but the cause is the orb initialization exception, which has another exception stack:
java.lang.RuntimeException: Orb initialization erorr
Caused by: java.lang.RuntimeException: java.lang.IllegalArgumentException: Can not set long field com.sun.corba.ee.impl.orb.ORBDataParserImpl.waitForResponseTimeout to java.lang.Integer
Caused by: java.lang.IllegalArgumentException: Can not set long field com.sun.corba.ee.impl.orb.ORBDataParserImpl.waitForResponseTimeout to java.lang.Integer
I'm really lost here. I've been having a lot of problems to get this going on grails, I had to get all glassfish jars (libs and modules) so it could make the InitialContext() call, but now i'm not sure if this is still a jar problem or a configuration problem or what it is.
I know that IllegalArgumentException occurs when u try to assign incompatible types in java, but i'm not setting anything like that, so i assume its an internal method initialization.
So the question is why is this exception coming up??
Is there another way to invoke my services from grails that works better??
The error is that you're trying to run your web application using the tomcat plugin in grails (using the command grails run-app). The problem is that when you try to create the InitialContext (com.sun.enterprise.naming.SerialInitContextFactory) groovy gives you an error casting some types if you're using the client libraries for GF 3.1. (I know that this is the problem, but I really don't know the reason for this. Because in theory this should work)
If you generate the .war file and you deploy in an AppServer, you can connect to your EJBs without problems. And if you deploy it on another GF server you don't have to import any of the client jars.
This will work perfect on production, the only problem is that you must compile and deploy your app on the GF server with every little change, and this is a bit annoying in development.
If you want to work outside of GF and using the command "grails run-app", you must modify two of the .jar GF 3.1 on your remote server, where you have the grails application:
1- The jar file $GLASSFISH_HOME/modules/glassfish-corba-omgapi.jar
You should search in the web the class com.sun.corba.ee.spi.orb.ParserImplBase, and modify this part
Field field = getAnyField(name);
field.setAccessible(true);
field.set(ParserImplBase.this, value);
for this
if (name.equalsIgnoreCase("waitForResponseTimeout")) {
Object newValue = new Long(1800000);
Field field = getAnyField(name);
field.setAccessible(true);
field.set(ParserImplBase.this, newValue);
} else {
Field field = getAnyField(name);
field.setAccessible(true);
field.set(ParserImplBase.this, value);
}
this should resolve the java.lang.IllegalArgumentException
2- The jar file $GLASSFISH_HOME/modules/glassfish-corba-orb.jar
you must delete the javax.rmi.CORBA.PortableRemoteObjectClass class of this library, because this class have conflicts with one used by the grails plugin
PS:
If you do not want to have the GF client jars in your grails application, you can add to the classpath of your client machine the following libraries
$GLASSFISH_HOME/modules/ejb-container.jar
$GLASSFISH_HOME/modules/ejb.security.jar
$GLASSFISH_HOME/modules/management-api.jar
If you use the grails console with the grails run-app command, must modify the configuration file $GRAILS_HOME/conf/groovy-starter.conf whit this
load $GLASSFISH_HOME/modules/ejb-container.jar
load $GLASSFISH_HOME/modules/ejb.security.jar
load $GLASSFISH_HOME/modules/management-api.jar

Implicity usage of Java Custom class loaders?

I've written some customer class loader that load some classes from a certain directory (that is not in the classpath), say:
class FileSystemClassLoader extends Classloader{
// implementation details
}
I have some directory say /home/mhewedy/classes/ that is not in the classpath, this directory contains some classes that I use the previous classlaoder to load.
how to use this classloader from the my code to load classes "simplicity" without writing : such code:
Thread.currentThread().setContextClassLoader(new FileSystemClassLoader());
// some code here ...
ClassLoader contextCL = Thread.currentThread().getcontextClassLoader();
Update to respond to OP edits:
When the JVM loads a class, it will use the classloader that loaded the "current" class (per JVM spec). So if you're in method Foo.main(), which was loaded with your custom classloader, and you want to create an instance of Bar, also loaded via that classloader, you don't have to do anything special.
However, if your current method is Baz.main(), and it was loaded via the system classpath (specified with -cp on the command line), then you have to explicitly load that class via the classloader. There's no way around this. The "context classloader" is meant for application code, to load resources; the JVM ignores it.
In almost all cases, you're better off constructing a classpath that includes your special classes.