finding a property using Spring and Webapp properties placeholder - java

This is a "simple" problem and I am seeking both a how-to and/or a you're-dumb-don't-do-that. I am open to both.
I am building a war file and want the structure to be:
WEB-INF/
properties/
<my properties files>
classes/
...
spring/
<my spring files>
Is that dumb? I know that I can access the properties files though the property-placeholder but I'd rather not nest the properties in the classes section - it doesn't make sense to me.
So the Spring file looks like this:
<context:property-placeholder location="classpath:properties/*.properties" />
if I want to access them in the classes area. I thought that
<context:property-placeholder location="properties/*.properties" />
would let me just put the directory under WEB-INF directly...am I wrong (ps I think I am :) ).
Any advice?

This should work
<context:property-placeholder location="WEB-INF/properties/*.properties" />
WEB-INF is not the root of the of the web-app, so you need to add WEB-INF to the path.
spring-context-3.1.xsd
<xsd:attribute name="location" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
The location of the properties file to resolve placeholders against, as a Spring
resource location: a URL, a "classpath:" pseudo URL, or a relative file path.
Multiple locations may be specified, separated by commas. If neither location nor properties-ref is
specified, placeholders will be resolved against system properties.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>

You can't do it the way you want since the classpath for the Classloader will be the /classes directory and any jars in the /lib directory. This is the standard configuration for a war file.
Wars and ears have specific configurations which you have to follow for the files to be valid. If you think about it, it would make it difficult to have different vendors provide web containers that could deploy the same war file if there was no standard format. There is a pretty informative page here.
To achieve something similar to what you want, you can simply have directories of /classes/properties and /classes/spring and look them up appropriately from your classpath ("classpath:properties/myfile.properties).

I am not sure what you want to achieve. Here the method I use to inject the properties from a basic properties file to a bean:
In the spring files (XML bean definitions), I add the reference to my property file (myfile.properties):
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:myfile.properties" />
</bean>
and then I add my references to the properties (db.url is the URL address for my database connection, I kept only the bean properties referenced in my property file).
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<!-- results in a setDriverClassName(String) call -->
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"><value>${db.url}</value></property>
<property name="username"><value>${db.login}</value></property>
<property name="password"><value>${db.password}</value></property>
</bean>
By default, if the property is not defined in the property file, Spring uses the System Properties (this behaviour can be changed).

Related

Read PropertyPlaceholderConfigurer classpath Spring with Jboss

Using PropertyPlaceholderConfigurer to externalize spring-configuration
properties.
Added following code to spring-servlet.xml
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:environment.properties</value>
</property>
</bean>
Filter to be externalized from spring-security.xml
<security:custom-filter position="AUTH_FILTER" ref="${filter}" />
filter value is present in environment.properties
environment.properties file is present inside Jboss modules and is readable from code using resource bundle.
But, with these changes somehow properties file is not getting loaded and following error is thrown while publishing code.
Caused by: java.lang.IllegalArgumentException: Could not resolve
placeholder 'filter' in string value "${filter}"
PS:
Also tried hardcoding path as <value>file:${jboss.home.dir}/modules/system/layers/base/configuration/main/environment.properties</value> but, dosen't seems to be working.
I think your problem is that your spring-servlet.xml is not linked to your spring-security.xml. So spring-security.xml has no knowledged of the PropertyPlaceholderConfigurer.
IMO, you should configure PropertyPlaceholderConfigurer in a properties-context.xml (for instance) so you can import this new file into your spring-servlet.xml and spring-security.xml as following:
<import resource="classpath:properties-context.xml" />

Ant Multiple Property Values with the Same Name

I am working on an ant build script. How do i set the two property value with the same name:
<property name="java.src.dir" location="src" />
<property name="java.src.dir" location="src/java" />
In my application some of the directories are src/java and some are src. I need to make it flexible enough to work on both.

Externalize properties in Tomcat

I would like to configure a series of environment-dependant settings as an external resource, so that the same WAR artifact can be configured in any application server.
In Glassfish I rememeber that I just created a .properties file using the built-in Properties Resource JNDI Factory, and it worked like a charm, but there's no such thing in Tomcat.
I tried defining a java.net.URL and a java.lang.String to define just the path that this file is held in, but I get the following error:
Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/c://app.properties]
So what would be a good way to create an environment-agnostic set of properties for my application?
PS: this is how I define my properties in Spring:
<jee:jndi-lookup id="appProperties" jndi-name="java:comp/env/url/urlAppProperties" />
<bean id="application-properties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>#{ appProperties }</value>
</list>
</property>
</bean>
You can add external configuration values to the JNDI context using Tomcat's resource configuration elements. As described in the Tomcat documentation, you can define a <GlobalNamingResources> element in your server.xml listing a set of configuration values which are available to all contexts (web applications) on that server:
Example taken from the Tomcat docs:
<GlobalNamingResources ...>
...
<Environment name="maxExemptions" value="10"
type="java.lang.Integer" override="false"/>
...
</GlobalNamingResources>
These environment variables are then available via JDNI in the java:comp/env context. In order to use such variables in a web application, you have to link to them in the individual context.xml configuration files using the <ResourceLink> element.
<Context>
<ResourceLink name="maxExemptions" global="maxExemptions" type="java.lang.Integer"/>
</Context>
With this set up, you can access these values through the standard JNDI API.

Liquibase Groovy-DSL Spring

I am developing a spring-shell database migration tool.
At the moment i try to use liquibase with the groovy-dsl extension.
My build.gradle includes the extension jar, also i declared liquibase in the spring-shell-plugin.xml
spring-shell-plugin.xml
<bean id="liquibase" class="liquibase.integration.spring.SpringLiquibase" depends-on="postgresService">
<property name="dataSource" ref="psqlDataSource"/>
<property name="changeLog" value="com.example.db.DbChangelog_master"/>
<property name="defaultSchema" value="${postgres.schema}"/>
</bean>
But everytime i start the application liquibase throws the following error
Caused by: liquibase.exception.UnknownChangelogFormatException: Cannot find parser that supports com.example.db.DbChangelog_master
at liquibase.parser.ChangeLogParserFactory.getParser(ChangeLogParserFactory.java:70)
at liquibase.Liquibase.getDatabaseChangeLog(Liquibase.java:226)
at liquibase.Liquibase.update(Liquibase.java:202)
at liquibase.Liquibase.update(Liquibase.java:192)
at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:434)
at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:391)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
... 13 more
The documentation is a bit rare, also the jar is included in the classpath.
Does the groovy scripts need to be in src/main/resources? Currently they are in a seperate package in src/main/groovy
I think that your property
<property name="changeLog" value="com.example.db.DbChangelog_master"/>
is incorrect. This should be the path to your changelog file. If that file is a groovy file, it might be
<property name="changeLog" value="DbChangelog_master.groovy"/>
if that file is available on the classpath.

