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}