Web application hosted in OpenLiberty cannot find classes through system class loader - open-liberty

I have hosted a web application in open liberty and I am trying to class load some third party java classes which are in a jar. I added the folder as a library which contain the jar file and added that library as a class loader. but i am getting a class not found exception when i try to load it.
Also when I use URLClassLoader it works perfectly fine. But i want to change the URLClassLoader to System ClassLoader
My server.xml contains below lines.
<application location="${application.name}"
type="war"
id="${application.name}"
name="${application.name}" context-root="<URL>">
<classloader apiTypeVisibility="spec, ibm-api, api, stable, third-party" commonLibraryRef="Lib"/>
</application>
<library id="Lib" apiTypeVisibility="spec, ibm-api, api, stable, third-party">
<folder dir="${wlp.install.dir}/../custom-java/" />
</library>
Any help regarding this highly appreciated.

If you have a jar file, you need to use <file> or <fileset> instead of <folder>.
For a single jar:
<library id="Lib" apiTypeVisibility="spec, ibm-api, api, stable, third-party">
<file name="${wlp.install.dir}/../custom-java/myjar.jar" />
</library>
For a directory with multiple jars:
<library id="Lib" apiTypeVisibility="spec, ibm-api, api, stable, third-party">
<fileset dir="${wlp.install.dir}/../custom-java/" includes="*.jar" scanInterval="5s" />
</library>
I believe <folder> is only used when you have a folder of files you want to load with Class.getResource(), or if you have a directory structure of .class files which aren't in a jar.
For more details, see the Knowledge Center
Update: When you've added a library to your application like this, you should be able to access the classes in the library just like you access classes in your application.
For example, these should work:
new MyLibraryObject()
Class.forName("com.example.MyLibraryObject")
Thread.currentThread().getContextClassLoader().loadClass("com.example.MyLibraryObject")
However, using the system classloader specifically still won't work.
In OpenLiberty, the system classloader loads a minimal set of classes. Liberty internals are loaded using OSGi which has its own set of classloaders and application classes are loaded by a special application classloader which can load the application classes, API classes and shared libraries, but doesn't have access to load any liberty internal classes.

After lot of fiddling around came up with the answer.
The problem was how I defined the class loader. I changed my class loader to use the Application class loader (this is what mentioned in the Azquelt reply) instead of the the system class loader.
also just adding a library path was enough. no need to specify in the class loader in the server.xml
thank you for your input #Azquelt

Related

Binding datasource to application when using springBootApplication in Liberty?

When deploying "regular" web apps to Liberty, I was used to binding the global datasource configured in Liberty's server.xml to the individual application by using a child element within the element, like this:
<application context-root="helloApp" location="..." name="helloApp" type="war">
<application-bnd>
<data-source id="db2appDs" name="jdbc/datasource" binding-name="jdbc/theDB"/>
</application-bnd>
...
</application>
<dataSource id="db2ds" jndiName="jdbc/theDB" type="javax.sql.DataSource">
...
</dataSource>
When configuring my first Spring Boot application to deploy to Liberty, I am trying to use the new <springBootApplication> element for it - but I don't seem to be able to add a binding for the datasource I want to use the same way, as this element doesn't seem to support such a child. (It seems to want only <classloader> as a child).
I've seen people suggest I use an #Resource annotation that includes both application-local JDNI name and global JNDI name for the datasorce - but that defeats the purpose, since I don't want to know what the global name is until deploy time.
Is there another way to do this, like we used to before? Or are applications deployed through <springBootApplication> expected to know the global JNDI name of the datasource(s) they want?
Application-defined datasources are not supported for <springBootApplication/>’s. While your application may certainly access a Liberty datasource using its global JNDI name, you should configure the spring.datasource.jndi-name property within your Spring Boot application as described in section 29.1.3 of the Spring Boot features reference. For your example try spring.datasource.jndi-name=jdbc/theDB.

IBM Liberty where to place properties file required by multiple applications

