How to add external properties file to classpath in jboss 4.2 - java

I want to read an external properties file when launching Jboss 4.2 . I want to add it to the classpath to read it from a WAR file . I have seen different solutions with Jboss 6 using modules, but I haven't seen anything related to JBoss 4.2.
I have included inside 'jboss-service.xml' the following code :
<!-- Bean for reading properties -->
<mbean code="org.jboss.varia.property.SystemPropertiesService"
name="jboss.util:type=Service,name=SystemProperties">
<!-- Load properties from each of the given comma separated URLs -->
<attribute name="URLList">
./conf/path.tmview.properties
</attribute>
</mbean>
In this file I have defined the property :
property-placeholder filepath=/var/tmview_props/tmview/tmview.properties
This property is used in the following bean definition
<bean id="tmviewConfigurerLocation" class="org.springframework.core.io.FileSystemResource">
<constructor-arg value="${property-placeholder-filepath}" />
</bean>
inside an applicationContext.xml . When I launch jboss, the file of properties is read
15:45:29,939 INFO [SystemPropertiesService] Loaded system properties
from: file:/D:/devel/projects/tmview/deployment/jboss-
...ver/tmview/conf/path.tmview.properties
So, the property is read, but I kept obtaining the following exception
2015-03-24 15:45:39,219 ERROR
[org.springframework.web.context.ContextLoader] Context
initialization failed
org.springframework.beans.factory.BeanInitializationException: Could
not load properties; nested exception is
java.io.FileNotFoundException: ${property-placeholder-filepath} (The
system cannot find the file specified)
at
org.springframework.beans.factory.config.PropertyResourceConfigurer.
postProcessBeanFactory(PropertyResourceConfigurer.java:78)
Is there any special way to read the property inside the spring bean ?

In jboss 4 you was able to drop property files in the <jboss_home>/server/<instance>/conf directory and they would be available from the classpath.
Another possibility is add your custom directory to the classpath, to do this see Adding second conf folder to JBoss 5.1.0

Ok . At the end , I solved the problem . It seems the problem was located in reading from application-context.xml .
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>file:${tmview.conf.variables}</value>
</property>
</bean>
I had to add a property placeholder reader . Regarding to jboss, you can read the parameter file either from conf/jboss-service.xml or deploy/properties-receive.xml, but it seems more appropiate to do the reading from the second one .

Related

How to use multiple property files (via PropertyPlaceholderConfigurer), having one property file optional?

In my applicationContext.xml file of my Spring project, I use a PropertyPlaceholderConfigurer manage the external properties from two configuration files, like this:
<!-- Configuration. -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>file:${universign.configuration}</value>
<value>file:${universign.common.configuration}</value>
</list>
</property>
</bean>
The two file paths in the list are provided by system properties. My question is: How can I make the second value optional? When I launch the program, some times I want to launch with 1 configuraiton file, sometimes 2. But using my configuration above, if I don't provide the two system properties, the program cannot be launched, it will give an Exception like this:
[WARNING] Failed startup of context o.e.j.m.p.JettyWebAppContext#12f9f896{/,[file:///opt/li/projects/universign/universign-admin-www/webapp/, file:///opt/li/projects/universign/universign-admin-www/target/tmp/universign-config-8_17-SNAPSHOT-universign-admin-www_zip1/],UNAVAILABLE}{file:///opt/li/projects/universign/universign-admin-www/webapp/}
org.springframework.beans.factory.BeanInitializationException: Could not load properties; nested exception is java.io.FileNotFoundException: ${universign.common.configuration} (Aucun fichier ou dossier de ce type)
at org.springframework.beans.factory.config.PropertyResourceConfigurer.postProcessBeanFactory(PropertyResourceConfigurer.java:89)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:265)
...
How to make one of the two configuration files optional?

Spring resolved property file location needs to resolve those properties

