resources.groovy of my Grails project is growing, so I am thinking of splitting it in some logical files that will be easier to mantain. After reading some questions, blogs, i got to know about importBeans or loadBeans. This works well only when application is run using grails run-app. However we I create a war and deploy it on JBoss, the custom bean files are not accessible.
Also tried below with no luck - mentioned here -
Load spring beans from custom groovy files in grails app
grails.war.resources = { stagingDir, args ->
copy(todir: "${stagingDir}/WEB-INF/classes/spring") {
fileset(dir:"grails-app/conf/spring") {
include(name: "datasourceDefinitions.groovy")
exclude(name: "resources.groovy")
}
}
}
I have added datasourceDefinitions.groovy in grails-app/conf/spring.
Please help.
The problem is due to the Spring bean configuration files are moved into the folder "WEB-INF/classes/spring/"(make sure the file is packaged in the.war) inside the WAR file. As what I did was locate the resource path in resources.groovy.
def loadFromFile = { name ->
importBeans("file:grails-app/conf/spring/"+name)
}
def loadFromWar = { name ->
def resource = application.parentContext.getResource("WEB-INF/classes/spring/"+name)
loadBeans(resource)
}
def loadResource = application.isWarDeployed() ? loadFromWar : loadFromFile
loadResource "datasourceDefinitions.groovy"
loadResource "anotherBean.groovy"
Related
I'm facing an issue on only one platform when I'm trying to execute mvn clean install. As part of the build we compile multiple component and last we execute functional testing using wiremock. It is supposed to pick specific configuration from function testing profile and default properties should be picked from application.properties file. But for some reason same code isn't able to find the properties mentioned in these file. So, just wondering if somehow, if I can get the list of properties files being loaded during wiremock ? This will give some clue on why isn't expected properties files are being picked ?
All properties files are located inside :
src/main/resources
And, following from test class.
#ContextConfiguration(classes = SampleFTConfiguration.class)
public class SampleControllerTest{
//test method
}
#ComponentScan("com.xxx.xxx.xxx.ft")
#PropertySource("classpath:application-test.properties")
public class SampleFTConfiguration{
}
Note : I'm not expecting anyone to fix the issue, all I wanted to know, if we can get the name of loaded property files ?
After searching and trying out for a while, looks like ConfigurableEnvironment is what you're trying to find.
The code is pretty simple. However I think it's better to debug and check the configurableEnvironment value directly, so you can adjust the code to your needs (remove filter name, etc).
#Autowired
private ConfigurableEnvironment configurableEnvironment;
#Test
public void getProperties() {
Map<String, Object> mapOfProperties = configurableEnvironment.getPropertySources()
.stream()
.filter(propertySource -> propertySource.getName()
.contains("application-test.properties"))
.collect(Collectors.toMap(PropertySource::getName, PropertySource::getSource));
mapOfProperties.values()
.forEach(System.out::println);
}
the code will printed out
{properties-one=value-for-properties-one,
properties-two=value-for-properties-two}
with my application-test.properties value
properties-one=value-for-properties-one
properties-two=value-for-properties-two
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/env/ConfigurableEnvironment.html
Ok, following the test definition please make sure that:
You should run the test with spring runner (spring extension if you're on JUnit5). So you should place the annotation #RunWith(SpringRunner.class) (or #ExtendsWith(SpringExtension.class) for junit 5)
The property source you're using is application-test.properties. You've said that the properties file is located in src/main/resources but the file name probably implies that it should reside in src/test/resources
To troubleshoot context configuration on app startup (for those who don't have an access to app sources) you can add
logging:
level:
org.springframework.boot.context.config: trace
to your application.yml to get filenames:
2022-10-26 13:29:45.977 TRACE [,,] 16522 --- [main] o.s.b.context.config.ConfigDataLoaders : Loading file [config/application-app.
yml] using loader org.springframework.boot.context.config.StandardConfigDataLoader
2022-10-26 13:29:45.977 TRACE [,,] 16522 --- [main] o.s.b.context.config.ConfigDataLoaders : Loading file [config/application-ppe.
yml] using loader org.springframework.boot.context.config.StandardConfigDataLoader
Adding org.springframework.boot.context.properties: trace doesn't help much though. Some user-defined properties get logged, however others don't.
I am building multiple microservices with wildfly-swarm. I have one microservice that works correctly and one that fails while trying to start the CDI-Container because the class com.google.common.cache.Cache is not present in the Classpath but is referenced from an ApplicationScoped Bean. This is the stacktrace i get:
WELD-001474: Class [...].core.framework.timeseries.cache.TimeseriesDataCache is on the classpath, but was ignored because a class it references was not found: com.google.common.cache.Cache from [Module \"deployment.43ef34ae-45a8-4468-aa7d-40d75c0f0a79.war:main\" from Service Module Loader].
The strange thing is that both microservices use this class from the same maven dependency, but the other service works like intended. The main difference is, that the failing microservice uses Ribbon (via the swarm-dependency) and this brings a second Guava-Dependency (version 14.0.1). Hence i tried to exclude the guava-dependency from Ribbon (coming from the netflix-guava module) in any way (by excluding the guava dependency directly on the main Ribbon artifact and by excluding the netflix-guava dependency from the main Ribbon aratifact and then adding the dependency for netflix-guava myself and excluding it there).
I was partly successful by manually excluding the guava artifact for version 14.0.1 in my main-class but that caused other issues and in my opinion would not be a viable option (since this behaviour could lead to us having to manually exclude any artifact that is shipped with some dependency if it causes problem.
So my question would be: is there any way to work around this behaviour? Or a solution i did not get from the swarm documentation? I am really lost right now and any help/idea is greatly appreciated. Just in case here is the code that builds my deployment as i would like it to work (without manually adding the neccessary artifacts to exclude unwanted ones):
public static void main(String[] args) throws Exception {
Swarm container = new Swarm(args);
final String offset = args.length > 0 ? args[0] : null;
container = container.socketBindingGroup(new SocketBindingGroup("default-sockets","public","${jboss.socket.binding.port-offset:" +
offset != null ? offset : "0" +
"}"));
container
.fraction(new JAXRSFraction())
.fraction(new CDIFraction())
.fraction(new LoggingFraction());
JAXRSArchive jaxrsArchive = ShrinkWrap.create(JAXRSArchive.class);
jaxrsArchive.addAsResource(new ClassLoaderAsset("META-INF/beans.xml", FormulaDeployment.class.getClassLoader()), "classes/META-INF/beans.xml");
jaxrsArchive.addAllDependencies();
jaxrsArchive.addAsLibrary(container.createDefaultDeployment());
jaxrsArchive.as(RibbonArchive.class).advertise();
container.start().deploy(jaxrsArchive);
}
I'm a total beginner in Spring Batch Framework, and I found easily understandable codes from http://www.javabeat.net/introduction-to-spring-batch/ to use as a learning tools. I have my project set up in Eclipse similiar to the codes from the page, it looks like this :
and the code executes the jobs in fileWritingJob.xml using CommandLineJobRunner like so :
package net.javabeat.articles.spring.batch.examples.filewriter;
import org.springframework.batch.core.launch.support.CommandLineJobRunner;
public class Main {
public static void main(String[] args) throws Exception {
CommandLineJobRunner.main(new String[]{"fileWritingJob.xml", "LayeredMultiThreadJobTest"});
}
}
and it runs as expected with no problem. But when I move the fileWritingJob.xml to another dir (still under the project dir) it doesn't run. I've tried changed the filename arguments at the CommandLineJobRunner method using relative and full path but it still doesn't run. For example, if create a directory under the project directory (same level as config) named jobs and put the xml there then pass the filepath to CommandLineJobRunner like this:
CommandLineJobRunner.main(new String[]{"/jobs/fileWritingJob.xml", "LayeredMultiThreadJobTest"});
or this
CommandLineJobRunner.main(new String[]{"../jobs/fileWritingJob.xml", "LayeredMultiThreadJobTest"});
it doesn't work.
But when I tried creating a subdir under the config directory and put the fileWritingJob.xml there, like this
CommandLineJobRunner.main(new String[]{"configsubdir/fileWritingJob.xml", "LayeredMultiThreadJobTest"});
it runs. It's as if the CommandLineJobRunner only checks the config directory.
I'm running out of ideas, can anyone help me?
UPDATE : After digging around a bit, thanks to Michael Minella's suggestion about ClassPathXmlApplicationContext I am able to put the xml wherever I want. I also consulted to this page Spring cannot find bean xml configuration file when it does exist and http://www.mkyong.com/spring-batch/spring-batch-hello-world-example/
So what I do now is declaring a new context by using ClassPathXmlApplicationContextand then run it using job launcher, here is how :
public static void main(String[] args) {
String[] springConfig =
{
"file:/path/to/xml/file"
};
ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);
JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");
Job job = (Job) context.getBean("JobName");
try {
JobExecution execution = jobLauncher.run(job, new JobParameters());
System.out.println("Exit Status : " + execution.getStatus());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Done");
}
Thank you very much for all your inputs!
A little detail around what is happening when you pass in the path to the xml based job definition to the CommandLineJobRunner. All we do is we pass that string to the constructor of ClassPathXmlApplicationContext. Because of that, it is expected that the xml file for the job definition be on the application's classpath. I can't tell from your project screen shot how you are building the project so I'm not sure if the config directory is on your classpath or not. However, if it is on the classpath and lives at the root of it, I'd expect you to be able to pass the path to the fileWritingJob.xml as "/config/fileWritingJob.xml".
The source for this class can be helpful when debugging this type of issue. You can find the source code for the CommandLineJobRunner here: https://github.com/spring-projects/spring-batch/blob/master/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/CommandLineJobRunner.java
You can specify the job path relative to your config directory. For example, if fileWritingJob.xml is in config/jobs/ directory, then in you can execute the job as follows:
CommandLineJobRunner.main(new String[]{"jobs/fileWritingJob.xml", "LayeredMultiThreadJobTest"});
Likewise, if the job configuration file is outside of the config directory, you can write:
CommandLineJobRunner.main(new String[]{"../fileWritingJob.xml", "LayeredMultiThreadJobTest"});
You can specify an absolute path for locating the job.
How: To disable Tomcat JARScanner?
Why: To stop Tomcat scan every .jar in my LIB folder.
According to documentation it says that it is possible to disable it within context.xml. But it seems to not be working. (May be I am missing something)
I made an exhaustive search in forums and could not find the solution.
This is in context.xml (not working yet):
<JarScanner scanClassPath="false" scanAllFiles="false" scanAllDirectories="false"></JarScanner>
Thanks in advance.
You should add the JarScanner element as a child of the root Context element in the context.xml file.
I have this kind of META-INF/context.xml file in the war file for disabling the JarScanner:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<JarScanner scanClassPath="false" scanAllFiles="false" scanAllDirectories="false"/>
</Context>
you can disable the JarScanner globally for user-definted patterns by opeining the file at
%TOMCAT_HOME%/conf/catalina.properties
and add a filename pattern to tomcat.util.scan.StandardJarScanFilter.jarsToSkip list.
For example, if you want to disable jar scanning completely you could add:
tomcat.util.scan.StandardJarScanFilter.jarsToSkip=\
*.jar,\
NOTE: this may of course lead to issues if you're employing JSTL, as templates won't be found by the scanner
in your java app add this :
#Bean
public TomcatServletWebServerFactory tomcatServletFactory() {
return new TomcatServletWebServerFactory() {
#Override
protected void postProcessContext(final Context context) {
((StandardJarScanner) context.getJarScanner()).setScanManifest(false);
}
};
}
This is what I did for Spring Boot.
Basically, append a new ignored jar file to the existing list of jars to ignore. This way, you don't totally disable the scanner, affecting who knows what else.
#Configuration
public class Config {
#Bean
public ServletWebServerFactory servletContainer() {
return new TomcatServletWebServerFactory() {
#Override
protected void postProcessContext(Context context) {
// db2 puts a ref to pdq.jar in the manifest, and tomcat then tries to find it, but it doesn't exist.
// The jar isn't needed, so we just disable looking for it. You could also remove it from the manifest,
// but that prob needs to be done after the build process.
JarScanFilter jarScanFilter = context.getJarScanner().getJarScanFilter();
if (jarScanFilter instanceof StandardJarScanFilter) {
StandardJarScanFilter filter = (StandardJarScanFilter) jarScanFilter;
String oldTldSkip = filter.getTldSkip();
String newTldSkip = oldTldSkip == null || oldTldSkip.trim().isEmpty() ? "pdq.jar" : oldTldSkip + ",pdq.jar";
filter.setTldSkip(newTldSkip);
} else {
logger.warn("Unable to disable the tomcat jar scanner for pdq.jar. You may see a FileNotFound exception complaining of not finding a db2 pdq.jar file. You can probably ignore the error. Ref: https://stackoverflow.com/questions/11656596/how-to-disable-tomcat-jarscanner");
}
}
};
}
}
The actual question is: Is there a way to get XmlWebApplicationContext to load resources using paths relative to the context location? For clarity's sake, let's say "context location" is the location of the first file specified via setConfigLocation() method.
Detailed explanation is below:
I'm using Spring MVC in web tier and Spring IOC in mid tier. Appropriate contexts are defined hierarchically as described in Spring Documentation: web stuff is defined in my-servlet.xml and services et al are defined in services.xml that's loaded via ContextLoaderListener. Mid tier can be deployed either together with web tier (e.g. the whole thing runs within ServletContainer) or separately (in which case services.xml is replaced by remote-services.xml defining remote stubs). The whole setup works perfectly except for the following problem:
I have certain resources (additional XML files, what have you) located in the same folder as services.xml that need to be accessible by said services. Those resources are specified as dependencies in services.xml using relative paths. When mid tier is deployed standalone that works fine, but not when it's deployed within servlet container. In the latter case mid tier context gets instantiated as XmlWebApplicationContext which loads all resources based of servlet context root meaning I have to prefix everything with /WEB-INF/ which I'd really like to avoid. Using PropertyPlaceholderConfigurer presents a similar problem as well.
I know I can work around this somewhat by having resources load from classpath, but that's not ideal either - for standalone deployment it means I need to add configuration folder to classpath and for web deployment it means everything has to be copied under WEB-INF/classes.
Any ideas?
I've ended up extending Spring's XmlWebApplicationContext to allow relative resource paths. This does what I want, that is allows me to use the same context.xml file no matter whether it's deployed as part of web app or standalone.
For anyone interested source is available below. It's published using SOV (Stack Overflow Voting) license :-) which means you're free to do whatever you want with it as long as you upvote this answer :-)
import java.io.IOException;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;
import org.springframework.web.context.support.XmlWebApplicationContext;
/**
* Extends Spring's default web application context to allow relative
* resource paths. Resources without explicitly specified URL protocol
* and / or leading slash are loaded relative to the first location
* from getConfigLocations().
*/
public class SpringApplicationContext extends XmlWebApplicationContext {
#Override
protected Resource getResourceByPath(String path) {
path = StringUtils.cleanPath(path);
if (path.startsWith("/") || (path.indexOf(':')>0)) {
return super.getResourceByPath(path);
}
try {
return super.getResourceByPath(getConfigLocations()[0])
.createRelative(path);
} catch (IOException E) {
// failed to create relative resource - default to standard implementation
return super.getResourceByPath(path);
}
} // getResourceByPath()
}
I agree that is rather annoying. I get around this by doing what you suggest, which is putting my spring config on the classpath, so even though I still use fully-qualified imports, they work under any environment.
I'm not sure why your classpath config needs to be that complex, though. The files can just under your java source folder alongside the java files, so they get handled the same.
Strange. Your solution does not work for me. Here is mine:
package dmp.springframework.web.context;
import java.io.IOException;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;
import org.springframework.web.context.support.XmlWebApplicationContext;
public class RelativeResourceXmlWebApplicationContext extends XmlWebApplicationContext {
#Override
protected Resource getResourceByPath(String path) {
path = StringUtils.cleanPath(path);
if (path.startsWith("/") || (path.contains(":"))) {
return super.getResourceByPath(path);
}
try {
String newFilename = super.getResourceByPath(getConfigLocations()[0]).getFile().getParentFile().getAbsolutePath();
newFilename = newFilename + "/" + path;
return new FileSystemResource(newFilename);
} catch (IOException E) {
// failed to create relative resource - default to standard implementation
return super.getResourceByPath(path);
}
} // getResourceByPath()
}