-Multiple spring boot apps are deployed to IBM liberty 20x
All the Spring boot app should access properties from multiple properties file.
Acording to the reference https://www.ibm.com/support/knowledgecenter/SSEQTP_liberty/com.ibm.websphere.wlp.doc/ae/cwlp_sharedlibrary.html
tried below configuration in server.xml by creating folder "customProps" at "wlp\usr\servers\controller1"
<library id="allpropeties">
<fileset dir="${server.config.dir}/customProps" includes="*.properties" />
</library>
But gets the below error as applicaiton not able to locate the properties file:
java.io.FileNotFoundException: class path resource [test.properties] cannot be opened because it does not exist
Where to keep multiple common properties files and what configuration has to be added to server.xml
As a simple answer you could try copying the properties file to the default global shared library location:
${server.config.dir}/lib/global
You could use this without additional server config, and/or read through some of the doc for additional configuration considerations.

JPA2 in liberty 18.0.0.3 using MySQL database

I'm new to JPA and Liberty. Could anyone please explain how to relate/link the server.xml, web.xml and persistence.xml configuration to set up the database connection?
your help on this is much appreciated.
In Liberty, you define the location of the JDBC driver jar files and configure a dataSource element with a JNDI name. This knowledge center page contains an example for MySQL,
https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.wlp.doc/ae/twlp_dep_configuring_ds.html
Directly quoting from the above page,
<dataSource id="DefaultDataSource" jndiName="jdbc/mySQL">
<jdbcDriver libraryRef="MySQLLib"/>
<properties databaseName="SAMPLEDB" serverName="localhost" portNumber="3306"/>
</dataSource>
<library id="MySQLLib">
<file name="C:/mysql-connector-java-x.x.xx/mysql-connector-java-x.x.xx.jar"/>
</library>
After this, you can configure the jta-data-source element in your persistence.xml pointing at the JNDI name that you chose. For example,
...
<persistence-unit name="ExamplePersistenceUnit">
<jta-data-source>jdbc/mySQL</jta-data-source>
</persistence-unit>
The above is sufficient to get it working, without involving web.xml.
The deployment descriptor (web.xml) gives you the option of adding a level of indirection/mapping and the ability to configure some additional settings such as shareability and container vs application authentication. You can do this by defining a resource reference in web.xml pointing to the data source. Resource references have names in java:comp/env, java:module/env, java:app/env or java:global/env that reflect their visibility. I'll use java:module in the following example, meaning that the reference we are defining is only visibility within the same module (the web module that provides the web.xml),
<resource-ref>
<res-ref-name>java:module/env/jdbc/mySQLRef</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
<lookup-name>jdbc/mySQL</lookup-name>
</resource-ref>
After defining the resource reference above, the data source continues to be available at the JNDI name specified in server.xml, but also becomes available via the JNDI name of the resource reference, meaning you could alternately specify,
<jta-data-source>java:module/env/jdbc/mySQLRef</jta-data-source>
Deployment descriptors can also do some more advanced things like defining a data source in place of the server config. However, to keep this answer simple, I've skipped over that possibility.
This IBM KnowledgeCenter topic is a good place to start

.ClassCastException: org.apache.xerces.jaxp.DocumentBuilderFactoryImpl cannot be cast to javax.xml.parsers.DocumentBuilderFactory

