Spring Application Context can't load the configuration files - java

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.

Related

Running jar with -Dloader.path= works, but not application.properties loader.path

I have an external properties file under /config/application.properties which I retrieve properties from. When I run my jar, it is able to pick up certain properties from it, (e.g. server.port=8083)
This is the structure of my files/folders:
ProjectFolder
|
+-- mytool.jar
|
+-- config
| |
| +-- application.properties
|
+-- lib
| |
| +-- externalJar.jar
Now, the problem is that I need the property "loader.path" from the external properties file, all other properties are being loaded correctly except for loader.path when I run the jar with:
java -jar mytool.jar
Inside the external application.properties contains:
spring.servlet.multipart.enabled=false
server.port = 8083
logging.file = /someplace/
loader.path=lib
Since it is not loading the externalJar.jar, I encounter classNotFoundExceptions.
However, what's strange is that when I start the app with:
java -Dloader.path=lib -jar mytool.jar
Everything works as expected.
Am I missing something with the application.properties file?
I have tried using the full path:
loader.path=/home/me/ProjectFolder/lib
but that didn't work either.
I am confident that the application.properties is being read because the server.port number showing up on boot is the one I specifically specified.
I've changed the project to use the PropertiesLauncher in Maven.
MANIFEST.MF
Manifest-Version: 1.0
Implementation-Title: mytool
Implementation-Version: 0.0.1-SNAPSHOT
Built-By: giraffepoo
Implementation-Vendor-Id: com.sap
Spring-Boot-Version: 2.1.3.RELEASE
Main-Class: org.springframework.boot.loader.PropertiesLauncher
Start-Class: com.sap.mytool
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Created-By: Apache Maven 3.3.9
Build-Jdk: 1.8.0_201
Implementation-URL: https://projects.spring.io/spring-boot/#/spring-bo
ot-starter-parent/mytool
If someone could point me in the right direction, your help is greatly appreciated. Thanks!
Note:
Not sure if related, but the externalJar.jar is utilized immediately when the application starts up in the overridden method: contextInitialized
I know that there is a kindda old question, but still without answear. I think the problem lays that the loader.path property should be provided in the standalone loader.properties file. As it is described in documentation.
Also keep in mind that it works only for PropertiesLauncher, not for JarLauncher or WarLauncher.

How do I build an OpenFire plugin using Gradle in Intellij?

According to the OpenFire documentation (https://www.igniterealtime.org/builds/openfire/docs/latest/documentation/plugin-dev-guide.html) to build a custom plugin I need to create a jar with the following folder structure:
myplugin/
|- plugin.xml <- Plugin definition file
|- readme.html <- Optional readme file for plugin, which will be displayed to end users
|- changelog.html <- Optional changelog file for plugin, which will be displayed to end users
|- logo_small.gif <- Optional small (16x16) icon associated with the plugin (can also be a .png file)
|- logo_large.gif <- Optional large (32x32) icon associated with the plugin (can also be a .png file)
|- classes/ <- Resources your plugin needs (i.e., a properties file)
|- database/ <- Optional database schema files that your plugin needs
|- i18n/ <- Optional i18n files to allow for internationalization of plugins.
|- lib/ <- Libraries (JAR files) your plugin needs
|- web <- Resources for Admin Console integration, if any
|- WEB-INF/
|- web.xml <- Generated web.xml containing compiled JSP entries
|- web-custom.xml <- Optional user-defined web.xml for custom servlets
|- images/
I know there is an Ant build script to help do this but I couldn't find it and I'm having a hard enough time with Gradle and Maven, I'd rather not add having to learn Ant and deal with XML on to my list of chores. So, I tried to make a Gradle build script. Unfortunately Gradle still doesn't make any sense to me and in Intellij it seems to just do whatever it wants.
Regardless, this is the Gradle script I came up with.
task buildPluginJar {
group 'build'
description 'Builds OpenFire Plugin Jar'
println 'Clean old libs and classes.'
delete 'pluginDefinition/lib/*'
delete 'pluginDefinition/classes/*'
println 'Copy libs.'
copy {
into 'pluginDefinition/lib'
from configurations.runtime
}
println 'Copy classes.'
copy {
into 'pluginDefinition/classes'
from 'build/classes'
}
println 'Build jar.'
String outputPath = 'build/out/' + project.name + '.jar';
jar {
into outputPath
from fileTree('pluginDefinition/').include('**/*').collect { zipTree it }
}
}
I managed to get the file copying to work, but the end where it's supposed to put it all into a signal jar isn't working. It completes but there is no jar output. What am I doing wrong?
I could not figure out how to do this with Gradle. But I did figure out how to build jars with Intellij. I followed this tutorial:
http://blog.jetbrains.com/idea/2010/08/quickly-create-jar-artifact/
I went through the File > Project Structure menu and added two artifacts. One to build the jar with all of the java code in my pluginDefinition/lib folder, and another to build a jar with the full contents of the pluginDefinition folder that I could install on my Openfire server.
Still, it would have been nice if I could have done this with Gradle.

Gradle change resource files target location in JAR

I am Gradle-fying a legacy project with the following structure:
root
+--- common
| \--- config
+--- module1
\--- module2
In the original project, config is just a folder that contains configuration files organized in subfolders for different environments. It contains a top level folder props and many subfolders as in:
config
\--- props
+--- prod
+--- dev
+--- john
\--- mike
The project can be configured to use any of the subfolders. The configuration gets loaded by a method that looks like this:
Config.class.getClassLoader().getResourceAsStream("props/" + ENV + "/" + name);
where ENV defines the environment (it's a system property), i.e., it can be prod, dev, mike, etc., and name is just the name of the file to load.
When running tests, I need to have the props folder in the classpath. When building the production artifacts (JARs and WARs) I wan't to avoid that and manually copy only the files I need in order to avoid possible conflicts or accidents.
So I decided to make config its own Gradle project and add it as a testCompile dependency to other modules that require configuration. However, if I add the props folder as a resource folder in Gradle, the generate JAR file for the config module will flatten all the subfolders of props (which is the intended behavior), and thus the code above will simply fail.
My question is: is there a way to tell Gradle to copy those files to a subfolder called props instead of to the root of the JAR?
I know it would be easy to refactor the project and move the folders around but we are in a phase of transition from legacy build and deployment tools and want to maintain the original structure as much as possible until we can switch to Gradle completely. It's an iterative process and can't happen overnight. So I need an interim solution.
Here's how I ended up doing it. This is the build.gradle file for the config module:
apply plugin: 'java'
sourceSets {
main {
resources {
srcDir 'props'
}
}
}
// this is to force Gradle to create the JAR used at
// runtime with the correct folder structure
jar.into('props')
idea.module.iml.withXml {
def node = it.asNode()
// this is to force IntelliJ to create the folders
// used at runtime with the correct folder ('package') structure
node.component.content.sourceFolder.#packagePrefix="props"
}
It works like a charm because the config module only contains resources in the props folder. Whew.

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.

How to load a resource from an embedded JAR File

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

Categories

Resources