001package systems.dmx.core.impl; 002 003import systems.dmx.core.service.Transactional; 004import systems.dmx.core.storage.spi.DMXTransaction; 005 006import com.sun.jersey.api.model.AbstractMethod; 007import com.sun.jersey.spi.container.ContainerRequest; 008import com.sun.jersey.spi.container.ContainerRequestFilter; 009import com.sun.jersey.spi.container.ContainerResponse; 010import com.sun.jersey.spi.container.ContainerResponseFilter; 011import com.sun.jersey.spi.container.ResourceFilter; 012import com.sun.jersey.spi.container.ResourceFilterFactory; 013 014import java.lang.reflect.Method; 015import java.util.ArrayList; 016import java.util.List; 017import java.util.logging.Logger; 018 019 020 021class TransactionFactory implements ResourceFilterFactory { 022 023 // ---------------------------------------------------------------------------------------------- Instance Variables 024 025 private PersistenceLayer pl; 026 027 private Logger logger = Logger.getLogger(getClass().getName()); 028 029 // ------------------------------------------------------------------------------------------------- Class Variables 030 031 private static final ThreadLocal<DMXTransaction> threadLocalTransaction = new ThreadLocal(); 032 033 // ---------------------------------------------------------------------------------------------------- Constructors 034 035 TransactionFactory(PersistenceLayer pl) { 036 this.pl = pl; 037 } 038 039 // -------------------------------------------------------------------------------------------------- Public Methods 040 041 @Override 042 public List<ResourceFilter> create(AbstractMethod method) { 043 if (!method.isAnnotationPresent(Transactional.class)) { 044 return null; 045 } 046 // 047 logger.fine("### Adding transaction support to " + info(method)); 048 List<ResourceFilter> filters = new ArrayList(); 049 filters.add(new TransactionResourceFilter(method)); 050 return filters; 051 } 052 053 // ------------------------------------------------------------------------------------------------- Private Methods 054 055 private String info(AbstractMethod method) { 056 Method m = method.getMethod(); 057 return m.getDeclaringClass().getName() + "#" + m.getName() + "()"; 058 } 059 060 // ------------------------------------------------------------------------------------------------- Private Classes 061 062 private class TransactionResourceFilter implements ResourceFilter { 063 064 private AbstractMethod method; 065 066 private TransactionResourceFilter(AbstractMethod method) { 067 this.method = method; 068 } 069 070 @Override 071 public ContainerRequestFilter getRequestFilter() { 072 return new ContainerRequestFilter() { 073 074 @Override 075 public ContainerRequest filter(ContainerRequest request) { 076 logger.fine("### Begining transaction of " + info(method)); 077 DMXTransaction tx = pl.beginTx(); 078 threadLocalTransaction.set(tx); 079 return request; 080 } 081 }; 082 } 083 084 @Override 085 public ContainerResponseFilter getResponseFilter() { 086 return new ContainerResponseFilter() { 087 088 @Override 089 public ContainerResponse filter(ContainerRequest request, ContainerResponse response) { 090 DMXTransaction tx = threadLocalTransaction.get(); 091 boolean success = response.getMappedThrowable() == null; // ### TODO: is this criteria concise? 092 if (success) { 093 logger.fine("### Comitting transaction of " + info(method)); 094 tx.success(); 095 } else { 096 logger.warning("### Rollback transaction of " + info(method)); 097 } 098 tx.finish(); 099 return response; 100 } 101 }; 102 } 103 } 104}