I am upgrading Weblogic server from 9 to 10.3.6. when I am trying to deploy my ear application and got below exception.
Caused By: java.lang.ClassCastException: org.apache.xerces.jaxp.DocumentBuilderFactoryImpl cannot be cast to javax.xml.parsers.DocumentBuilderFactory
at javax.xml.parsers.DocumentBuilderFactory.newInstance(DocumentBuilderFactory.java:123)
at org.springframework.beans.factory.xml.DefaultDocumentLoader.createDocumentBuilderFactory(DefaultDocumentLoader.java:89)
at org.springframework.beans.factory.xml.DefaultDocumentLoader.loadDocument(DefaultDocumentLoader.java:70)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:396)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:342)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:310)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:143)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:178)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:149)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:212)
at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:113)
at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:80)
at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:123)
at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:423)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:353)
at org.springframework.context.access.ContextSingletonBeanFactoryLocator.initializeDefinition(ContextSingletonBeanFactoryLocator.java:141)
at org.springframework.beans.factory.access.SingletonBeanFactoryLocator.useBeanFactory(SingletonBeanFactoryLocator.java:384)
at org.springframework.web.context.ContextLoader.loadParentContext(ContextLoader.java:341)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:195)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:45)
at weblogic.servlet.internal.EventsManager$FireContextListenerAction.run(EventsManager.java:481)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
at weblogic.servlet.internal.EventsManager.notifyContextCreatedEvent(EventsManager.java:181)
at weblogic.servlet.internal.WebAppServletContext.preloadResources(WebAppServletContext.java:1868)
I tried all sorts for things including adding a weblogic-application.xml but it still does not work.
<?xml version="1.0" encoding="UTF-8"?>
<weblogic-application>
<xml>
<parser-factory>
<saxparser-factory>
org.apache.xerces.jaxp.SAXParserFactoryImpl
</saxparser-factory>
<document-builder-factory>
org.apache.xerces.jaxp.DocumentBuilderFactoryImpl
</document-builder-factory>
<transformer-factory>
org.apache.xalan.processor.TransformerFactoryImpl
</transformer-factory>
</parser-factory>
</xml>
<prefer-application-packages>
<package-name>org.apache.xerces.parsers.*</package-name>
</prefer-application-packages>
</weblogic-application>
my weblogic.xml has
<prefer-web-inf-classes>true</prefer-web-inf-classes>
This is part of my pom.xml:
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>2.8.1</version>
<scope>runtime</scope>
</dependency>
Please help. Thanks!
I answer my own question:
Below link inspired me of fixing this issue:
Dealing with "Xerces hell" in Java/Maven?
Basiclly I have removed all the dependencies of xml-api and xmlParserAPIs in pom.xml. The problem is fixed. The root cause is my classpath should not include any javax libraries which cause the library conflict with Weblogic app server. Hope it helps.
I had the similar problem. I was using an application installed on wildly server. The problem was that I have to place xerces jars in both framework's and third party lib folder of the application. After much research, I found the solution in the documentation of xerces.
Why do I get a ClassCastException when I use Xerces and WebSphere Application Server?
Xerces uses the ObjectFactory class to load some classes dynamically, e.g. the parser configuration. The ObjectFactory finds the specified implementation class by querying the system property, reading META-INF/services/factoryId file or using a fallback classname. After the implementation is found, the ObjectFactory tries to load the file using the context classloader and if it is null, the ObjectFactory uses the system classloader.
If you run Xerces in an environment, such as WebSphere® Application Server, that has multiple classloaders you may get ClassCastExceptions thrown from Xerces because different classloaders might get involved in loading Xerces classes. For example, ClassCastExceptions may occur when utility EAR classes that use Xerces load Xerces classes from WAR modules.
We suggest you read the "Avoiding ClassCastExceptions..." article which explains a workaround for this problem. Also you might want to read the "J2EE Class Loading Demystified" article that explains how multiple classloaders work in WebSphere Application Server.
"
Basically, use two util class to create domparser object. For the service call from your application, change the classloader and create the object. After doing the processing, revert back the classloader.
ClassLoader savedClassLoader = Thread.currentThread().getContextClassLoader();
ClassLoader currentClassLoader = this.getClass().getClassLoader() ;
Thread.currentThread().setContextClassLoader(currentClassLoader);
//do the processing, after that revert back
https://xerces.apache.org/xerces2-j/faq-general.html

Simple axis2.xml for Axis2 embedded in webapp

I am developing a webapp with an embedded webservice with Axis2 using Maven.
The service implementation is a POJO with RPC-style interaction, the target appserver is Tomcat running the Axis2 servlet.
The "Hello world" works but now I need to configure some global axis2 settings in the axis2.xml file (placed under WEB-INF/conf).
Please provide or point to a simple configuration for axis2.xml for this common environment.
The default taken from the binary distribution has too many features activated (hotdeploy?) and also causes this problem:
<soapenv:Reason>
<soapenv:Text xml:lang="en-US">
The ServiceClass object does not implement the required method
in the following form: OMElement ping(OMElement e)
</soapenv:Text>
</soapenv:Reason>
As a reference: http://axis.apache.org/axis2/java/core/docs/servlet-transport.html says to configure the servlet transport in this way, but it does not solve the issue.
<transportReceiver name="http" class="org.apache.axis2.transport.http.AxisServletListener"/>
Apparently the problem is that the default axis2.xml sets raw xml messageReceivers, instead of the RPC ones.
Try to add this to the services.xml for the developed service, should fix the problem.
<messageReceivers>
<messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only"
class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver" />
<messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out"
class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
</messageReceivers>
"Solution that worked for me was adding the operation tag in the service.xml against the Java Service method name:
<operation name="sayHello" >
<messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out" class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
</operation>
<parameter name="ServiceClass" locked="false">com.learning.webservices.pojo.HelloService</parameter>

Resources