Im trying to read a properties file from an external location and I am trynig to use the contextPath name as the file's names beacuse I will run multiple instances of the app on he same server. I'm currently using SpringFramework 3.1.4
<context:property-placeholder location="file:/configFolder/#{servletContext.contextPath}.properties" />
the file name ends up being /configFolder/#{servletContext.contextPath}.properties
It does not replace the variable
is there another way to get this value?
Try:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="file:/config/#{servletContext.contextPath}.properties" />
</bean>
#{servletContext.contextPath} is a variable only known in JSP and Facelets through Expression Language. This won't work in Spring. You should put your configuration file inside a resource folder in your jar and retrieve it from there instead.
You state that this worked in other projects but that was because Spring supported a variable called servletContext (which IMO is wrong). Looks like Spring MVC 3.2 doesn't support this anymore, as explained here: Resolving servletContext.contextPath Expression in Spring 3.2.
Related
I'm trying to get a Marklogic ContentSource object loaded from Tomcat's context.xml using JNDI and Spring.
I'm using Tomcat 8.5, and Spring 2.5 (unfortunately)
I have added the following to context.xml in Tomcat
<Resource name="MLContentSource" auth="Container" type="com.marklogic.xcc.ContentSource"
factory="com.marklogic.xcc.jndi.ContentSourceBeanFactory"
url="xcc://username:password#mymarklogic-server/DatabaseName"/>
And the following in my applicationContext.xml
<bean id="contentSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/MLContentSource"/>
</bean>
I have another bean declared in my applicationContext.xml that relies on the ContentSource bean. Its expecting a property to be set that is of type com.marklogic.xcc.ContentSource
<bean id="marklogicRepository" class="org.example.repository.ingestion.MarkLogicRepositoryImpl">
<property name="contentSource" ref="contentSource" />
</bean>
The issue is that the contentSource bean is of type JndiObjectFactoryBean and not com.marklogic.xcc.ContentSource. Is there something I'm missing to get a proper ContentSource from the JndiObjectFactoryBean?
It turns out the above code actually worked, my IDE was complaining about types but Spring will automatically cast the object stored inside JndiObjectFactoryBean to the target type at runtime.
Maybe try XQJ?
https://github.com/cfoster/xqj-pool-example/blob/master/src/main/java/simple/WithJNDI.java
http://xqj.net/
The XQuery API for Java
A standard Java interface to XML DataSources which support XQuery 1.0.
The XQJ API is to XML Databases as the JDBC API is to Relational Databases.
Is a light-weight design and is very easy to pick up.
I use spring framework in my application,and i use some configuration files,but in different environment,i need to use different properties like db config properties.Now i put different files in different path,then i use maven profile method to package different WAR.
Now,i want to package only one WAR in all environment,and want by transfer different parameters to use different configuration files.In addition i don't want to put the configuration file out of the project.
You can use spring bean profiles or conditional beans.You can use following configuration to define propertyplaceholder beans for each environment.
<beans profile="environment1">
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>database_env1.properties</value>
</property>
</bean>
</beans>
<beans profile="environment2">
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>database_env2.properties</value>
</property>
</bean>
</beans>
For database configuration, a possible approach is to define the JDBC DataSource as a JNDI resource directly in your application server that you then use (see how) - this way your WAR file doesn't contain the connection information, the runtime environment does hold this info instead.
One advantage of this approach is that the connection information then can be managed by a server administrator instead of the application developer.
Not sure it meets your "no configuration outside project" requirement though.
First a bit of setup info:
I have a multi-tenant spring based application. The multi-tenant enabling library is an in-house developed tool where I work that I have to use. How it works is that there is an interceptor that sets in front of the servlet for the application. Upon a request hitting the servlet it loads a tenant specific spring config for "stuff" needed for the tenant specified on the url hitting the servlet.
As stated, the above is just a bit of background. Now to the issue/question:
What I want to do is to create, in the tenant configuration that is loaded, a value that I can use to inject where I need. So, is there a way I can just define a constant in a spring config and then reference it via #Value or #Resource in java code?
There will be no bean implementation behind it, it would just be purely and only a key/value that I can reference where needed in my application by name. So, something to the effect of:
<bean name="MyIdentifier">
<property name="theId" value="1001" />
</bean>
And then can I do something like?
#Value{MyIdentifier.theId}
String theId;
And have Spring be aware of and inject the value. The problem is that doing something like above Spring complains there is no implementation for the bean. Notice, no class specified for the bean. The reason I want to do this is every tenant config file will contain this bean, but the actual value will vary per tenant.
Is there some other type to use in the config to do this? If so, what schemas have to be on the config?
I am guessing I am either trying to make Spring do something not intended, or, this is so simple I cannot see it since I have stared at it too long. Anyway, thanks for the help.
You can not create bean tag in configuration file without providing class implementation. If you want to inject the value of fields, you have to go for properties file instead.
Create property file as below:
application.properties
theId=1001
Load property file in your configuration:
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="locations">
<list>
<value>classpath:application.properties</value>
</list>
</property>
</bean>
And access the property in your concrete class:
#Value("${theId}")
String theId;
I have the following properties declared in my spring-config.xml
<util:properties id="ldap" location="classpath:com/company/project/resources/some_configuration.properties"/>
Then I inject the values contained in the properties into some member variables using the spring #Value annotation in a service implementation (this approach is by far the cleanest/most elegant I have used in the implementation of the service and if possible I wouldn't want to change it).
The problem with this layout is that I have to modify the properties file and regenerate the application war for every deployment environment (quality, production, etc) and the server admins want to configure the some_configuration.properties path by JNDI (the application server is JBoss)
How can I pass the file location by jndi in the <util:properties /> tag?
Any help and suggestions would be appreciated
edit:
It would be nice if somebody comes out with a solution where I could do something like:
<util:properties id="ldap" location="jndi:url/some_configuration.properties"/>
Or similar
Old post, but this may be useful for others:
<jee:jndi-lookup id="ldapProps" jndi-name="your/jndi" resource-ref="true"/>
<util:properties id="ldap" location="file://#{ldapProps}/some_configuration.properties" />
I was looking something similar, this answer will help you using PropertyPlaceholderConfigurer: https://stackoverflow.com/a/3486315/439427.
HTH
In your case you will need to configure the PropertyPlaceholderConfigurer in your beans then you will just need to do the following change:
<util:properties id="ldap"
location="classpath:x/y/z/resources/${environment}.properties"/>
Where ${environment} will be set by an environment variable like this: -Denvironment=dev
I'm a big user of properties (with PropertyPlaceholderConfigurer) for making my application as "dynamic" as possible. Almost all the constants are defined as such. Anyway, I'm currently defining a default.properties which comes shipped with the default WAR.
In other environments (Acceptance/Production) I need to overwrite of the configurations. I'm doing this as following:
<bean id="propertyManager"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:com/company/default.properties</value>
<value>file:${COMPANY_PROPERTIES_LOCATION}\kbo-select-settings.properties</value>
</list>
</property>
</bean>
With this means I can use a promotable build for each of the environments.
HOWEVER, I do dislike the fact that I can't change any of my properties from inside WebSphere. Instead I have to go to each of the servers (we have 8 clustered) and change the properties accordingly. It would be a lot more user friendly if I could change those from inside WebSphere and just perform a restart afterwards...
Anyone has an idea on how I could do such a promotable build? I already define JNDI configuration for datasources/java mail/etc.
Thanks!
We solved this problem by using an extension on the property file for each environment (local, dev, int, tst ...) and each file contained specific values for those environments. The only addition you then require is a VM argument on the server to set -Druntime.env=X.
Your lookups in your config file will then look like this
<bean id="propertyManager"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:com/company/default.properties.${runtime.env}</value>
<value>file:${COMPANY_PROPERTIES_LOCATION}\kbo-select-settings.properties</value>
</list>
</property>
</bean>
Of course this only works if you have fairly static environments, as it still doesn't lend itself to changing it at runtime, but it does makes promotion of the application dead simple. If you want to be able to change the values without redeploying your application, you will have to have them stored outside your application, which you already seem to be doing for the kbo-select-settings.properties
One potential issue is that you are hardcoding the location of your properties file. You could specify the location of the properties file as a JNDI resource and falling back on the defaults specified on the classpath:
<!-- try to lookup the configuration from a URL, if that doesn't work, fall back to the properties on the classpath -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<bean class="org.springframework.core.io.UrlResource">
<constructor-arg>
<jee:jndi-lookup
jndi-name="url/config"
default-value="file:///tmp" /> <!-- dummy default value ensures that the URL lookup doesn't fall over if the JNDI resource isn't defined -->
</constructor-arg>
</bean>
</property>
<property name="properties">
<bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:com/company/default.properties</value>
</list>
</property>
</bean>
</property>
<property name="ignoreResourceNotFound" value="true"/>
</bean>
That way you can specify different file names for different environments using the WAS console in Resources > URL > URLs by creating a resource with the JNDI-name "url/config" and pointing it to the correct file (file:///your/path/to/properties).
As an alternative solution, if you want to manage individual properties through the console, you instead of using the PropertyPlaceholderConfigurer you could use jee:jndi-lookup to get values from the web.xml env-entries (which you can manage using the WAS console). See this answer
If the configuration is in the EAR file then I know of no simple way to propogate changes without backdoor cheats or re-deploying the app.
I think that configuration, espcially that which changes when you promote the app should not be in the application.
One approach is described here by Keys Botzum,
Note that you can actually propogate files that are not part of any particular application out to nodes using standard WebSphere synchronisation.
Another option is to use a database for config. These days poppin XML into a DB such as DB2 is not very hard.
Adding a URL resource that points to your config files to your websphere servers and then looking that up in your application is a viable way to go. You can then configure the url to point to a central location where all the configuration files are managed - if you use svn and your svn has read-only access you could even directly read them from svn (via http).
Spring has some built in facilities for this, and it also means you can priorities various config files.
For more information take a look at how-to-differentiate-between-test-and-production-properties-in-an-application
The way that I have dealt with this is to use property values on the JVM's but then reference them to a WebSphere variable that is defined at the cluser or cell level. For example, say you want a value called value1 set in param1 in your spring configuration you would do the following:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />
And then something like as follows do reference the variable:
<bean id="id" class="com.blah.class">
<property name="value1" value="${param1}" />
</bean>
Then within your tests you can setup your tests as follows:
/**
* #see org.springframework.test.AbstractSingleSpringContextTests#prepareApplicationContext(org.springframework.context.support.GenericApplicationContext)
*/
#Override
protected void prepareApplicationContext(GenericApplicationContext context) {
System.setProperty("param1", "myvalue");
}
Then from within the websphere configuration, if you create a JVM variable and link it to the WebSphere variable you only need to change the WebSphere variable and it will automatically update all the JVM variables on each machine.
To do this, create a JVM variable called:
param1
with a value of ${webspherevar.param1}
And then create a WebSphere variable called:
webspherevar.param1
That contains whatever the value you need to put in it. This allows you to then not have to ship around the values for each environment and they can be instead loaded into the environment and just used.
I hope this helps.