OSGi bundle read config properties - spring

I have config.properties in my OSGi bundle. but the OSGi bundle can not read it.
Application context refresh failed (OsgiBundleXmlApplicationContext(bundle=dao, config=osgibundle:/META-INF/spring/*.xml))
org.springframework.beans.factory.BeanInitializationException: Could not load properties; nested exception is java.io.FileNotFoundException
I am using Spring to read the config.properties
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="config.properties" />
</bean>
It seems like the OSGi only reads the .xml file.
Does someone has any idea?

You have to specify the correct resource for your value property.
There are some built in implementations, like:
ClassPathResource: value="classpath:/META-INF/config.properties"
FileSystemResource: value="file:C:/foobar/config.properties"
If you want to place the file outside the library you can use a system property (e.g. -DpropertyFile=C:/loremIpsum/config.properties) to specify the path, like
value="file:${propertyFile}"
since Spring 3.0.? even with default value
value="file:${propertyFile:C:/foobar/config.properties}"
(Have a look at your OSGi framework on how to set a system property. I am also not sure if the ClassPathResource works well / is recommended in OSGi environments.)

Related

Blueprint/Spring can't find 'classpath:path/to/file.ext' resource having moved project from Talend 6.5.1 to 7.1.1

In a Talend ESB (SE) project, I have a bean instantiated in the "Spring" configuration using a route resource.
In version 6.5.1 the following (used as a parameter) works fine.
<bean class="java.lang.String">
<constructor-arg>
<bean class="org.springframework.util.FileCopyUtils" factory-method="copyToByteArray" >
<constructor-arg value="classpath:query/sqlQuery.sql" type="java.io.InputStream" />
</bean>
</constructor-arg>
</bean>
but this doesn't for in my Talend 7.1.1 project. It seems to be unable to find the resource. I've looked in the created .kar file, and the resource is in the project .jar in the query folder.
[EDIT] It appears that Talend 7.1.1 encloses the "Spring" configuration in a <blueprint> element, which perhaps has change the way in which this functions.
I presume that something has changed in the way Talend packages the route, or in the way that the Spring xml is interpreted. Camel has no problem finding resources, for example from("sql:classpath:query/sqlQuery.sql"), but the "Spring" classpath search seems not to be able to find them.
I've tried substituting classpath*: for the straight classpath in the parameter as that had been suggested in some of the answers I'd seen to "resource not found" questions, but this didn't seem to be valid and was interpreted as a straight filename.
Am I doing something wrong with the classpath declaration? Is there another way of setting a spring/blueprint bean property with the contents of a resource file?
I've also tried explicitly declaring a ClassPathResource bean and it claims the resource does not exist when using the getInputStream() method, despite the fact I can see it if I open up the contained jar file.
Has the wrapping of the created feature in Maven terms (from Talend 7) had some impact on the classpath I need to use?

reflect property file changes in osgi bundle without restarting Karaf Server

How can i configure my Karaf Server in such a way that whenever there is a property file change, i should not restart my server for getting those changes in staead it should atomatically detect thos changes. I deploying my bundle in osgi Karaf Server. For loading property file i am using below configuration in my camel context.
<bean
class="org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer"
id="properties">
<property name="locations">
<list><value>file:etc/app/properties/env/env.properties</value>
<value>file:etc/vrol/security/ssl.properties
</value></list></property></bean>
You are currently not using an OSGi mechanism to load the property file. As far as I know you can only achieve this by switching from spring to blueprint.
In blueprint you can define a config like this:
<cm:property-placeholder persistent-id="myconfig" update-strategy="reload" >
</cm:property-placeholder>
This will load the config from etc/myconfig.cfg and will reload the blueprint context when the config changes.

Tomcat vs Jetty JNDI Lookup

I use Spring to configure my Java Web App and in my Spring configuration I obtain a datasource via JNDI for Jetty as follows:
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/myDataSource" />
but this won't work with Tomcat. With Tomcat I have to do this:
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/myDataSource" />
Whats the best way to solve this? I am already using JNDI as a way to externalize configuration, so I can't externalize my externalized configuration! At the same time I absolutely loath the idea of having two separate Spring configuration files. HELP!!!
I found an answer here, but I thought it was a bit complicated, but it did give me the idea to use the very cool ServerDetector class that blogger had found.
Once I can dynamically figure what type of server I am running in, I was able to use the Spring expression language to do the rest of the work:
<jee:jndi-lookup id="myAppDataSource"
jndi-name="#{ (AppServerType == 'Jetty' ? 'jdbc/' : 'java:comp/env/jdbc/') +
'myAppDataSource' }" />
Easy!
After some experimenting, I figured out I could just force Jetty to use the same JNDI path as Tomcat. The following snippet is from my jetty-env.xml file:
<New id="myDataSource" class="org.mortbay.jetty.plus.naming.Resource">
<!-- We MUST specify the entire JNDI path here to force compliance with the Tomcat/J2EE convention -->
<Arg>java:comp/env/jdbc/myDataSource</Arg>
<Arg>
<New class="com.atomikos.jdbc.nonxa.AtomikosNonXADataSourceBean">
<Set name="uniqueResourceName">sbeDatabase</Set>
...............
</New>
</Arg>
</New>
Not sure if this is ideal, but it works.
Update:
It works if you put your jetty-env.xml file inside the WAR...but for whatever reason, one you move this configuration outside the WAR and into a context fragment file in Jetty's "contexts" directory then it throws an exception:
Check it out: http://jira.codehaus.org/browse/JETTY-273
The cleanest way to do it is to configure your configuration. ;)
Use a Spring property place holder. See
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-factory-placeholderconfigurer
The basic idea is that you just put a placeholder in your spring config with a property, and then it reads matching property from a properties file. You generate the properties file in your build process. Ive seen it done where the build tool (ant) reads an environment variable and then creates a properties file appropriate for the environment based of a skeleton file populated with tokens.

Loading Liferay Properties from Spring IoC container (to get jdbc connection parameters)

I'm developing some portlets for Liferay Portal 5.2.3 with bundled tomcat 6.0.18 using Spring IoC container.
I need to map the User_ table used in Liferay database to an entity with Hibernate, so I need to use two different dataSources to separate the liferay db from the db used by portlets.
My jdbc.properties has to hold all connection parameters for both databases: no problem for the one used by portlets, but I am having issues determining which database uses liferay to hold its data.
My conclusion is that i should have something like this:
liferayConnection.url=jdbc:hsqldb:${liferay.home}/data/hsql/lportal
in order to get the database url dynamically loaded, according to Liferay properties found in portal-ext.properties. (Or, better, load the whole portal-ext.properties and read database properties from there).
The problem is that the placeholder is not resolved:
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'liferayDataSource' defined in class path resource [WEB-INF/applicationContext.xml]: Could not resolve placeholder 'liferay.home'
To dodge this problem I tried to load explicitly portal-ext.properties with a Spring bean:
<bean id="liferayPropertiesConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="../../portal-ext.properties"/>
but no luck: liferay.home is not resolved but there aren't other errors.
How can I resolve the placeholder defined by Liferay? Thanks
You can use PropsUtil class (from Liferay) to get values of portal-ext.properties.
String value = PropsUtil.get("key");
For loading properties files from an applicationContext.xml file I usually use the PropertiesFactoryBean specifying the location property with a the name of the file located in the classpath, like this:
<bean name="myHibernateProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location">
<value>classpath:hibernate.properties</value>
</property>
</bean>
Make sure the properties files are in a folder/package that is in the classpath.
You can call PropsUtil using SpringEL. for example:
#{T(com.liferay.portal.kernel.util.PropsUtil).get('liferay.home')}
I haven't tried exactly this. but you could load the liferay properties that you need with the following:
<util:properties id="liferayProps">
<prop key="liferay.home">#{T(com.liferay.portal.kernel.util.PropsUtil).get('liferay.home')}</prop>
</util:properties>

Where to store database passwords in a spring application or use JNDI?

Seems like a simple task. I have a webapp which requires a database connection. I'd like to be able to drop an updated .war file on this app server and load a new version without having to re-edit an applicationConfig.xml file to specify the database connection parameters for production.
Is using the container to setup the data source and then referencing it from JNDI the preferred way to go? I think it is cleaner having it all defined in the spring .xml file, but I can't come up with a clean way to allow the production password to be set only once as we roll out new versions.
So, how do you specify your database connection information in a spring application so that you can upgrade it without having to re-edit the files?
If you use JNDI, how do you handle setting up of your tests since the JNDI is not going to be available outside of the container?
Thanks!
The typical way to externalize database connection properties is to store them in a .properties file and load using <context:property-placeholder .../> . Then you can have different .properties files for testing and production.
If you choose JNDI, you can use a Spring's mock JNDI support for testing.
One approach is for your Spring configuration file to be composed of fragments related to specific layers in your application.
One such fragment could contain your DataSource defintion. For production, this fragment would use a jee:jndi-lookup. And then for test, have a different fragment would use a DriverManagerDataSource ?
Update:
If you want to change the datasource after deployment, then you can use this technique, along with changing the which datasource is injected into your other beans using a PropertyPlaceholderConfigurer as explained in an old post I wrote
eg:
<bean class="foo.bar.SomeClassNeedingDataSource"">
<property name="dataSource" ref="${the.datasource.to.inject}" />
</bean>
<jee:jndi-lookup id="jndiDataSource" ... />
<bean id="driverManagerDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
...
</bean>
# the properties file
the.datasource.to.inject = jndiDataSource
#the.datasource.to.inject = driverManagerDataSource

Resources