I am using Spring version 4.0.6.RELEASE and am trying to have spring read from a properties file and use one of the resolved properties to provide a location to another properties file. My spring.xml file has the following:
<bean id="applicationProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:application.properties</value>
<value>classpath:version.properties</value>
<!- The below file contains the another file location -->
<value>file:${catalina.base}/conf/instance.properties</value>
<value>${another.file.location}</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="true"/>
</bean>
instance.properties contains:
account.id=BlahBlahBlah
another.file.location=file:/Users/beardman/.myapp/local.properties
and /Users/beardman/.myapp/local.properties contains:
magic.number=3
database.endpoint=blah
I keep getting the following warning:
WARN [main] o.s.b.f.c.PropertyPlaceholderConfigurer Could not load properties from ServletContext resource [/${another.file.location}]: Could not open ServletContext resource [/${another.file.location}]
When debugging my code, I can see that the account.id was injected correctly, but I can never get the magic.number or database.endpoint to show up. How can I get spring to use the resolved property from the instance.properties file as the value for the another.file.location?
EDIT: Added property file contents
Spring by default replaces property placeholders with system properties. Since you want to use properties defined in an external file as well, you need to create a PropertyPlaceholderConfigurer
This tag is the shorthand, but you can define PropertyPlaceholderConfigurer as a bean if you need more control. Add this before your applicationProperties bean
<context:property-placeholder location="file:${catalina.base}/conf/instance.properties"/>
Note that properties in the file will override system properties in the default mode. You can specify that system properties are checked first by adding the attribute systemPropertiesMode="override" to the property-placeholder element

Exposing jndi variables as property place holder

I have a jar containing a spring configuration. I am retrieving some JNDI variables to configure web service addresses inside the jar. Now, I am using the same jar in a Spring Batch and I would like to use the same spring configuration file.
My problem is that I am passing the web service addresses as system properties to my batch with the
java -DmyFoo=bar
Using this
<context:property-placeholder system-properties-mode="OVERRIDE" ignore-unresolvable="true" />
I can get my variables as #Value("myFoo")
So my question is: is there any way to be able to get my JNDI variables in my property placeholder? Or be able to get them as JNDI and then expose them in a property placeholder?
What I want to be able to do is replace this
<bean id="MBean" class="com.xxx.utils.ActivationMBean">
<property name="makeCall">
<jee:jndi-lookup jndi-name="semantic.activation" />
</property>
</bean>
By this
<bean id="MBean" class="com.xxx.utils.ActivationMBean">
<property name="makeCall" value="${semantic.activation}" />
</bean>
When using <context:property-placeholder /> a PropertySourcesPlaceholderConfigurer is registered. (That is when you are on Spring 3.1 or later and are using the xsd without version or a version > 3.0). The property-source abstraction has been added in Spring 3.1.
The PropertySourcesPlaceholderConfigurer uses the configured PropertySources to obtain values for placeholders. The PropertySources consulted depends on the environment, web or non-web, and the amount of #PropertySource annotations or loaded property files through the location attribute of the <context:property-placeholder /> elements.
For the StandardServletEnvironment (web) the PropertySources are consulted in the following order.
ServletContext init-params
ServletContext context-params
JndiPropertySource
System Properties
System Environment
For the StandardEnvironment (non-web) the PropertySources are consulted in the following order.
System Properties
System Environment
Depending on the setting of the localOverride property properties loaded from properties files are added to the top (true) or to the bottom (false) of the list of PropertySources to consult.
Given the following bean definition.
<bean id="MBean" class="com.xxx.utils.ActivationMBean">
<property name="makeCall" value="${semantic.activation}" />
</bean>
In a web environment the placeholder ${semantic.activation} is being resolved first against the JNDI tree if that isn't found it will fallback to the System Properties. For a non-web no JNDI lookup is attempted and properties specified by -D or in the environment are consulted.
I finally found a trick that makes what I need:
<bean id="MBean" class="com.xxx.utils.ActivationMBean">
<property name="makeCall">
<jee:jndi-lookup jndi-name="semantic.activation" default-value="${semantic.activation}" />
</property>
</bean>
It can't be used with the #Value annotation but if we are using JNDI it will take it and not it will fall back to the property. If none is defined it will fail to start and that is what I wanted.

Spring MVC localization - properties file not being found

