001    package de.deepamehta.core.impl;
002    
003    import de.deepamehta.core.service.DeepaMehtaService;
004    import de.deepamehta.core.service.Transactional;
005    import de.deepamehta.core.storage.spi.DeepaMehtaTransaction;
006    
007    import com.sun.jersey.api.model.AbstractMethod;
008    import com.sun.jersey.spi.container.ContainerRequest;
009    import com.sun.jersey.spi.container.ContainerRequestFilter;
010    import com.sun.jersey.spi.container.ContainerResponse;
011    import com.sun.jersey.spi.container.ContainerResponseFilter;
012    import com.sun.jersey.spi.container.ResourceFilter;
013    import com.sun.jersey.spi.container.ResourceFilterFactory;
014    
015    import java.util.ArrayList;
016    import java.util.List;
017    import java.util.logging.Logger;
018    
019    
020    
021    class 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    }