001    /*
002     * Copyright 2002-2005 the original author or authors.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jencks.interceptor;
018    
019    import org.apache.commons.logging.Log;
020    import org.apache.commons.logging.LogFactory;
021    import org.apache.geronimo.transaction.DefaultInstanceContext;
022    import org.apache.geronimo.transaction.InstanceContext;
023    import org.apache.geronimo.transaction.TrackedConnectionAssociator;
024    
025    import javax.resource.ResourceException;
026    import javax.servlet.Filter;
027    import javax.servlet.FilterChain;
028    import javax.servlet.FilterConfig;
029    import javax.servlet.ServletException;
030    import javax.servlet.ServletRequest;
031    import javax.servlet.ServletResponse;
032    import java.io.IOException;
033    import java.util.HashSet;
034    import java.util.Set;
035    
036    /**
037     * This servlet filter is used to enter in a transactional context
038     * automtically at every servlet call and exit of it when the response
039     * is sent back to the client.
040     * <p/>
041     * This class must be used with a mechanism (for example, Acegi) to
042     * use injection on filters.
043     * <p/>
044     * The following is an example of use:
045     * <p/>
046     * <web-app id="WebApp">
047     * ...
048     * <filter>
049     * <filter-name>Geronimo Transaction Context Filter</filter-name>
050     * <filter-class>
051     * org.springframework.web.filter.DelegatingFilterProxy</filter-class>
052     * <init-param>
053     * <param-name>targetBeanName</param-name>
054     * <param-value>
055     * org.springframework.jca.interceptor.TransactionContexFilter
056     * </param-value>
057     * </init-param>
058     * </filter>
059     * <p/>
060     * <filter-mapping>
061     * <filter-name>Geronimo Transaction Context Filter</filter-name>
062     * <url-pattern>/*</url-pattern>
063     * </filter-mapping>
064     * ...
065     * </web-app>
066     *
067     * @author Thierry Templier
068     * @see TrackedConnectionAssociator#enter(InstanceContext)
069     * @see TrackedConnectionAssociator#exit(InstanceContext)
070     * @see InstanceContext
071     * @see DefaultInstanceContext
072     */
073    public class TransactionContexFilter implements Filter {
074    
075        private TrackedConnectionAssociator associator;
076    
077        protected transient Log logger = LogFactory.getLog(getClass());
078    
079        public void init(FilterConfig config) throws ServletException {
080        }
081    
082        /**
083         * This is the central method of the filter which allows the
084         * request to enter in a transactionnal context and exit when
085         * the request is sent back to the client.
086         *
087         * @see #enterContext(Set, Set)
088         * @see #exitContext(InstanceContext)
089         */
090        public void doFilter(ServletRequest request, ServletResponse response,
091                             FilterChain chain) throws IOException, ServletException {
092            // Enter in the transactionnal context
093            Set unshareableResources = new HashSet();
094            Set applicationManagedSecurityResources = new HashSet();
095            InstanceContext oldContext =
096                    enterContext(unshareableResources, applicationManagedSecurityResources);
097    
098            // Proceed with chain
099            chain.doFilter(request, response);
100    
101            // Exit the transactionnal context
102            exitContext(oldContext);
103        }
104    
105        /**
106         * This method enters in a new context and returns it
107         * in order to exit of it when the request is sent back to
108         * the client.
109         */
110        private InstanceContext enterContext(Set unshareableResources,
111                                             Set applicationManagedSecurityResources) {
112            try {
113                InstanceContext oldContext =
114                        associator.enter(new DefaultInstanceContext(
115                                unshareableResources, applicationManagedSecurityResources));
116                if (logger.isDebugEnabled()) {
117                    logger.info("Geronimo transaction context set.");
118                }
119                return oldContext;
120            }
121            catch (ResourceException ex) {
122            }
123            return null;
124        }
125    
126        /**
127         * This method exits of the specified context. This context is
128         * created when entering a new one.
129         *
130         * @see #enterContext(Set, Set)
131         */
132        private void exitContext(InstanceContext oldContext) {
133            try {
134                associator.exit(oldContext);
135                if (logger.isDebugEnabled()) {
136                    logger.info("Geronimo transaction context unset.");
137                }
138            }
139            catch (ResourceException ex) {
140            }
141        }
142    
143        public void destroy() {
144        }
145    
146        /**
147         * Set the TrackedConnectionAssociator instance to allow the bean
148         * to enter and exit a transactional context.
149         */
150        public void setAssociator(TrackedConnectionAssociator associator) {
151            this.associator = associator;
152            }
153    
154    }