Initializing a sessionfactory after web application startup - spring

in common, hibernate sessionfactory is created in spring configuration file (eg spring-dao.xml) like;
<bean id="mySessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation">
<value>file:src/hibernate.cfg.xml</value>
</property>
</bean>
and then in dao,
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
in web.xml, we put the config file (spring-dao.xml) in contextConfigLocation;
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-dao.xml</param-value>
</context-param>
when the application is started, datasource is injected to all dao beans.
This was the summary, what my problem is, I do not want spring to connect to database on application startup. I have an admin(responsible for opening db connection after startup) and an admin applet working on remote machine, which communicates with web app servlet. database connection for web application should be opened if authentication is ok.
how can i achieve this goal?

Specify lazy-init="true" on the mySessionFactory bean and it will be initialized when your code tries to access it for the first time i.e. when the authentication is successful.

The solution was not to hard; Create a datasource with no parameters initially, and then setting values after admin credentials ok.
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- Connection properties. All should be ommitted. -->
</bean>
// code below is called after admin login
DataSource dS = context.getBean("dataSource");
dS.setUrl("...");
dS.setUserPass(adminPass);

Related

Exception Handling in Spring Framework JNDI

I have configured JNDI reference in spring-context.xml ,created JNDI in Websphere application server 7.5, this working fine, but if its database is down, I am not able to start the web application ,i am getting 500 uncaught servlet initialization exception .
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${reports_db_jndi_ref}"/>
</bean>
Could you please advise ? How to handle the exception or how to start the web application even though the database is down?
Set the lookupOnStartup property to false so that Spring returns a proxy to the datasource instead of the actual datasource. However if your application uses the datasource as part of the startup process e.g due to some dependency trying to connect to the database still the looup will occur. Change as follows
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${reports_db_jndi_ref}"/>
<property name="lookupOnStartup" value="false"/>
</bean>

Spring + JMS + ActiveMQ without dependency on ActiveMQ

I'm trying to build a MQ producer that sends a message to an ActiveMQ queue. The thing is that I don't want the implementation to be specific for ActiveMQ. I actually am doing the ActiveMQ sending in dev environment, and in production the application server will use something else. I'm planning to use Maven to create 2 profiles that will filter resources based on the given profile.
I started playing with JNDI, but I'm stuck... I tried a lot of options, but none are viable.
For now, my spring config xml is like this:
<jee:jndi-lookup id="mqConnectionFactory" jndi-name="java:comp/env/jms/mqConnectionFactory" />
<bean id="jmsJndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">org.apache.activemq.jndi.ActiveMQInitialContextFactory</prop>
<prop key="java.naming.provider.url">vm://localhost</prop>
</props>
</property>
</bean>
<bean id="ismeJmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="defaultDestination" ref="ismeJmsDestination"/>
<property name="connectionFactory" ref="mqConnectionFactory"/>
</bean>
<bean id="ismeJmsDestination" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="jmsJndiTemplate"/>
<property name="jndiName" value="dynamicQueues/FOO.BAR"/>
</bean>
mqConnectionFactory cannot be found because I didn't add it in JNDI. I don't know how to add it actually, as this is not a webapp, so no context.xml.
Can someone help me in the right direction?
Whatever broker implementation you chose, you need to have the corresponding client library in your classpath. The JMS API is just an API, you need an actual implementation to connect to the broker of your choice.
Say you want to connect to ActiveMQ in development and to whatever JMS implementation in production. You can isolate those two config in separate profiles and make the activeMQ dependency an optional dependency in Maven.

Multi-tenant webapp using Spring MVC and Hibernate 4.2.0.Final

I have developed a small webapp using and SpringMVC(3.1.3.RELEASE) and Hibernate 4.2.0.Final.
I'm trying to convert it to be a multi-tenant application.
Similar topics have been covered in other threads, but I couldn't find a definitive solution to my problem.
What I am trying to achieve is to design a web app which is able to:
Read a datasource configuration at startup (an XML file containing multiple datasource definitions, which is placed outside the WAR file and it's not the application-context or hibernate configuration file)
Create a session factory for each one of them (considering that each datasource is a database with a different schema).
How can i set my session factory scope as session? ( OR Can i reuse the same session factory ?) .
Example:
Url for client a - URL: http://project.com/a/login.html
Url for client b - URL: http://project.com/b/login.html
If client "a" make request,read the datasource configuration file and Create a session factory using that XML file for the client "a".
This same process will be repeating if the client "b" will send a request.
What I am looking, how to implement datasource creation upon customer subscription without editing the Spring configuration file. It needs to be automated.
Here is my code ,that i have done so far.
Please anyone tell me,What modifications i need to be made?
Please give an answer with some example code..I am quite new in spring and hibernate world.
Spring.xml
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.databaseurl}"
p:username="${jdbc.username}" p:password="${jdbc.password}" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
JDBC.properties File
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.dialect=org.hibernate.dialect.MySQLDialect
jdbc.databaseurl=jdbc:mysql://localhost:3306/Logistics
jdbc.username=root
jdbc.password=rot#pspl#12
hibernate.cfg.xml File
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<mapping class="pepper.logis.organizations.model.Organizaions" />
<mapping class="pepper.logis.assets.model.Assets" />
</session-factory>
</hibernate-configuration>
Thanks,
First create a table for Tenant with tenant_id and associate it with all users.Now, you can fetch this details while the user logs in and set it in session.
We are using AbstractRoutingDataSource to switch DataSource for every request on Spring Boot. I think it is Hot Swapable targets/datasource mentioned by #bhantol above.
It solves our problems but I don't think it is sound solution. I guess JNDI could be a better one than AbstractRoutingDataSource.
Wondering what you ended up with.
Here are some ideas for you.
Option 1) Single Application Instance.
It is somewhat ambitious to to this using what you are actually trying to achieve.
The gist is to simply deploy the same exact application with different context root on the same JVM. You can still tune the JVM as a whole like you would have if you had a truely multi-tenant application. But this comes at the expense of duplication of classes, contexts, local caching, start up times etc.
But as of today the Spring Framework 4.0 does not provide much of an multi-tenancy support (other than Hot Swapable targets/datasource) etc. I am looking for a good framework but it may be a wash to move away from Spring at this time for me.
Option 2) Multiple deployments of same application (more practical as of today)
Just have your same exact application deploy to the same application server JVM instance or even different.
If you use the same instance you may now need to bootstrap your app to pickup a DataSource based on what the instance should serve e.g. client=a property would be enough to pickup a **a**DataSource" or **b**DataSource I myself ended up going this approach.
If you have a different application server instance you could just configure a different JNDI path and treat things generically. No need for client="a" property because you have liberty to define your datasource differently with the same name.

