Pont entre REST et WS - Java - Programmation
Marsh Posté le 12-04-2011 à 16:30:02
un problème d'encodage de l'URL peut etre ? (qui fait que struts se vautre, et donc les beans ne sont pas peuplés ?)
t'as essayé de recup l'URL et de la copier/coller dans un web browser pour voir si la requete est dépilée correctement coté Serveur ?
Marsh Posté le 18-03-2011 à 03:33:03
Salut tous.
J'ai une application RESTful normale (Jersey) qui doit appelle le WebService (Axis) équivalent sur le même serveur Tomcat, les 2 applications sont mixées ensemble (l'exemple modifié de base Axis avec les petits ajouts REST), le tout lié avec Spring.
Mon problème : l'appel de REST fonctionne, l'appel d'Axis fonctionne, l'appel d'un HelloWorld REST qui appelle le même sous Axis fonctionne, l'appel de fonctions Hibernate depuis une application autonome avec le DAO établi par Spring fonctionne, mais quand j'essaie d'appeler une fonction Axis depuis une méthode REST avec un appel à Hibernate ça se vautre car mon DAO Hibernate n'est plus injecté, en fait quand l'application REST appelle Axis littéralement Spring ne fonctionne plus sur la partie Axis.
Vous auriez des idées, genre utiliser un Filter peut être ? Je voudrais comprendre pourquoi la partie Axis de mon application Web devient incapable d'utiliser Spring quand c'est un client REST qui l'appelle.
Bouts de codes et configs intéressants, tout est dans la même WebApp :
Code client REST :
// Appel du 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); <<< Ca vautre là dessus
------------------
Code service WS Axis appelé :
public class IpeUserServiceWS
{
private IpeService service = new IpeServiceImpl(); <<< Codé en dur car pas initialisé par Spring
public String findAllUsersCreatedAtDate(String date)
{
String wsResult = "Users created at date " + date + ": ";
String newDate = date.replace('_', '/');
List<User> users = service.findAllUsersCreatedAtDate(newDate); <<< On va là dedans pour l'implémentation du service
------------------
Code d'implémentation du service appelé :
public class IpeServiceImpl implements IpeService
{
private IpeDao ipeDao = new IpeDaoHibernateImpl();<<< Codé en dur car pas initialisé par Spring
@Override
public List<User> findAllUsersCreatedAtDate(String date)
{
return ipeDao.findAllUsersCreatedAtDate(date); <<< Puis là dedans pour le DAO Hibernate
------------------
Code d'implémentation du DAO appelé :
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); <<< Vautrage final ici car Spring n'a pas initalisé HibernateTemplate, mais il le fait pour l'application autonome
------------------
Config web.xml :
<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>
------------------
Config Spring :
<?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="classpathhibernate.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>
------------------
Le client de test pour appeler Axis fonctionne :
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);
------------------
Le test de peuplement de la DB qui utilise Spring pour configurer le DAO Hibernate fonctionne :
public class LocalPopulateTest extends TestCase
{
private static final String SPRING_CONFIG_FILE = "CDeveloppement/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);
}
}
------------------
Mais donc Spring ne fonctionne PAS pour injecter mon DAO Hibernate uniquement dans le cas où Axis est appelé depuis REST.
Des idées ? transformer la WebApp REST en Filter peut être ?
---------------
When injustice becomes law, resistance becomes duty (Thomas Jefferson)