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

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

Related

Jetty Server not Working for War with JSPs

I am trying to create a simple jetty server/container that will take a war file and deploy. This is not embedded jetty with spring-boot.
Here is my build.gradle dependencies:
dependencies {
def jettyVersion = "9.4.34.v20201102"
implementation "org.eclipse.jetty:jetty-server:$jettyVersion"
implementation "org.eclipse.jetty:jetty-security:$jettyVersion"
implementation "org.eclipse.jetty:jetty-servlet:$jettyVersion"
implementation "org.eclipse.jetty:jetty-webapp:$jettyVersion"
implementation "org.eclipse.jetty:jetty-annotations:$jettyVersion"
implementation "org.eclipse.jetty:jetty-jmx:$jettyVersion"
}
Here is my main class:
public static void main(String[] args) throws Exception {
Server server = new Server(8080);
MBeanContainer mbContainer = new MBeanContainer(getPlatformMBeanServer());
server.addBean(mbContainer);
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/");
webapp.setWar(warFile()); // LOGIC TO UPLOAD WAR FILE
webapp.setExtractWAR(true);
Configuration.ClassList classList = Configuration.ClassList.setServerDefault(server);
classList.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
"org.eclipse.jetty.annotations.AnnotationConfiguration");
webapp.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/[^/]*taglibs.*\\.jar$");
server.setHandler(webapp);
server.start();
server.dumpStdErr();
server.join();
}
However, when I try to go to the app (http://localhost:8080/index), I keep getting the following error message:
URI: /index
STATUS: 500
MESSAGE: JSP support not configured
SERVLET: jsp
There is only one line of error message in the console:
2020-12-11 09:49:51.563:INFO:oejshC.ROOT:qtp2025864991-33: No JSP support. Check that JSP jars are in lib/jsp and that the JSP option has been specified to start.jar
What JSP Jars that it is referring to? I am at a loss as to what dependencies I need to add to make it work for JSPs.
Thx.
You will have to add apache-jsp so that your server will support jsps. If your web app uses jstl, you should also add apache-jstl.
For WebAppContext usage (which is a bit easier to setup than ServletContextHandler usage) you'll need the following artifacts ...
https://search.maven.org/artifact/org.eclipse.jetty/apache-jsp (for the Jetty specific JettyJspServlet which extends from the Jasper JspServlet)
https://search.maven.org/artifact/org.eclipse.jetty/apache-jstl (to support Taglibs custom and standard)
Make sure your org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern can reference the apache-jsp artifact properly, otherwise the internal javax.servlet.ServletContextInitializer will not load properly.
If nothing happens by simply adding those artifacts, you'll need to verify your default descriptor setup on your WebAppContext.setDefaultsDescriptor(String) to ensure that you pass in a resource reference (path or uri) to the Jetty default descriptor XML.
https://github.com/eclipse/jetty.project/blob/jetty-9.4.35.v20201120/jetty-webapp/src/main/config/etc/webdefault.xml
Enabling JSP support in embedded mode can be quite tricky if you use the ServletContextHandler instead of the WebAppContext.
If you ever decide to use the ServletContextHandler instead of a WebAppContext (to have a single fat/uber jar, to speed up load/deploy time, to ease unit testing, etc...), then check out the Jetty maintained example project at ...
https://github.com/jetty-project/embedded-jetty-jsp

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 bring SOAP capability to payara/micro in EJB project

I have an EJB project providing webservices (both SOAP and REST) running inside a container with payara/micro as base image, since payara/micro does not come with JAXWS(SOAP support) feature out of the box, however, by adding
cxf-rt-frontend-jaxws
and
cxf-rt-transports-http
as dependencies into the project as well as following this tutorial and put the following code instead:
#Override
public void loadBus(ServletConfig servletConfig) {
super.loadBus(servletConfig);
Bus bus = getBus();
BusFactory.setDefaultBus(bus);
Endpoint.publish("/MySoapService", new ASoapService());
}
I was able to make the SOAP interface almost available (wsdl information is publicly available already), and
http://localhost:8080/<my project name>/services
event listed out the available services as well their available methods and endpoints/WSDL/Target namespace information.
But when trying to access the SOAP service via SOAP client, I got on the server side errors with the following line of info:
...
Caused by: java.lang.NullPointerException: null
at com.example.ASoapService.getXxx
...
Where
ASoapService
Is Actually an EJB. So I tried instead to replace the above code with the following:
#EJB
ASoapService aSoapService
...
Endpoint.publish("/MySoapService", aSoapService);
During startup of container, I got
Caused by: javax.naming.NameNotFoundException: com.example.ASoapServiceF#com.example.ASoapService not found
By checking the logs, I found a possible reason:
When SOAP part starts up with the following code
Endpoint.publish("/MySoapService", aSoapService);
The EJB Container is not yet ready and thus the lookup of
ASoapService
failed, is such assumption correct? Because normally you should see something like:
[2018-02-02T14:43:57.821+0000] [] [INFO] [AS-EJB-00054] [javax.enterprise.ejb.container] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1517582637821] [levelValue: 800] Portable JNDI names for EJB ASoapService: [java:global/<my project name>/ASoapService, java:global/<my project name>/ASoapService!com.example.ASoapService]
during start up, which is not the case for my situation.
I am relatively new to EJB and Glassfish world, can I somehow force EJB container to start first? Or does it actually have anything to do with the starting sequence? How to combine the two together?
Thanks in advance.
You shouldn't be trying to force EJB container to start. Instead, try one of the following:
instead of #EJB ASoapService aSoapService to inject the EJB try #Inject
ASoapService aSoapService - #Inject should wait for the dependencies therefore wait until the EJB is available
run the method Endpoint.publish from an object which is initialized after EJB container is ready, either from a startup singleton EJB or when CDI application scope is initialized: https://rmannibucau.wordpress.com/2015/03/10/cdi-and-startup/

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

Weblogic 11 G : Altering default class loading

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()));