How do I catch Spring errors when starting up a Tomcat webapp?

I have a webapp running in Tomcat which uses Spring for dependency injection. (It's a GWT application, but I don't think that makes much of a difference to the solution I'm looking for.)
My web.xml file is of the following format:
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Servlets -->
<servlet>
<servlet-name>dispatch</servlet-name>
<servlet-class>com.example.my.gwt.dispatch.DispatchServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatch</servlet-name>
<url-pattern>/my_gwt/dispatch</url-pattern>
</servlet-mapping>
... more servlets ...
</web-app>
One of the things my Spring configuration does is to connect to a databse via Hibernate:
<bean id="datasource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driver}" />
<property name="url"
value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>
<bean id="databaseSessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="datasource" />
<property name="packagesToScan">
<array>
<value>com.example.my.gwt.model</value>
</array>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
If the database is unavailable, this causes an org.h2.jdbc.JdbcSQLException to be thrown, so the Spring initialisation does not continue, so the rest of the webapp cannot be used. Navigating to the webapp's URL gives an HTTP 503 'Service Unavailable' error.
What I want to do is to catch that error and display a page to the user (when they first navigate to the app) explaining what the problem is likely to be and suggested fixes. How can I do this?
I have tried using a custom ContextLoaderListener class that delegates to the one in the XML above, but catches any exceptions. This allows me to catch the exception, but there is not much I can do - the web.xml is still pointing the user's request to a servlet that is not running after the Spring initialisation has failed. Is there any way that I can change the webapp config when I catch that exception, so that it doesn't try to load the servlets from the web.xml and perhaps changes the welcome file to point to a page about the error? Or is there any other way that I can make the webapp gracefully handle this exception?
Thanks
Basically you're asking if you can have a functioning web application after the web application fails to start up.
You could try configuring a 503 handler page and/or have a welcome page, not dependent on Spring, that checks for something in the application context that's set only on a good spin up. If it didn't spin up, the exception you've already captured could be placed into the app context.
Not sure if anything in the app, even web.xml-only resources, if Spring doesn't spin up, though.
You could add a Servlet Filter to your web app that would intercept all the requests to the Spring servlet and forward to your custom error page if the Spring initialization has failed.

Configuring Datasource in Spring 3.0

Hello guys I have configured a connection pool and JNDI resource in glassfish 2.1. I can get the Datasource via lookup method in my projects and everything works good. However I decided to try Spring framework and to use my existing connection pool.
In the Spring context file I have the following:
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/name" />
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
<bean id="dao" class="com.mycompany.mavenproject3.Dao">
<property name="simpleJdbcTemplate" ref="jdbcTemplate"/>
</bean>
When I deploy the project I get:
java.lang.IllegalArgumentException: 'dataSource' or 'jdbcTemplate' is required]
Is there anything else I have to configure in that file or in any other file in order to get the Datasource?
Presumably, com.mycompany.mavenproject3.Dao extends JdbcDaoSupport, but you're setting a property named simpleJdbcTemplate on it, leading me to believe that you've defined your own property to hold the template since that doesn't exist on Spring's implementation. It's therefore complaining at you because you're required to set either the dataSource property or the jdbcTemplate property of the JdbcDaoSupport object before using it, exactly like it's telling you. Change <property name="simpleJdbcTemplate"... to <property name="jdbcTemplate"....
If your DAO doesn't extend JdbcDaoSupport, then find what does and remove it or set its properties appropriately.
You can also call your datasource directly in your dao bean, don't need to do an another bean for jdbcTemplate. So your context file become something like this:
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/name" />
<bean id="dao" class="com.mycompany.mavenproject3.Dao">
<property name="dataSource" ref="dataSource"/>
</bean>
After you just have to extends JdbcDaoSupport spring class (in which contain the getter and setter of datasource) on your Dao class.

Resources