How to load a resource from an embedded JAR File - java

I am trying to load a resource that is contained within an embedded JAR file. The project is actually deployed in JBoss using an EAR file with the following structure:
deploy.ear
|
|-> project.sar
|
|-> sub_project.jar
| |
| |-> settings.xml
|
|-> com/path/project/
|
|-> main.class
From main.java I'd like to get a InputStream for settings.xml. What is the correct way to do this?
My current understanding that the following code should work, but it is returning null:
this.getClass().getResourceAsStream("settings.xml");
Update
After some trial and error, the following statements work:
getClass().getResourceAsStream("/settings.xml");
getClass().getResourceAsStream("/sub_project.jar/settings.xml");
getClass().getClassLoader().getResourceAsStream("/settings.xml");
getClass().getClassLoader().getResourceAsStream("settings.xml");
getClass().getClassLoader().getResourceAsStream("sub_project.jar/settings.xml");
getClass().getClassLoader().getResourceAsStream("/sub_project.jar/settings.xml");

This might be a good resource: http://one-jar.sourceforge.net/version-0.95/
The main idea is that the inner JAR is not loaded by the ClassLoader that loaded the outer JAR automatically, you need to do so manually, e.g. by using a StreamClassLoader to load the inner jar
Only then, from your own ClassLoader you can get that resource using getResourceAsStream(...)

Related

{project.parent.basedir} taking of path sub module rather than Parent module path

I have following structure in project
| prj
| a1_module
|src
|pom
| a2_module
|src
|pom
| lib
xyz.jar
|pom(parent)
Now i register xyz.jar in sub module(a1_module) pom like this:
<dependency>
<groupId>com.asd.prj</groupId>
<artifactId>pubsub</artifactId>
<version>1.0.0.</version>
<scope>system</scope>
<systemPath>${project.parent.basedir}/lib/pubsub_2.11-1.0.0-SNAPSHOTjar</systemPath>
</dependency>
I expect ${project.parent.basedir}/lib/pubsub_2.11-1.0.0-SNAPSHOTjar should give me prj/lib/pubsub_2.11-1.0.0-SNAPSHOTjar but it gives me path like this prj/a1_module/lib/pubsub_2.11-1.0.0-SNAPSHOTjar.
Beacuse of this situtaion i get error as there is no jar kept in sub-module but its kept outside in "lib" directory of main project.
This question says that project.parent.basedir should give path of parent of that module path but in my case its giving me path of submodule rather parent module path.
Any suggestion that what i am doing wrong or what is other way to register my local jar in submodules.
You can use this:
<systemPath>${basedir}/../lib/pubsub_2.11-1.0.0-SNAPSHOTjar</systemPath>

Classloading issue in EAP 6.1 - JBoss 7.2 / WAR Classes don't see EAR classes

