I have a problem with my web module classpath in Websphere v6.1.
In my WEB-INF/lib I have a largish number of jar files which include xercesImpl.jar and xmlparserv2.jar. I need both jars to be present, but they appear to confict with each other. Specifically, each jar contains a META-INF/services directory so, when we try to get an instance of a DocumentBuilderFactory via JAXP, which instance we get depends upon the order in which these two jars appear in the classpath.
I always want to use the xerces instance of the DocumentBuildFactory, so I want to push xercesImpl.jar to the front of the classpath. I've tried to do this by specifying a Class-Path section in the Manifest file for the war file, but the class path that I actually get in my WAS Module Compound CLass Loader in is very strange. I seem to get some standard stuff that WAS puts on, followed by the contents of WEB-INF lib in alphabetical order, followed by the classpath specified by the Manifest file.
If I don't put a manifest file into the war at all, I get the standard stuff followed by the contents of WEB-INF/lib but in an arbitrary order.
What am I missing? Is there a way in which I can set the class path up to be exactly what I want?
Dave
I assume by WebSphere, you mean the regular J2EE Application Server (and not something like Community Edition; WebSphere is a brand name applied to a number of IBM products).
I think your options are limited. Since the dependencies look quite explicit, I would prefer a programmatic approach rather than relying on the vagaries of the classpath (like creating factory instances explicitly rather than relying on the SPI).
If that isn't an option, you might want to look at making one of your dependencies an EAR project utility JAR and configure MODULE classloading with a PARENT_LAST classloading policy on the WAR. This can be configured via the browser admin console (or via the RAD tooling if you use it).
Another thing I'd look at is the WAS Shared Libraries feature (under Environment in the browser admin console). These can be associated with servers or applications. The downside is that this requires more configuration.
In IBM Websphere Application Server 6.1, web modules have their own class loaders that are usually used in the PARENT_FIRST mode. This means that the web module class loaders attempt to delegate class loading to the parent class loaders, before loading any new classes.
If you wish to have the Xerces classes loaded before the XML parser v2 (I'm assuming Oracle XML v2 parser) classes, then the Xerces classes will have to be loaded by a parent class loader - in this case, preferably the application class loader. This can be done by placing the Xerces jar in the root of the EAR file (if you have one) or prepare the EAR file with xerces.jar and your WAR file in the root. The xmlparserv2 jar should then be placed in WEB-INF\lib.
You could also attempt creating an Xerces shared library for usage by your application.
You can find more information about this in the IBM WebSphere Application Server V6.1: System Management and Configuration. Details are available in Chapter 12.
How JAXP Chooses Parsers
You may be wondering which parser this program actually uses. JAXP, after all, is reasonably parser-independent. The answer depends on which parsers are installed in your class path and how certain system properties are set. The default is to use the class named by the javax.xml.parsers.DocumentBuilderFactory system property. For example, if you want to make sure that Xerces is used to parse documents, then you would run JAXPChecker like this:
D:\books\XMLJAVA>java -Djavax.xml.parsers.DocumentBuilderFactory=org.apache.xerces.jaxp.DocumentBuilderFactoryImpl JAXPChecker file:///D:/books/xmljava/dom.xml
> file:///D:/books/xmljava/dom.xml is well-formed.
If the javax.xml.parsers.DocumentBuilderFactory property is not set, then JAXP looks in the lib/jaxp.properties properties file in the JRE directory to determine a default value for the javax.xml.parsers.DocumentBuilderFactory system property. If you want to consistently use a certain DOM parser, for instance gnu.xml.dom.JAXPFactory, place the following line in that file:
javax.xml.parsers.DocumentBuilderFactory=gnu.xml.dom.JAXPFactory
If this fails to locate a parser, next JAXP looks for a META-INF/services/javax.xml.parsers.DocumentBuilderFactory file in all JAR files available to the runtime to find the name of the concrete DocumentBuilderFactory subclass.
Finally, if that fails, then DocumentBuilderFactory.newInstance() returns a default class, generally the parser from the vendor who also provided the JAXP classes. For example, the JDK JAXP classes pick org.apache.crimson.jaxp.DocumentBuilderFactoryImpl by default but the Ælfred JAXP classes pick gnu.xml.dom.JAXPFactory instead.
You could also try setting system property to prefer an implementation.
e.g. to prefer xmlparserv2 dom parser, set
javax.xml.parsers.DocumentBuilderFactory=oracle.xml.jaxp.JXDocumentBuilderFactory
Related
I was searching about this with many sources from the internet. But still I couldn't find a specific resource which exactly addresses my question.
In tomcat, is there any order in classes are loaded at startup. Just imagine a situation like this.
I have myApp.war file inside webapps. And inside that war, I have some library (say mylib-2.5.jar bundled inside it). And imagine, I have also placed the same library in different version (say mylib-2.8.jar) inside the /lib folder.
So when I start up my application, and call a particular end point, which lib (version) will have the chance to be loaded (on demand) into JVM by a class loader?
And what are the chances for a lib conflict? and what are the reasons for that?
From link posted by #GyroGearless
Therefore, from the perspective of a web application, class or resource loading looks in the following repositories, in this order:
•Bootstrap classes of your JVM
•/WEB-INF/classes of your web application
•/WEB-INF/lib/*.jar of your web application
•System class loader classes (described above)
•Common class loader classes (described above)
If the web application class loader is configured with <Loader delegate="true"/> then the order becomes:
•Bootstrap classes of your JVM
•System class loader classes (described above)
•Common class loader classes (described above)
•/WEB-INF/classes of your web application
•/WEB-INF/lib/*.jar of your web application
If classloader needs to load class X then once it finds it in one place it will not look for it in any other places.
Lib conflict is possible if you place one version of your dependency (say MySQL driver) to $JAVA_HOME/jre/lib/ext and another one into /WEB-INF/lib
Today I was asked in an interview, what will happen at the time of deployment if the Tomcat's lib and your WEB-INF/lib of the war file contains same jar file?
I tested today in my machine, I didn't found any difference. Application is deploying successfully.
I have gone through with this similar article , For, more clarification if anyone is having idea about what will happen if the Tomcat's lib and WEB-INF/lib contains same jar what will happen ??
the jar contained in your WEB-INF/lib will be picked up by tomcat. The only caveat is core container jar's will be loaded in preference to jar's in WEB-INF/lib.
read : https://tomcat.apache.org/tomcat-8.0-doc/class-loader-howto.html#Class_Loader_Definitions
Depends on delegate attribute
I haven't tried any of this. But it seems to hinge on value of the boolean delegate attribute.
And the way I read https://tomcat.apache.org/tomcat-10.0-doc/class-loader-howto.html#Class_Loader_Definitions is this:
For any webapp there are FOUR class loaders: bootstrap, system, common, webapp.
By default the boolean delegate attribute is not specified and will default to false
=> order of class loaders: bootstrap, webapp, system, common
=> Your webapp's JAR wins.
If, and only if, you explicitly specify <Loader delegate="true"/>
=> order of class loaders: bootstrap, system, common, webapp
=> common takes JARs from $CATALINA_BASE and $CATALINA_HOME
=> Tomcat's JAR wins.
Further reading
Added info: This here is the documentation for the "delegate" attribute itself.
I find this slightly confusing, but it seems that Tomcat's default is to NOT follow Java's default. (Not sure wherever Java's default "delegation model" may have been defined.)
Quote from https://tomcat.apache.org/tomcat-10.0-doc/config/loader.html#Common_Attributes
(Formatting changed for emphasis.)
Set to true if you want the class loader to follow the standard Java2 delegation model, and attempt to load classes from parent class
loaders before looking inside the web application.
Set to false (the default) to have the class loader look inside the web application first, before asking parent class loaders to find
requested classes or resources.
In one of my projects I have resources stored in /src/test/resources (typical maven directory structure). Those resources are being used by an utility class stored in the project.
The utility class itself is being used from other projects (other projects depend on this one). I would access the resource like that:
final InputStream inputStreamDobs =
ClassLoader.class.getResourceAsStream("/dbunit/clear_db.xml");
but since I use it from different projects the path is not correct - it is relative to current project that is being built/tested, not the one where utility class and resources are.
Any thought how to approach this?
I need to avoid absolute paths - would like to have a way of defining relative path to the utility class.
I also don't want to replicate resources over multiple projects. Cheers.
EDIT:
To give a context I have a definition of tables in XML file that needs to be cleared after Integration Tests (clear whole DB schema). Integration Tests sits in multiple project, but the clear script and resource file is the same for all of them and sits in common parent project.
EDIT2:
Bonus question: I would like to access common DTD file (let's call it tables.dtd) that need to be accessed from XML files from multiple other projects. (it will sit in common parent project).
Currently I have it duplicated over multiple project, and I refer to it from XML using directive:
<!DOCTYPE dataset SYSTEM "src/test/resources/dbunit/dobs.dtd">
How to point it to a file in different project?
You wrote
... but since I use it from different projects the path is not correct - it is relative to current project that is being built/tested, not the one where utility class and resources are
...
Relative paths are not the problem here. You use an absolute path in your example, but even if you would use a relative one, this would refer to the package or directory structure. getResourceAsStream would pick them up as long as the classpath is correct. The real problem is that you are referring to test resources in another project. But test resources and classes are not contained in the project artifact, so they are not accessible from modules that include this as a dependency. If you need these resources for tests in several projects, I would suggest that you create a new project (let's say "projectxyz-testresources") with these resouces contained in src/main/resources and add this as a dependency with scope "test" where relevant.
EDITED TO ADD:
If you don't want to use a separate project for test resources, you can create a test-jar containing test classes and resources using goal jar:test-jar and include this as a test dependency. You may want to configure the jar plugin in your pom to execute this goal on regular builds.
Your runtime classpath shouldn't reference src/test/resources. Maven will copy everything over to target so you should be able to get it with "/dbunit/clear_db.xml"
Have you tried using "classpath:" prefix? You shouldn't have to specify full paths to resources if they are available on the classpath. For example:
<mvc:resources location="classpath:/META-INF/web-resources/" mapping="/resources/**" />
/META-INF/web-resources/ comes from Spring MVC's JAR which is one of the project's dependencies. The project doesn't need to know how to get to that resource "directly" instead it uses the classpath.
I think you can use 2 below plugins for this purpose.
if your project is web project, you can create 2 web projects, one of them contains config files and another project is your main project, now on you can overlay projects with maven-war-plugin
There are many types for overlay, you can visit this page for more information
maven-war-plugin overlay
for jar files you can merge them to single one with maven-assembly-plugin
maven-assembly-plugin
We had a similar instance in which, we had some configuration files that were used across multiple modules in big multi module maven project.
So what we did was split the conf files into a separate module, that just jars up the config files.
And then whatever module needed those files could declare the dependency to the config files modules and just use the jar files with the config files and unzip them to use them.
You could do something similar for the test resources. Create a module with just the resources and then put them into the relevant path.
In this case, I would suggest to program a maven plugin for this task, so that this so variable path may be configured via properties.
You will also benefit from the Project object.
/**
* Location of the file.
*/
#Parameter(defaultValue = "${basedir}/src/main/java", property = "sourceFolder", required = true)
private File sourceFolder;
#Parameter(defaultValue = "${basedir}/src/test/java", property = "testFolder", required = true)
private File testFolder;
#Parameter(defaultValue = "${project}", property = "project", readonly = true, required = true)
private MavenProject project;
Can you try using Maven Overlays? We had faced similar situation in the past, and very much resolved using overlays. Usually, overlays are used to share common resources across multiple web applications.
Maybe one of these approaches:
Either: You outsource the xml files AND the java classes (like the utility class) that need access to them into a seperate library which you can then include into your several other projects (conveniently as maven dependencies).
Or: You put these xml files into a seperate VCS-tree or repository and you include them in your project tree (e.g. as an "external" in SVN). So you can update this reference seperately in your projects, but you only have to maintain one source file.
I've created a web service client using Axis2. I would like to package the client into a jar, so I can use it in several other projects. The client uses the Axis2 WS-Security module 'rampart'. This module, rampart.mar (not a typo!) has to be present on the Axis 'repository path', in a directory called 'modules'. The client also requires a security policy file, policy.xml. The locations of these last two are injected via Spring, but as they are not subject to change, I would like to package them into the jar.
If you inject a File object like:
<bean id="webserviceStubFactory" class="com.company.WebserviceStubFactory">
<constructor-arg value="classpath:policy.xml"/>
</bean>
it will work just fine when running/testing the project directly. However, when you package it into a jar, you get
java.io.FileNotFoundException: class path resource [policy.xml] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/path/to/webservice-0.8.jar!/policy.xml
This is a well known Spring 'problem': the constructor-arg is resolved into a Spring ClasspathResource instance and it doesn't support getFile(), because File instances cannot refer to something inside a jar. The solution to this is pretty simple: change the constructor to take a Resource instead of a file and use the InputStream directly. However, this doesn't work for the Axis2 repository path, as I can only specify the full path to the repository and the Axis2 internals figure out where the rampart.mar is located.
So, the question basically boils down to: is it possible to use Spring to inject a path inside a jar (even if it's only /) and have other libraries read from that path as if it were a regular filesystem? I'm guessing it isn't, but I would like to be sure, before installing external 'axis repositories' on the dev/test/production environments and having several copies of the rampart.mar lying around.
There's only so much that Spring can do to hide the inconsistencies of the underlying JavaSE API. The various getXYZ methods on the Resource interface come with caveats in the documentation, e.g. for getFile():
Throws:
IOException - if the resource cannot be resolved as absolute file path,
i.e. if the resource is not available in a file system
A resource inside a JAR is not "on a filesystem", and so this will never work.
In your case you're going to have to work around Axis2's requirement to operate on files, but manually making sure a file exists. In other words, use Resource.getInputStream() to extract the content of the JAR resource and copy it to a temporary File on the local filesystem, then pass that File to Axis2.
In Java, you often see a META-INF folder containing some meta files. What is the purpose of this folder and what can I put there?
From the official JAR File Specification (link goes to the Java 7 version, but the text hasn't changed since at least v1.3):
The META-INF directory
The following files/directories in the META-INF directory are recognized and interpreted by the Java 2 Platform to configure applications, extensions, class loaders and services:
MANIFEST.MF
The manifest file that is used to define extension and package related data.
INDEX.LIST
This file is generated by the new "-i" option of the jar tool, which contains location information for packages defined in an application or extension. It is part of the JarIndex implementation and used by class loaders to speed up their class loading process.
x.SF
The signature file for the JAR file. 'x' stands for the base file name.
x.DSA
The signature block file associated with the signature file with the same base file name. This file stores the digital signature of the corresponding signature file.
services/
This directory stores all the service provider configuration files.
New since Java 9 implementing JEP 238 are multi-release JARs. One will see a sub folder versions. This is a feature which allows to package classes which are meant for different Java version in one jar.
Generally speaking, you should not put anything into META-INF yourself. Instead, you should rely upon whatever you use to package up your JAR. This is one of the areas where I think Ant really excels: specifying JAR file manifest attributes. It's very easy to say something like:
<jar ...>
<manifest>
<attribute name="Main-Class" value="MyApplication"/>
</manifest>
</jar>
At least, I think that's easy... :-)
The point is that META-INF should be considered an internal Java meta directory. Don't mess with it! Any files you want to include with your JAR should be placed in some other sub-directory or at the root of the JAR itself.
I've noticed that some Java libraries have started using META-INF as a directory in which to include configuration files that should be packaged and included in the CLASSPATH along with JARs. For example, Spring allows you to import XML Files that are on the classpath using:
<import resource="classpath:/META-INF/cxf/cxf.xml" />
<import resource="classpath:/META-INF/cxf/cxf-extensions-*.xml" />
In this example, I'm quoting straight out of the Apache CXF User Guide. On a project I worked on in which we had to allow multiple levels of configuration via Spring, we followed this convention and put our configuration files in META-INF.
When I reflect on this decision, I don't know what exactly would be wrong with simply including the configuration files in a specific Java package, rather than in META-INF. But it seems to be an emerging de facto standard; either that, or an emerging anti-pattern :-)
The META-INF folder is the home for the MANIFEST.MF file. This file contains meta data about the contents of the JAR. For example, there is an entry called Main-Class that specifies the name of the Java class with the static main() for executable JAR files.
META-INF in Maven
In Maven the META-INF folder is understood because of the Standard Directory Layout, which by name convention package your project resources within JARs: any directories or files placed within the ${basedir}/src/main/resources directory are packaged into your JAR with the exact same structure starting at the base of the JAR.
The Folder ${basedir}/src/main/resources/META-INF usually contains .properties files while in the jar contains a generated MANIFEST.MF, pom.properties, the pom.xml, among other files. Also frameworks like Spring use classpath:/META-INF/resources/ to serve web resources.
For more information see How do I add resources to my Maven Project.
You can also place static resources in there.
In example:
META-INF/resources/button.jpg
and get them in web3.0-container via
http://localhost/myapp/button.jpg
> Read more
The /META-INF/MANIFEST.MF has a special meaning:
If you run a jar using java -jar myjar.jar org.myserver.MyMainClass you can move the main class definition into the jar so you can shrink the call into java -jar myjar.jar.
You can define Metainformations to packages if you use java.lang.Package.getPackage("org.myserver").getImplementationTitle().
You can reference digital certificates you like to use in Applet/Webstart mode.
Adding to the information here, the META-INF is a special folder which the ClassLoader treats differently from other folders in the jar.
Elements nested inside the META-INF folder are not mixed with the elements outside of it.
Think of it like another root. From the Enumerator<URL> ClassLoader#getSystemResources(String path) method et al perspective:
When the given path starts with "META-INF", the method searches for resources that are nested inside the META-INF folders of all the jars in the class path.
When the given path doesn't start with "META-INF", the method searches for resources in all the other folders (outside the META-INF) of all the jars and directories in the class path.
If you know about another folder name that the getSystemResources method treats specially, please comment about it.
Just to add to the information here, in case of a WAR file, the META-INF/MANIFEST.MF file provides the developer a facility to initiate a deploy time check by the container which ensures that the container can find all the classes your application depends on. This ensures that in case you missed a JAR, you don't have to wait till your application blows at runtime to realize that it's missing.
I have been thinking about this issue recently. There really doesn't seem to be any restriction on use of META-INF. There are certain strictures, of course, about the necessity of putting the manifest there, but there don't appear to be any prohibitions about putting other stuff there.
Why is this the case?
The cxf case may be legit. Here's another place where this non-standard is recommended to get around a nasty bug in JBoss-ws that prevents server-side validation against the schema of a wsdl.
http://community.jboss.org/message/570377#570377
But there really don't seem to be any standards, any thou-shalt-nots. Usually these things are very rigorously defined, but for some reason, it seems there are no standards here. Odd. It seems like META-INF has become a catchall place for any needed configuration that can't easily be handled some other way.
If you're using JPA1, you might have to drop a persistence.xml file in there which specifies the name of a persistence-unit you might want to use. A persistence-unit provides a convenient way of specifying a set of metadata files, and classes, and jars that contain all classes to be persisted in a grouping.
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
// ...
EntityManagerFactory emf =
Persistence.createEntityManagerFactory(persistenceUnitName);
See more here:
http://www.datanucleus.org/products/datanucleus/jpa/emf.html
All answers are correct. Meta-inf has many purposes. In addition, here is an example about using tomcat container.
Go to
Tomcat Doc and check
" Standard Implementation > copyXML " attribute.
Description is below.
Set to true if you want a context XML descriptor embedded inside the application (located at /META-INF/context.xml) to be copied to the owning Host's xmlBase when the application is deployed. On subsequent starts, the copied context XML descriptor will be used in preference to any context XML descriptor embedded inside the application even if the descriptor embedded inside the application is more recent. The flag's value defaults to false. Note if the deployXML attribute of the owning Host is false or if the copyXML attribute of the owning Host is true, this attribute will have no effect.
You have MANIFEST.MF file inside your META-INF folder. You can define optional or external dependencies that you must have access to.
Example:
Consider you have deployed your app and your container(at run time) found out that your app requires a newer version of a library which is not inside lib folder, in that case if you have defined the optional newer version in MANIFEST.MF then your app will refer to dependency from there (and will not crash).
Source: Head First Jsp & Servlet
As an addition the META-INF folder is now also used for multi-release jars. This is a feature which allows to package classes which are meant for different Java version in one jar, e.g. include a class for Java 11 with new features offered by Java 11 in a jar also working for Java 8, where a different class for Java 8 with less features in contained. E.g this can be useful if a newer Java version is offering enhanced, different or new API methods which would not work in earlier version due to API violations. One will see a sub folder versions then.