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

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>

Related

Spring session with JDBC integration

I am new in Spring Session and want to use embedded database to store session information. I follow all the steps in
http://docs.spring.io/spring-session/docs/current/reference/html5/guides/httpsession-jdbc.html using spring-session-jdbc of version 1.2.0.but using Spring-web of 3.2.4 only
The following error is shown repeatly:
Caused by: org.postgresql.util.PSQLException: ERROR: relation "spring_session" does not exist 'Position: 13
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2198)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1927)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:561)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:419)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:365)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:824)
at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:818)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:589)
... 21 more'
This issue already haunted me for days. Please help.
Here is the xml configuration
<bean class="org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessi‌​onConfiguration"/>
<jdbc:embedded-database id="dataSource02" type="H2">
<jdbc:script location="classpath:org/springframework/session/jdbc/schema-h2.sql"/>
</jdbc:embedded-database>
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource02"/>
</bean>
Your problem stems from the fact that you use multiple data sources, since the provided stacktrace includes PostgreSQL JDBC driver classes while you are configuring a secondary, embedded data source to storing sessions.
Spring Session configuration picks up your primary data source (PostgreSQL) and expects to find session tables there.
I'd suggest you to use your primary data source to store session data, but if you insist on having secondary/embedded data source for that purpose you need to override JdbcOperationsSessionRepository bean provided by JdbcHttpSessionConfiguration#sessionRepository with your own instance which is created using your secondary data source and its appropriate tra saction manager. Note that bean must be named sessionRepository in order to override one from JdbcHttpSessionConfiguration.

how to handle name not found exception in application-context.xml?

I am creating a spring project using Oracle and jboss server.
I have one bean in my application-context.xml.
<!-- Datasource for TaskManager -->
<jee:jndi-lookup id="tmTestDataSource"
jndi-name="test_datasource" expectedtype="javax.sql.DataSource"/>
<bean id="tmTestJdbcTemplate" name="TmTestJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="tmTestDataSource" />
</bean>
If the 'test_datasource' JNDI (one datasource.xml file in jboss deployment folder, which contains db credentials like url, uid, password) inside the file found deployment is successfull, but if the file is not there then the deployment is failing.
I want to handle this exception so that deployment should not fail.
how I can do this. Can anybody provide me any solution.
Thanks.
Instead of using dataSource args constructor, you can set it using setter method.
This way your bean will be created but its datasource will be null. So you will get NPE if you try to use it, but at least bean creation tree will not be stalled.

How to switch the datasource dynamically at runtime using AbstractRoutingDataSource?

Requirement:
I have the requirement like to switch the datasource at runtime after receiving the request.
I had read the blog about routing the datasource at runtime in spring3 using the class AbstractRoutingDataSource. Using that we can get the manually defined datasource key's at runtime.
Here in my project, datasources had configured in jetty-env.xml file. Now, i want to retrieve the Database name from DB in some tables like app_config.Using that DB name, i want to switch the database at runtime and also i want to pass the parameters to jetty-env.xml file.
Even I have a problem trying to set datasources from DB. You may like my solution (with annotations instead of xml). Spring 3.1.3 + Hibernate Configuration with annotations and with (Dynamic) AbstractRoutingDataSource
Taking a look at the "EDIT", you can set there any number of static datasources you want) or use them in xml.
Create a new subclass of DriverManagerDataSource, and autowire it a DAO to access table app_config.
Then for example override getUrl() method, and construct the url using a code dbNameParameter that allows to retrieve the database name from app config:
<bean id="parentDataSource"
class="org.springframework.jdbc.datasource.custom.MyDriverManagerDataSource"
abstract="true">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="username" value="sa"/>
</bean>
<bean id="goldDataSource" parent="parentDataSource">
<property name="dbNameParameter" value="gold"/>
</bean>
jetty-env.xml is not meant for that use and is better not used on this use case. It's better to put in jetty-env.xml only the datasource for where table app_config is.
You should store the tenant identifier in a ThreadLocal, supply data source list, configure an AbstractRoutingDataSource to select the data source at run time based on the tenant identifier.

OSGi bundle read config properties

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.)

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