How to use property-placeholder for file on filesystem

We used to have a way to load properties from a file on the classpath:
<context:property-placeholder location="classpath:myConfigFile.properties" />
and it worked great. But now we want to load properties from a specific file on the system that is NOT in the classpath. We wanted to be able to dynamically load the file, so we are using a Java environment variable to populate it. I'll give a simple example below:
In Java:
System.setProperty("my.prop.file", "/path/to/myConfigFile.properties");
In Spring XML:
<context:property-placeholder location="${my.prop.file}" />
I've also tried it this way, thanks to an idea from Luciano:
<context:property-placeholder properties-ref="prop" />
<util:properties id="prop" location="reso"/>
<bean id="reso" class="org.springframework.core.io.FileSystemResource">
<constructor-arg index="0" value="${my.prop.file}" />
</bean>
Everything I've tried has failed. No matter what I set my.prop.file to. Greatest hits include:
<context:property-placeholder location="/path/to/myConfigFile.properties" />
(ClassNotFoundException: .path.to.myConfigFile.properties)
<context:property-placeholder location="file:/path/to/myConfigFile.properties" />
(ClassNotFoundException: file:.path.to.myConfigFile.properties)
<context:property-placeholder location="file:///path/to/myConfigFile.properties" />
(ClassNotFoundException: file:...path.to.myConfigFile.properties)
How do you use property-placeholders with a location that is on the file system and NOT on the classpath? We are using Spring 3.0.5.
It turns out there was a problem with the script running the Java program that loads the spring file. Thank you for helping. I am going to request that this question be deleted, as the original code works after all.
Thank you for your help.
This did work for me:
<context:property-placeholder location="file:/path/to/myConfigFile.properties" />
But this (interestingly) did not:
<context:property-placeholder location="#{ systemProperties['foo'] }" />
I got
java.io.FileNotFoundException: Could not open ServletContext resource [/#{ systemProperties['foo'] }]
You're not going to be able to use a property placeholder ${..} with the definition of a PropertyPlaceholderConfigurer. It's the chicken before the egg.
You can always subclass PropertyPlaceholderConfigurer and have it do whatever you want (for example, call setLocations() in a #PostConstruct method. Then, instead of using <context:property-placeholder>, use:
<bean class="com.foo.MyPropertyPlaceholderConfigurer"/>
What about this way?
<context:property-placeholder properties-ref="prop" />
<util:properties id="prop" location="reso"/>
<bean id="reso" class="org.springframework.core.io.FileSystemResource">
<constructor-arg index="0" value="/yourpathandfile" />
</bean>

Categories