According to this thread : http://osdir.com/ml/java-tynamo-user/2012-04/msg00005.html, this is merely a COMMIT issue :).
In standard context, the transaction is deal by the Page that called the service. In REST approach, this job should be done by the service itself.
The idea is, indeed, to change your autodiscovered REST service into a real tapestry IOC one.
1 - Move it away from autodiscovery
Move it into service package (or anyone that allow Tapestry binding and not in rest autodiscovery package) :
- as Alejandro Scandroli advise it in per documentation : http://docs.codehaus.org/pages/viewpage.action?pageId=151847035#tapestry-resteasyguide-Contributesingletonresources
- and in this post : Class xxx does not contain a public constructor needed to autobuild when xxx become a Tapestry Service
2 - Extract Interface
Extract the interface, and put annotations on it + CommitAfter where you want to deal with transaction .
package com.myorg.mobile.pushup.services.user;
@Path("/user")
public interface IUserResource {
/**
* Lecture de tous les utilisateurs
*
* @return une List des utilisateurs existants
*/
@GET
@Produces("application/json")
List<User> getAllDomains();
/**
* Méthode d'enregistrement / MAJ d'un utilisateur.
*
* @param user
* l'utilisateur à créer
* @return
*/
@POST
@PUT
@Produces({ "application/xml", "application/json" })
@Consumes({ "application/xml", "application/json" })
@CommitAfter
Response registerOrUpdate(User user);
}
Delete annotation on implementation
package com.myorg.mobile.pushup.services.user.impl;
public class HibernateUserResourceImpl implements IUserResource {
/* (non-Javadoc)
*/
public List<User> getAllDomains() {
return session.createCriteria(User.class).list();
}
/* (non-Javadoc)
*/
Response registerOrUpdate(User user);
session.saveOrUpdate(user);
return Response.ok().build();
}
3 - Contribute it as a singleton Resource
public class AppModule {
public static void bind(ServiceBinder binder) {
binder.bind(IUserResource.class, HibernateUserResourceImpl.class);
}
/**
* Contributions to the RESTeasy main Application, insert all your RESTeasy
* singletons services here.
*/
@Contribute(javax.ws.rs.core.Application.class)
public static void configureRestResources(Configuration<Object> singletons,
IUserResource userResource) {
singletons.add(userResource);
}
}
4 - Advise annotate methods that they are transactionals
public class AppModule {
@Match("*Resource*")
public static void adviseTransactionally(
HibernateTransactionAdvisor advisor, MethodAdviceReceiver receiver) {
advisor.addTransactionCommitAdvice(receiver);
}
You may add another dependencies if you'd prefer to use JPATransactionAdvision instead of Hibernate one :
<dependency>
<groupId>org.tynamo</groupId>
<artifactId>tapestry-jpa-core</artifactId>
<version>2.0.1</version>
</dependency>
5 - Conclusion
This solution is working for me, but as far as I understand it, this is actually the only way to do it.
Alejandro > If you read those lines, please tell me if there is another (shortest) way, of I'm right :)