I'm trying to get basic localization working in a new Spring MVC app. I've tried everything I can think of but always end up with the following exception, regardless of what I do. Any help would be greatly appreciated...
I've tried adding the properties file to every single directory but it still gives me an error. Once I get it working I'll systematically remove extras.
The exception:
07/13/2012 21:06:00.178 [DEBUG] [org.springframework.context.support.ReloadableResourceBundleMessageSource] No properties file found for [messages] - neither plain properties nor XML
07/13/2012 21:06:00.178 [DEBUG] [org.springframework.context.support.ReloadableResourceBundleMessageSource] No properties file found for [messages_en] - neither plain properties nor XML
07/13/2012 21:06:00.179 [DEBUG] [org.springframework.context.support.ReloadableResourceBundleMessageSource] No properties file found for [messages_en_US] - neither plain properties nor XML
07/13/2012 21:06:00.182 [ERROR] [org.springframework.web.servlet.tags.MessageTag] No message found under code 'test.testMessage' for locale 'en_US'.
javax.servlet.jsp.JspTagException: No message found under code 'test.testMessage' for locale 'en_US'.
Here's the JSP entry (the fmt:message just shows ???test.testMessage??? while the spring:message blows up):
<h2><fmt:message key="test.testMessage" />!</h2>
<h2><spring:message code="test.testMessage" />!</h2>
Here's the configuration in my comparison-servlet.xml file:
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="messages" />
</bean>
Here's the war structure (note that I added the messages.properties at pretty much every level):
messages.properties
src
messages.properties
main
messages.properties
java
...
resources
messages.properties
webapp
index.jsp
messages.properties
WEB-INF
comparison-servlet.xml
web.xml
messages.properties
jsp
messages.properties
compare.jsp
globalIncludes.jsp
classes
messages.properties
resources
messages.properties
test
...
Any idea why it can't find a file that is definitely there? Do I need to explicitly set something regarding the classpath?
Try to put messages.properties under WEB-INF directory inside any folder and set the path with basename property.
For example:
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="/WEB-INF/i18n/messages" />
</bean>
See Javadoc here.
The problem turned out to be with the war file itself. While the properties files were being copied to the target directory and showed up as if they were included in the build, the maven pom file was set to explicitly exclude properties files from the built artifact.
Once I removed this from my pom file, everything started working fine:
<configuration>
<packagingExcludes>**/*.properties</packagingExcludes>
</configuration>

Elegant ways to separate configuration from WAR in Tomcat

I am trying to find the best way to pass complex configurations in a Spring webapp running in Tomcat. Currently I use JNDI to pass data sources and strings from the Tomcat context into the webapp, and this works well.
But, lets say I need to select the implementation of a notification service. There is no way that Spring can conditionally select which bean to instantiate (although in the past I have used a JNDI string to import a predefined configuration of beans by setting contextConfigLocation).
I've also seen many webapps which supply a configuration tool which will create a custom WAR file. In my opinion this is bad form, if for no other reason than it prevents the redeployment of WARs from upstream without many checks to ensure all the configuration has been re-applied.
Ideally I would be able to supply a Spring XML file which existed on the filesystem, outside of the webapp. But, the spring import directive does not seem to resolve ${} variables, making it impossible to supply customisations.
Are there any techniques I can employ here to properly separate complex configuration from the webapp?
If I have a specific set of beans that I'd like to configure, and this configuration must be separated from the WAR file, I usually do the following:
In applicationContext.xml:
<!-- here you have a configurer based on a *.properties file -->
<bean id="configurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="file://${configDir}/configuration.properties"/>
<property name="ignoreResourceNotFound" value="false" />
<property name="ignoreUnresolvablePlaceholders" value="false" />
<property name="searchSystemEnvironment" value="false" />
</bean>
<!-- this is how you can use configuration properties -->
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="${smtp.host}"/>
</bean>
In configuration.properties:
smtp.host=smtp.your-isp.com
You also need to start Tomcat with -DconfigDir=/path/to/configuration/directory
If you are using Spring 3, you can take advantage of the Spring Expression Language. Let's say you have two applications app1.war and app2.war and they require a properties file named config.properties. The applications will be deployed with context paths /app1 and /app2.
Create two directories app1 and app2 in a common directory, eg. C:\myConfig\app1 and C:\myConfig\app2.
Put config.properties inside app1 and another config.properties inside app2.
Then create a file ${CATALINA_HOME}/conf/[enginename]/[hostname]/context.xml.default with the contents:
context.xml.default:
<Context>
<Parameter name="myConfigDirectory" value="C:/myConfig" override="false"/>
</Context>
The parameter myConfigDirectory will be available to all the applications on the host. It is better to create this parameter in context.xml.default rather than in server.xml, because the file can be changed later without restarting tomcat.
In the applicationContext.xml inside war you can access config.properties using the SpEL expression: "#{contextParameters.myConfigDirectory + servletContext.contextPath}/config.properties", so for example you can write:
applicationContext.xml:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="file:#{contextParameters.myConfigDirectory + servletContext.contextPath}/config.properties" />
</bean>
The expression will get expanded to C:/myConfig/app1 for application with contextPath /app1, and C:/myConfig/app2 for application with contextPath /app2. This will make the applications access the config.properties file based on their contextPath.
If you want to be fully portable between web containers you cannot rely on anything outside your WAR-file. In Tomcat the SecurityManager allows you to discover the physical location on disk where your code is deployed, and you can then use that knowledge to navigate the disk to a location where your configuration file is placed.
See e.g. Determine location of a java class loaded by Matlab

Categories