Hi all.
I have a standard RESTful application (Jersey) which must call the equivalent WebService (Axis) on same TomCat server , both applications being mixed together (the basic Axis example plus the tiny REST stuff), the whole stuff linked with Spring.
My problem is: REST call works, Axis call works, call of a REST HelloWorld which calls the same under Axis works, call of Hibernate template from an autonomous application with Spring set Hibernate DAO works, BUT when I attempt to call an Axis method from a REST method with a call to Hibernate it fails since Hibernate template DAO is no longer injected, in fact when REST application calls Axis then Spring literally doesn't work any longer on Axis parts.
Would you have some ideas, kind of use a Filter for REST instead of a Servlet perhaps ? I would like to understand why Axis part of my web application becomes unable to use Spring when it is called by a REST client.
Code excerpts & interesting configs, all within the same WebApp :
REST client Code:
// Appel from WS Axis
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress(new URL(WS_URL));
call.setOperationName("findAllUsersCreatedAtDate" );
String newDate = date.replace('/', '_');
Object[] params = {newDate};
Object result = call.invoke(params); <<< It fails here
------------------
Code of called WS Axis service:
public class IpeUserServiceWS
{
private IpeService service = new IpeServiceImpl(); <<< Hard coded since not initialized by Spring
public String findAllUsersCreatedAtDate(String date)
{
String wsResult = "Users created at date " + date + ": ";
String newDate = date.replace('_', '/');
List<User> users = service.findAllUsersCreatedAtDate(newDate); <<< We go inside here for service implementation
------------------
Implementation code of called service:
public class IpeServiceImpl implements IpeService
{
private IpeDao ipeDao = new IpeDaoHibernateImpl(); <<< Hard-coded since not initialized by Spring
@Override
public List<User> findAllUsersCreatedAtDate(String date)
{
return ipeDao.findAllUsersCreatedAtDate(date); <<< Then inside here for Hibernate DAO
------------------
Implementation code of called DAO:
public class IpeDaoHibernateImpl extends HibernateDaoSupport implements IpeDao
{
@SuppressWarnings("unchecked" )
@Override
@Transactional
public List<User> findAllUsersCreatedAtDate(String date)
{
User user = new User();
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy" );
try
{
user.setCreated(sdf.parse(date));
} catch (ParseException e)
{
e.printStackTrace();
}
List<User> users = getHibernateTemplate().findByExample(user); <<< Final failure here for Spring didn't initialized HibernateTemplate, but it does for autonomous application
------------------
web.xml config:
<web-app>
<display-name>IPE User Service WS+RESTful Application</display-name>
<!-- Just prevent Spring of complaining -->
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>winweb_ipeuserservice_rest_axis</param-value>
</context-param>
<!-- Location of log4J configuration file -->
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>WEB-INF/log4j.properties</param-value>
</context-param>
<!-- Location of Spring configuration file -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/SpringApplicationContext.xml</param-value>
</context-param>
<!-- Necessary for Spring -->
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.apache.axis.transport.http.AxisHTTPSessionListener</listener-class>
</listener>
<servlet>
<servlet-name>AxisServlet</servlet-name>
<display-name>Apache-Axis Servlet</display-name>
<servlet-class>
org.apache.axis.transport.http.AxisServlet
</servlet-class>
</servlet>
<servlet>
<servlet-name>AdminServlet</servlet-name>
<display-name>Axis Admin Servlet</display-name>
<servlet-class>
org.apache.axis.transport.http.AdminServlet
</servlet-class>
<load-on-startup>100</load-on-startup>
</servlet>
<servlet>
<servlet-name>SOAPMonitorService</servlet-name>
<display-name>SOAPMonitorService</display-name>
<servlet-class>
org.apache.axis.monitor.SOAPMonitorService
</servlet-class>
<init-param>
<param-name>SOAPMonitorPort</param-name>
<param-value>5001</param-value>
</init-param>
<load-on-startup>100</load-on-startup>
</servlet>
<servlet>
<servlet-name>Jersey RESTful Application</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.winweb.ipe.rest.IpeUserServiceRESTfulApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/servlet/AxisServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>*.jws</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>SOAPMonitorService</servlet-name>
<url-pattern>/SOAPMonitor</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Jersey RESTful Application</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<!-- uncomment this if you want the admin servlet -->
<!-- <servlet-mapping> <servlet-name>AdminServlet</servlet-name> <url-pattern>/servlet/AdminServlet</url-pattern>
</servlet-mapping> -->
<session-config>
<!-- Default to 5 minute session timeouts -->
<session-timeout>5</session-timeout>
</session-config>
<!-- currently the W3C havent settled on a media type for WSDL;
http://www.w3.org/TR/2003/WD-wsdl1 [...] ietf-draft
for now we go with the basic 'it's XML' response -->
<mime-mapping>
<extension>wsdl</extension>
<mime-type>text/xml</mime-type>
</mime-mapping>
<mime-mapping>
<extension>xsd</extension>
<mime-type>text/xml</mime-type>
</mime-mapping>
<welcome-file-list id="WelcomeFileList">
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jws</welcome-file>
</welcome-file-list>
</web-app>
------------------
Spring config:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/sch [...] ns-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/sch [...] xt-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/sch [...] tx-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/sch [...] ">
<!-- For autowire annotations -->
<context:annotation-config />
<context:component-scan base-package="com.winweb.ipe" />
<!-- DO NOT FORGET the @Transactional annotations in your code -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- Inject the logger -->
<bean id="logger"
class="org.springframework.beans.factory.config.CommonsLogFactoryBean">
<property name="logName" value="log" />
</bean>
<!-- JPA configuration stuff -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<!-- DataBase related parameters -->
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.connection.driver_class">org.gjt.mm.mysql.Driver</prop>
<prop key="hibernate.connection.url">jdbc:mysql://localhost/intuit_ipe</prop>
<prop key="hibernate.connection.username">intuit_user</prop>
<prop key="hibernate.connection.password">intuit</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.bytecode.use_reflection_optimizer">false</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>com.winweb.ipe.model.User</value>
</list>
</property>
<!-- <property name="configLocation" value="classpath:/hibernate.cfg.xml"
/> -->
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
<property name="namingStrategy" ref="namingStrategy" />
</bean>
<bean id="namingStrategy" class="org.hibernate.cfg.ImprovedNamingStrategy" />
<!-- Inject here the relevant persistence implementation to be used in service -->
<!-- <bean id="ipeServiceWS" class="com.winweb.ipe.ws.IpeUserServiceWS">
<property name="service"> <ref local="ipeService" /> </property> </bean> -->
<!-- Inject here the relevant DAO to be used in service implementation -->
<bean id="ipeService" class="com.winweb.ipe.dal.IpeServiceImpl">
<property name="ipeDao" ref="hibernateDAO" />
</bean>
<bean id="hibernateDAO" class="com.winweb.ipe.dal.dao.IpeDaoHibernateImpl">
<property name="hibernateTemplate" ref="hibernateTemplate" />
</bean>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
<property name="jdbcExceptionTranslator" ref="jdbcExceptionTranslator" />
</bean>
<bean id="jdbcExceptionTranslator"
class="org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator" />
<!-- Don't forget transactional context or DB inserts won't ever occur since
no commit -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="transactionalContext"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref local="transactionManager" />
</property>
<property name="proxyTargetClass" value="true" />
<property name="target">
<ref local="ipeService" />
</property>
<property name="transactionAttributes">
<props>
<prop key="findUser">PROPAGATION_REQUIRED</prop>
<prop key="createUser">PROPAGATION_REQUIRED</prop>
<prop key="deleteAllUsers">PROPAGATION_REQUIRED</prop>
<prop key="findAllUsers">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
</beans>
------------------
Test client to call Axis works:
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress(new URL(WS_URL));
call.setOperationName(new QName("HelloWorldWS", "sayHello" ));
Object[] params = {"Message from WS test client"};
Object result = call.invoke(params);
System.out.println("Result of WS test is: " + result);
------------------
Populate test of DB which uses Spring to configure DAO works:
public class LocalPopulateTest extends TestCase
{
private static final String SPRING_CONFIG_FILE = "C:/Developpement/Java/eclipse/workspace/WinWeb WS-REST/resources/axis_plus_rest/WEB-INF/classes/SpringApplicationContext.xml";
private IpeService service; // Initialized by Spring's bean "ipeService"
// Clear the local DataBase
public void testClearAll()
{
service.deleteAllUsers();
List<User> users = service.findAllUsers();
assertEquals(true, users.isEmpty());
}
// Populate a local DataBase
public void testPopulate()
{
User user = new User();
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy" );
try
{
user.setCreated(sdf.parse("12/31/2015" ));
} catch (ParseException e)
{
e.printStackTrace();
}
service.createUser(user);
List<User> users = service.findAllUsers();
assertEquals(1, users.size());
}
protected void setUp() throws Exception
{
super.setUp();
ApplicationContext ctx = new FileSystemXmlApplicationContext( SPRING_CONFIG_FILE );
service = ( (IpeService) ctx.getBean( "ipeService" ) );
}
protected void tearDown() throws Exception
{
super.tearDown();
}
public static void main(String[] args)
{
junit.swingui.TestRunner.run(LocalPopulateTest.class);
}
}
------------------
So Spring doesn't work to inject the Hibernate DAO only when Axis is called from REST.
Ideas? Transform REST Servlet into a Filter maybe?