Sunday, January 25, 2009

Spring Blaze Integration 1.0 M1 with Hibernate

I have a reference project that I have been using to stitch the different Spring/Hibernate/Flex/AIR technologies together.

Well today, I wanted to upgrade to Spring3 and look at the new Spring BlazeDS Integration. You can find all of the information about the Spring BlazeDS integration here.

This particular project used as Flex 3 front end, communicating to a Tomcat/Spring2.5/SpringJDBC to MySql database. Today I decided to upgrade the application to use Spring3 and Hibernate 3.3.1 which I did not anticipate being a big project - but I was wrong. Well ok, it was not a big project but it was bigger than I expected it to be.

If you following along with the sample application from the Spring/BlazeDS integration it goes really well.

However when you go to integrate Hibernate and use the OpenSessionInViewFilter things get a little tricky.

Conventional Spring wisdom would have us use the ContextLoaderListener to load the Spring context much like the following:

    <context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/main-application-config.xml</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>



However, when I did that the MessageBroker complained that the ServletConfig was null so I decided I would initialize the Spring application context as the Spring BlazeDS Integration suggested. However - when I did that, the OpenSessionInView Filter complained that the web application context was not initialized.

So I was between the proverbial rock and a hard place.

I spent some time looking through the code to see how I could 'fix' this problem. Then it occurred to me that perhaps it was not a problem with the code. Maybe, this could fixed with a different configuration. The OpenSessionInView filter just needs information about the Hibernate Session, SessionFactory, DataSource, etc. It does not need to know about the MessageBroker and the MessageBroker does not need the Hibernate information.

So instead of trying to fix the code, I looked at how to fix my configuration.

I looked at my application config, and removed all of the elements that were related to Blaze integration and created a separate configuration for the servlet to load. I now have the ContextLoaderListener initialize part of the application config and the servlet the other part.

Here is a portion of the web.xml file configuration:

    <context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/main-application-config.xml</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>


<filter>
<filter-name>hibernate-session</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>sessionFactory</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hibernate-session</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<servlet>
<servlet-name>redpointnotes</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/blaze-config.xml</param-value>
</init-param>

<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>redpointnotes</servlet-name>
<url-pattern>/spring/*</url-pattern>
</servlet-mapping>




The blaze-config.xml file looks like the following:
  <bean id="mySpringManagedMessageBroker" 
class="org.springframework.flex.messaging.MessageBrokerFactoryBean" />

<bean id="flexMessageBroker" abstract="true">
<property name="messageBroker" ref="mySpringManagedMessageBroker" />
</bean>

<!-- bean id name is the name that will be exposed to Flex remoting as the destination name -->
<bean id="redpointNotesServiceDestination" parent="flexMessageBroker"
class="org.springframework.flex.messaging.remoting.FlexRemotingServiceExporter">
<property name="service" ref="notesService" />
</bean>

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

<!-- map request paths at /messagebroker to the BlazeDS MessageBroker -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>
/messagebroker/*=mySpringManagedMessageBroker
</value>
</property>
</bean>

<!-- dispatches requests mapped to a message broker -->
<bean class="org.springframework.flex.messaging.servlet.MessageBrokerHandlerAdapter" />




So by breaking up the configuration I was able to get around this 'chicken-n-egg' problem but I will still look to see if there is a more elegant way to handle this. If anyone has a better way of dealing with this, please post a comment so we can all benefit.

I hope this helps save someone some time.

No comments: