001package de.deepamehta.core.impl; 002 003import de.deepamehta.core.service.DeepaMehtaService; 004import de.deepamehta.core.service.Transactional; 005import de.deepamehta.core.storage.spi.DeepaMehtaTransaction; 006 007import com.sun.jersey.api.model.AbstractMethod; 008import com.sun.jersey.spi.container.ContainerRequest; 009import com.sun.jersey.spi.container.ContainerRequestFilter; 010import com.sun.jersey.spi.container.ContainerResponse; 011import com.sun.jersey.spi.container.ContainerResponseFilter; 012import com.sun.jersey.spi.container.ResourceFilter; 013import com.sun.jersey.spi.container.ResourceFilterFactory; 014 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 DeepaMehtaService dms; 026 027 private Logger logger = Logger.getLogger(getClass().getName()); 028 029 // ------------------------------------------------------------------------------------------------- Class Variables 030 031 private static final ThreadLocal<DeepaMehtaTransaction> threadLocalTransaction = new ThreadLocal(); 032 033 // ---------------------------------------------------------------------------------------------------- Constructors 034 035 TransactionFactory(DeepaMehtaService dms) { 036 this.dms = dms; 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 " + method); 048 List<ResourceFilter> filters = new ArrayList(); 049 filters.add(new TransactionResourceFilter(method)); 050 return filters; 051 } 052 053 // ------------------------------------------------------------------------------------------------- Private Classes 054 055 private class TransactionResourceFilter implements ResourceFilter { 056 057 private AbstractMethod method; 058 059 private TransactionResourceFilter(AbstractMethod method) { 060 this.method = method; 061 } 062 063 @Override 064 public ContainerRequestFilter getRequestFilter() { 065 return new ContainerRequestFilter() { 066 067 @Override 068 public ContainerRequest filter(ContainerRequest request) { 069 logger.fine("### Begining transaction of " + method); 070 DeepaMehtaTransaction tx = dms.beginTx(); 071 threadLocalTransaction.set(tx); 072 return request; 073 } 074 }; 075 } 076 077 @Override 078 public ContainerResponseFilter getResponseFilter() { 079 return new ContainerResponseFilter() { 080 081 @Override 082 public ContainerResponse filter(ContainerRequest request, ContainerResponse response) { 083 boolean success = response.getMappedThrowable() == null; // ### TODO: is this criteria concise? 084 DeepaMehtaTransaction tx = threadLocalTransaction.get(); 085 if (success) { 086 logger.fine("### Comitting transaction of " + method); 087 tx.success(); 088 } else { 089 logger.warning("### Rollback transaction of " + method); 090 } 091 tx.finish(); 092 return response; 093 } 094 }; 095 } 096 } 097}