I have a strange kind of problem.
My application is simple structured like that: An EAR that contain web module (WAR).
I put my specific application jar into lib directory of the EAR, and then i refer it into MANIFEST of WAR module.
I have another jar in the lib directory of the WAR, this jar contains a servlet.
When i start the server and full publish my application all is fine, but in the runtime phase when i call the entry point of my application i obtain a ClassNotFound error about this servlet. (maybe the servlet uses a class contained in my application jar, which that is contained in EAR lib)
Instead, if i put the specific application jar into lib directory of the WAR togheter with the other jar (which one that contain the servlet) i don't obtain any kind of error (even at runtime).
But i need to maintain my application jar into lib directory of the EAR.
I don't have problems with other type of jar, maybe the problem in this case is related to the servlet? classloading isolation?don't know?:(
Any suggestions? What can i do?
I try multiple type of configuration about jboss-classloading.xml without success..
PS: With another type of application server like websphere i don't have any problem and i can maintain the jar into EAR lib directory.
Assumed that: Each class will use it's own classloader to load other classes. So if ClassA.class references ClassB.class then ClassB needs to be on the classpath of the classloader of ClassA, or it's parents.
If i add to manifest (of WAR) the classpath dependency about the jar into EAR/lib how is possible that the class into war doens't see class into EAR/lib?
I'am going crazy...missing another type of setting? Is there any security setting?
Stacktrace:
{java.lang.NoClassDefFoundError: it/myapp/services/servlets/Dispatcher}|
at it.myapp.services.contexts.ContextManager.configureSet(ContextManager.java:2972)}
at it.myapp.services.servlets.Dispatcher.getSession(Dispatcher.java:1344)}
at it.myapp.services.servlets.Dispatcher.service(Dispatcher.java:5139)}
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)}
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:295)}
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)}
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)}
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:149)}
at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:169)}
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:145)}
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:97)}
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:102)}
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:336)}
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:856)}
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:653)}
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:920)}
at java.lang.Thread.run(Thread.java:722)}
Caused by: java.lang.ClassNotFoundException: it.myapp.services.servlets.Dispatcher from [Module "deployment.MyEAR.ear:main" from Service Module Loader]}
at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:196)}
at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:444)}
at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:432)}
at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:374)}
at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:119)}
... 17 more}
the problem seems to be related to classloading visibility...it's very strange. :(
Dispatcher is a servlet-class packed in a jar into WAR/lib, this class call another class (ContextManager) that is contained into a jar in EAR/lib.
In the manifest of WAR/lib i have correctly added to classpath the jar into EAR/lib.
Sorry...Maybe the problem is the opposite, ie a class from EAR's jar seems cannot see servlet class into WAR...Is possible to remove this limitation? i don't want to put all the jar into war...
Thanks in advance.
IlPistolero.
In our project, we have got a structure like this (test.ear contains the two modules test.ejb.jar and test.web.war):
test.ear
+-- lib (contains 3rd party libs)
+-- META-INF
| +-- application.xml (lists modules test.web.war and test.ejb.jar)
| +-- MANIFEST.MF
+-- test.ejb.jar
| +-- META-INF
| | +- ejb-jar.xml
| +-- com (root package of all ejb .class files)
| +-- ...
+-- test.web.war
+-- META-INF
| +-- MANIFEST.MF (Class-Path: test.ejb.jar)
+-- WEB-INF
| +-- classes
| | +-- com (root package of all war .class files)
| | +-- ...
| +-- lib (3rd party libs only used by .war)
| +-- web.xml
+-- index.html
The classes of the .jar files inside test.ear/lib can be used by test.ejb.jar and test.web.war.

Spring Application Context can't load the configuration files

