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 javax.jdo.PersistenceManager;
020: import javax.jdo.PersistenceManagerFactory;
021:
022: import org.apache.commons.logging.Log;
023: import org.apache.commons.logging.LogFactory;
024:
025: import org.springframework.dao.DataAccessException;
026: import org.springframework.orm.jdo.PersistenceManagerFactoryUtils;
027: import org.springframework.orm.jdo.PersistenceManagerHolder;
028: import org.springframework.transaction.support.TransactionSynchronizationManager;
029: import org.springframework.ui.ModelMap;
030: import org.springframework.web.context.request.WebRequest;
031: import org.springframework.web.context.request.WebRequestInterceptor;
032:
033: /**
034: * Spring web request interceptor that binds a JDO PersistenceManager to the
035: * thread for the entire processing of the request. Intended for the "Open
036: * PersistenceManager in View" pattern, i.e. to allow for lazy loading in
037: * web views despite the original transactions already being completed.
038: *
039: * <p>This interceptor makes JDO PersistenceManagers available via the current thread,
040: * which will be autodetected by transaction managers. It is suitable for service
041: * layer transactions via {@link org.springframework.orm.jdo.JdoTransactionManager}
042: * or {@link org.springframework.transaction.jta.JtaTransactionManager} as well
043: * as for non-transactional read-only execution.
044: *
045: * <p>In contrast to {@link OpenPersistenceManagerInViewFilter}, this interceptor
046: * is set up in a Spring application context and can thus take advantage of
047: * bean wiring. It inherits common JDO configuration properties from
048: * {@link org.springframework.orm.jdo.JdoAccessor}, to be configured in a
049: * bean definition.
050: *
051: * @author Juergen Hoeller
052: * @since 1.1
053: * @see OpenPersistenceManagerInViewFilter
054: * @see org.springframework.orm.jdo.JdoInterceptor
055: * @see org.springframework.orm.jdo.JdoTransactionManager
056: * @see org.springframework.orm.jdo.PersistenceManagerFactoryUtils#getPersistenceManager
057: * @see org.springframework.transaction.support.TransactionSynchronizationManager
058: */
059: public class OpenPersistenceManagerInViewInterceptor implements
060: WebRequestInterceptor {
061:
062: /**
063: * Suffix that gets appended to the PersistenceManagerFactory toString
064: * representation for the "participate in existing persistence manager
065: * handling" request attribute.
066: * @see #getParticipateAttributeName
067: */
068: public static final String PARTICIPATE_SUFFIX = ".PARTICIPATE";
069:
070: protected final Log logger = LogFactory.getLog(getClass());
071:
072: private PersistenceManagerFactory persistenceManagerFactory;
073:
074: /**
075: * Set the JDO PersistenceManagerFactory that should be used to create
076: * PersistenceManagers.
077: */
078: public void setPersistenceManagerFactory(
079: PersistenceManagerFactory pmf) {
080: this .persistenceManagerFactory = pmf;
081: }
082:
083: /**
084: * Return the JDO PersistenceManagerFactory that should be used to create
085: * PersistenceManagers.
086: */
087: public PersistenceManagerFactory getPersistenceManagerFactory() {
088: return persistenceManagerFactory;
089: }
090:
091: public void preHandle(WebRequest request)
092: throws DataAccessException {
093: if (TransactionSynchronizationManager
094: .hasResource(getPersistenceManagerFactory())) {
095: // Do not modify the PersistenceManager: just mark the request accordingly.
096: String participateAttributeName = getParticipateAttributeName();
097: Integer count = (Integer) request.getAttribute(
098: participateAttributeName, WebRequest.SCOPE_REQUEST);
099: int newCount = (count != null) ? count.intValue() + 1 : 1;
100: request.setAttribute(getParticipateAttributeName(),
101: new Integer(newCount), WebRequest.SCOPE_REQUEST);
102: } else {
103: logger
104: .debug("Opening JDO PersistenceManager in OpenPersistenceManagerInViewInterceptor");
105: PersistenceManager pm = PersistenceManagerFactoryUtils
106: .getPersistenceManager(
107: getPersistenceManagerFactory(), true);
108: TransactionSynchronizationManager.bindResource(
109: getPersistenceManagerFactory(),
110: new PersistenceManagerHolder(pm));
111: }
112: }
113:
114: public void postHandle(WebRequest request, ModelMap model) {
115: }
116:
117: public void afterCompletion(WebRequest request, Exception ex)
118: throws DataAccessException {
119: String participateAttributeName = getParticipateAttributeName();
120: Integer count = (Integer) request.getAttribute(
121: participateAttributeName, WebRequest.SCOPE_REQUEST);
122: if (count != null) {
123: // Do not modify the PersistenceManager: just clear the marker.
124: if (count.intValue() > 1) {
125: request.setAttribute(participateAttributeName,
126: new Integer(count.intValue() - 1),
127: WebRequest.SCOPE_REQUEST);
128: } else {
129: request.removeAttribute(participateAttributeName,
130: WebRequest.SCOPE_REQUEST);
131: }
132: } else {
133: PersistenceManagerHolder pmHolder = (PersistenceManagerHolder) TransactionSynchronizationManager
134: .unbindResource(getPersistenceManagerFactory());
135: logger
136: .debug("Closing JDO PersistenceManager in OpenPersistenceManagerInViewInterceptor");
137: PersistenceManagerFactoryUtils.releasePersistenceManager(
138: pmHolder.getPersistenceManager(),
139: getPersistenceManagerFactory());
140: }
141: }
142:
143: /**
144: * Return the name of the request attribute that identifies that a request is
145: * already filtered. Default implementation takes the toString representation
146: * of the PersistenceManagerFactory instance and appends ".FILTERED".
147: * @see #PARTICIPATE_SUFFIX
148: */
149: protected String getParticipateAttributeName() {
150: return getPersistenceManagerFactory().toString()
151: + PARTICIPATE_SUFFIX;
152: }
153:
154: }
|