001: /*
002: * Copyright 2002-2007 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.springframework.orm.jdo.support;
018:
019: import java.io.IOException;
020:
021: import javax.jdo.PersistenceManager;
022: import javax.jdo.PersistenceManagerFactory;
023: import javax.servlet.FilterChain;
024: import javax.servlet.ServletException;
025: import javax.servlet.http.HttpServletRequest;
026: import javax.servlet.http.HttpServletResponse;
027:
028: import org.springframework.orm.jdo.PersistenceManagerFactoryUtils;
029: import org.springframework.orm.jdo.PersistenceManagerHolder;
030: import org.springframework.transaction.support.TransactionSynchronizationManager;
031: import org.springframework.web.context.WebApplicationContext;
032: import org.springframework.web.context.support.WebApplicationContextUtils;
033: import org.springframework.web.filter.OncePerRequestFilter;
034:
035: /**
036: * Servlet 2.3 Filter that binds a JDO PersistenceManager to the thread for the
037: * entire processing of the request. Intended for the "Open PersistenceManager in
038: * View" pattern, i.e. to allow for lazy loading in web views despite the
039: * original transactions already being completed.
040: *
041: * <p>This filter makes JDO PersistenceManagers available via the current thread,
042: * which will be autodetected by transaction managers. It is suitable for service
043: * layer transactions via {@link org.springframework.orm.jdo.JdoTransactionManager}
044: * or {@link org.springframework.transaction.jta.JtaTransactionManager} as well
045: * as for non-transactional read-only execution.
046: *
047: * <p>Looks up the PersistenceManagerFactory in Spring's root web application context.
048: * Supports a "persistenceManagerFactoryBeanName" filter init-param in <code>web.xml</code>;
049: * the default bean name is "persistenceManagerFactory". Looks up the PersistenceManagerFactory
050: * on each request, to avoid initialization order issues (when using ContextLoaderServlet,
051: * the root application context will get initialized <i>after</i> this filter).
052: *
053: * @author Juergen Hoeller
054: * @since 1.1
055: * @see OpenPersistenceManagerInViewInterceptor
056: * @see org.springframework.orm.jdo.JdoInterceptor
057: * @see org.springframework.orm.jdo.JdoTransactionManager
058: * @see org.springframework.orm.jdo.PersistenceManagerFactoryUtils#getPersistenceManager
059: * @see org.springframework.transaction.support.TransactionSynchronizationManager
060: */
061: public class OpenPersistenceManagerInViewFilter extends
062: OncePerRequestFilter {
063:
064: public static final String DEFAULT_PERSISTENCE_MANAGER_FACTORY_BEAN_NAME = "persistenceManagerFactory";
065:
066: private String persistenceManagerFactoryBeanName = DEFAULT_PERSISTENCE_MANAGER_FACTORY_BEAN_NAME;
067:
068: /**
069: * Set the bean name of the PersistenceManagerFactory to fetch from Spring's
070: * root application context. Default is "persistenceManagerFactory".
071: * @see #DEFAULT_PERSISTENCE_MANAGER_FACTORY_BEAN_NAME
072: */
073: public void setPersistenceManagerFactoryBeanName(
074: String persistenceManagerFactoryBeanName) {
075: this .persistenceManagerFactoryBeanName = persistenceManagerFactoryBeanName;
076: }
077:
078: /**
079: * Return the bean name of the PersistenceManagerFactory to fetch from Spring's
080: * root application context.
081: */
082: protected String getPersistenceManagerFactoryBeanName() {
083: return this .persistenceManagerFactoryBeanName;
084: }
085:
086: protected void doFilterInternal(HttpServletRequest request,
087: HttpServletResponse response, FilterChain filterChain)
088: throws ServletException, IOException {
089:
090: PersistenceManagerFactory pmf = lookupPersistenceManagerFactory(request);
091: boolean participate = false;
092:
093: if (TransactionSynchronizationManager.hasResource(pmf)) {
094: // Do not modify the PersistenceManager: just set the participate flag.
095: participate = true;
096: } else {
097: logger
098: .debug("Opening JDO PersistenceManager in OpenPersistenceManagerInViewFilter");
099: PersistenceManager pm = PersistenceManagerFactoryUtils
100: .getPersistenceManager(pmf, true);
101: TransactionSynchronizationManager.bindResource(pmf,
102: new PersistenceManagerHolder(pm));
103: }
104:
105: try {
106: filterChain.doFilter(request, response);
107: }
108:
109: finally {
110: if (!participate) {
111: PersistenceManagerHolder pmHolder = (PersistenceManagerHolder) TransactionSynchronizationManager
112: .unbindResource(pmf);
113: logger
114: .debug("Closing JDO PersistenceManager in OpenPersistenceManagerInViewFilter");
115: PersistenceManagerFactoryUtils
116: .releasePersistenceManager(pmHolder
117: .getPersistenceManager(), pmf);
118: }
119: }
120: }
121:
122: /**
123: * Look up the PersistenceManagerFactory that this filter should use,
124: * taking the current HTTP request as argument.
125: * <p>Default implementation delegates to the <code>lookupPersistenceManagerFactory</code>
126: * without arguments.
127: * @return the PersistenceManagerFactory to use
128: * @see #lookupPersistenceManagerFactory()
129: */
130: protected PersistenceManagerFactory lookupPersistenceManagerFactory(
131: HttpServletRequest request) {
132: return lookupPersistenceManagerFactory();
133: }
134:
135: /**
136: * Look up the PersistenceManagerFactory that this filter should use.
137: * The default implementation looks for a bean with the specified name
138: * in Spring's root application context.
139: * @return the PersistenceManagerFactory to use
140: * @see #getPersistenceManagerFactoryBeanName
141: */
142: protected PersistenceManagerFactory lookupPersistenceManagerFactory() {
143: if (logger.isDebugEnabled()) {
144: logger.debug("Using PersistenceManagerFactory '"
145: + getPersistenceManagerFactoryBeanName()
146: + "' for OpenPersistenceManagerInViewFilter");
147: }
148: WebApplicationContext wac = WebApplicationContextUtils
149: .getRequiredWebApplicationContext(getServletContext());
150: return (PersistenceManagerFactory) wac.getBean(
151: getPersistenceManagerFactoryBeanName(),
152: PersistenceManagerFactory.class);
153: }
154:
155: }
|