Spring session with JDBC integration - spring

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.

Related

Programatically set v$session program property

I found some answers on the problem but none that i could make work in my case. My problem is that I load a datasource from my JBoss configuration with spring:
<xa-datasource jndi-name="java:jboss/jdbc/oracleDatasource" pool-name="jdbc/oracleDatasource" enabled="true">
<xa-datasource-property name="URL">
jdbc:oracle:thin:#URL:1522:SID
</xa-datasource-property>
<xa-datasource-property name="connectionProperties">
v$session.program=MyAPP
</xa-datasource-property>
<driver>oracle-jdbc</driver>
The spring loading is made as follows:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:jboss/jdbc/oracleDatasource"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
As you can see, I have set the v$session.program property in JBoss, it works well.
The problem is that i have several applications (war) that can be deployed on the same JBoss server, using this configuration. What I want to do in this case is to have each of my application to have its own name written in the v$session.program property.
So basically, i would like to be able to load the same datasource on each app but to have each of them using its own name to log the program property in oracle DB. Is it possible or do I have to have one datasource for each application hosted?
The only thing you need it to intercept each call of getConnection from connection pool.
You must obtain a real Oracle connection - not a proxy - and call the setClientInfo on 12c or setEndToEndMetrics in older versions to set the action / client / module identification.
An example see here.
Also note that the use of dbms_application_info for this same purpose works as well, but this produces a one server roundtrip too much. The setClientInfo doesn't produce server call, but stores this information for the next statement execution (which is the preformance saving approach).
Also note that to use this feature, your driver must match perfectly with your database - the strange exeptions you can see while setting teh client info are in most cases caused by the incompatibility of teh JDBC driver and the RDBMS.
If putting this information into v$session.module or v$session.client_info is an option, you can do using Java code.
All you need to do is call dbms_application_info.set_module() or dbms_application_info.set_client_info() after your Java code obtained the connection from the datasource.
Something like this:
Connection conn = ... // get connection from the DataSource
CallableStatement cstmt = conn.prepareCall("{call dbms_application_info.set_client_info(?)}");
cstmt.setString(1, "Some interesting information");
cstmt.execute();

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.

how to get XADatasource using JNDI look up for Atomikos Transaction Management

I am configuring Atomikios TM API with my Spring Application to achieve global transaction. As Atomikios require XADatasource to work, so I have done JNDI look up to get the same. But, unfortunately I am getting following errors while doing the look up.
Object of type [class com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource] available at JNDI location [jdbc/cuds] is not assignable to [javax.sql.XADataSource]
<jee:jndi-lookup id="dataSourceCu" jndi-name="jdbc/cuds" cache="true" resource-ref="true" lookup-on-startup="true" expected-type="javax.sql.XADataSource" />
<jee:jndi-lookup id="dataSourceGodb" jndi-name="jdbc/pushpullds" cache="true" resource-ref="true" lookup-on-startup="true" expected-type="javax.sql.XADataSource" />
I am using Spring 3.0/ hibernate with WebSphere 7.0.Where I am doing wrong. Please help me. Thanks.
The data source configured under jdbc/cuds is not an XADataSource but a normal one. You need to change the data source configuration in WebSphere (I have no idea how to do this).
However since you're on WebSphere which has it's own transaction manager there really is no need for configuring Atomikios. You can either use
<tx:jta-transaction-manager>
or org.springframework.transaction.jta.JtaTransactionManager / org.springframework.transaction.jta.WebSphereUowTransactionManager but the data source still needs to be XA.
XADataSource defines a contract between a JDBC provider and the application server and can only be used in that context. The DataSource object that you get when looking up the data source via JNDI in your application will never implement the XADataSource interface, even if the underlying data source is configured to support XA.
If you want to use your own transaction manager, then you would also have to manage the data sources yourself. Note that personally I wouldn't do that and strongly advice to use WebSphere's transaction manager instead. The reason is that distributed transactions involve lots of subtleties (e.g. recovery and in-doubt transactions) and it is unlikely that setting up a transaction manager inside an application would achieve the same level of robustness as WebSphere's transaction manager.

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