I got 2 projects. A plugin project containing some components (POJOs) and a fragment project containing the according unit and integration tests. I'm using Tycho to build these projects and I want to use Spring to bootstrap my integration tests.
I've annotated my test classes with
#ContextConfiguration(locations = { "classpath*:spring/*-config.xml" })
#RunWith(SpringJUnit4ClassRunner.class)
But when I try to build the projects with tycho (clean install) or run the test class as Plugin-Test within eclipse, Spring complains that there are no beans in the context defined. In the log I found the following lines:
DEBUG o.s.t.c.s.AbstractGenericContextLoader - Loading ApplicationContext for
locations [classpath*:spring/*-config.xml].
DEBUG o.s.b.f.xml.XmlBeanDefinitionReader - Loaded 0 bean definitions from
location pattern [classpath*:spring/*-config.xml]
I've put the configuration files under src/main/java/spring/ and src/main/resources/spring but spring can't find them. I've also tried to add these paths explicit to the bundle-classpath in the manifest.
When I change the configuration path to "file:spring/some-config.xml" spring is loading my bean definitions but crashes when it tries to load the "context" schema with the following output:
Configuration problem: Unable to locate Spring NamespaceHandler for XML schema
namespace [http://www.springframework.org/schema/context]
Why is it not working with the classpath prefix? And why is it working with the file prefix? I thought the file prefix would only work for the file system and not for a jar file... What am I doing wrong?
Thanks in advance
Update: Here is a complete view of the (fragment) test project:
/
+-- src/main/java/
| +-- MyTestClass.java
|
+-- src/main/resources/
| +-- spring/
| | +-- some-config.xml
| +-- log4j.properties
|
+-- META-INF/
| +-- MANIFEST.MF
|
+-- pom.xml
After tycho has tried to execute my test class I see the following files under target:
/target
|
+-- classes/
+-- MyTestClass.class
+-- spring/
+-- some-config.xml
+-- log4j.properties
+-- work/ // contains the eclipse configuration (config.ini, etc.)
+-- MANIFEST.MF
+-- mybundle-xx.jar
I've ommitted the properties and surfire files. The generated config.ini under target/work/configuration/ lists all bundles that are mentioned in the manifest as required bundles. They are referenced as jar files except of my test fragment bundle. For the test bundle the following entry exists:
reference\:file\:C\:/[...]/workspaces/workspace/my.bundle.tests
Is this correct? It would at least explain why the file prefix is working...
But what about the classpath prefix? Has the manifest been copied to the right location in the target folder? I mean it's outside of the classes folder that is referenced in the dev.properties.
Furthermore log4j complains at startup that it's not properly configured which indicates that it can't find the log4j.properties on the classpath.
Update: Now I'm trying another way. I've read this article and it seemed to be an easier way to get things running. So I've added the maven-surfire-plugin to my pom and changed my packaging type from "eclipse-test-plugin" to "jar" so that tycho doesn't run it's own surefire-plugin. But now I'm standing in front of another problem. Spring seems to provide only an ArtifactLocator for maven2 repositories and not for p2 repositories like tycho uses.
Does anyone know if there is an ArtifactLocator for p2 repositories out there?
Is anyone using the same setup with tycho, osgi and spring for integration testing?
Put spring-context-xx.jar on your classpath.
Namespaces are handled by implementations of the NamespaceHandler interface. At startup spring loads all of them, and attempts to parse each namespace with the loaded handlers. If none of them claims to be able to parse it, the exception is thrown. the context: namespace is parsed by ContextNamespaceHandler, which resides in the aforementioned jar.
Using Tycho,
according to http://blog.vogella.com/2010/07/06/reading-resources-from-plugin/
I tried locations like:
"platform:/plugin/<host-bundle-id>/<path-to-resource>"
and now its able to load the context configurations as a resource.

Access resource file from JSP

I want to access xml files from java class, lying under web/resources folder..
i.e
---Web pages
|
|--Web-INF
|
|-resources
| |-data.xml
|
|-other jsps
---Source Folder
|-databean
I want to access data.xml from a class under databean package. Is it possible? How?
Use ServletContext#getResource() or #getResourceAsStream() to obtain resources which are available in the webcontent.
InputStream input = getServletContext().getResourceAsStream("/WEB-INF/resources/data.xml");
You however normally do that in a Servlet, not a JSP.

Load properties file in JAR?

I'm having trouble when one of the jars that my web app depends on tries to load a properties file from within the jar. Here is the code in the jar.
static
{
Properties props = new Properties();
try
{
props.load(ClassLoader.getSystemResourceAsStream("someProps.properties"));
} catch (IOException e)
{
e.printStackTrace();
}
someProperty = props.getProperty("someKey");
}
The properties file is in my "src/main/resources" directory of the Maven project. When I run this code from my junit test in Eclipse, it executes just fine. When the project is built with Maven into a jar, and included as a dependency in my web app, it fails to locate the properties file. I know that the properties file is at the base directory of the depended on jar, I don't know how to fix this.
The problem is that you are using getSystemResourceAsStream. Use simply getResourceAsStream. System resources load from the system classloader, which is almost certainly not the class loader that your jar is loaded into when run as a webapp.
It works in Eclipse because when launching an application, the system classloader is configured with your jar as part of its classpath. (E.g. java -jar my.jar will load my.jar in the system class loader.) This is not the case with web applications - application servers use complex class loading to isolate webapplications from each other and from the internals of the application server. For example, see the tomcat classloader how-to, and the diagram of the classloader hierarchy used.
EDIT: Normally, you would call getClass().getResourceAsStream() to retrieve a resource in the classpath, but as you are fetching the resource in a static initializer, you will need to explicitly name a class that is in the classloader you want to load from. The simplest approach is to use the class containing the static initializer,
e.g.
[public] class MyClass {
static
{
...
props.load(MyClass.class.getResourceAsStream("/someProps.properties"));
}
}
For the record, this is documented in How do I add resources to my JAR? (illustrated for unit tests but the same applies for a "regular" resource):
To add resources to the classpath for
your unit tests, you follow the same
pattern as you do for adding resources
to the JAR except the directory you
place resources in is
${basedir}/src/test/resources. At
this point you would have a project
directory structure that would look
like the following:
my-app
|-- pom.xml
`-- src
|-- main
| |-- java
| | `-- com
| | `-- mycompany
| | `-- app
| | `-- App.java
| `-- resources
| `-- META-INF
| |-- application.properties
`-- test
|-- java
| `-- com
| `-- mycompany
| `-- app
| `-- AppTest.java
`-- resources
`-- test.properties
In a unit test you could use a simple
snippet of code like the following to
access the resource required for
testing:
...
// Retrieve resource
InputStream is = getClass().getResourceAsStream("/test.properties" );
// Do something with the resource
...

Categories

Resources