001/** 002 * Copyright 2005-2018 The Kuali Foundation 003 * 004 * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php 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 */ 016package org.kuali.rice.krad.web.controller; 017 018import org.springframework.beans.factory.annotation.Autowired; 019import org.springframework.beans.factory.annotation.Qualifier; 020import org.springframework.transaction.PlatformTransactionManager; 021import org.springframework.transaction.TransactionDefinition; 022import org.springframework.transaction.TransactionStatus; 023import org.springframework.transaction.support.DefaultTransactionDefinition; 024import org.springframework.web.servlet.HandlerInterceptor; 025import org.springframework.web.servlet.ModelAndView; 026 027import javax.servlet.http.HttpServletRequest; 028import javax.servlet.http.HttpServletResponse; 029 030/** 031 * Spring interceptor class that will start the Rice configured transaction on pre handle (before binding 032 * and controller) and commit after controller execution. 033 * <p/> 034 * <p>For KRAD, this interceptor should be listed first 035 * (before {@link org.kuali.rice.krad.web.controller.UifControllerHandlerInterceptor})</p> 036 * 037 * @author Kuali Rice Team (rice.collab@kuali.org) 038 * @see org.kuali.rice.core.framework.persistence.jta.Jta 039 */ 040public class TransactionHandlerInterceptor implements HandlerInterceptor { 041 042 private static final ThreadLocal<TransactionStatus> context = new ThreadLocal<TransactionStatus>(); 043 044 @Autowired() 045 @Qualifier("transactionManager") 046 PlatformTransactionManager txManager; 047 048 /** 049 * {@inheritDoc} 050 */ 051 @Override 052 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 053 throws Exception { 054 DefaultTransactionDefinition def = new DefaultTransactionDefinition(); 055 def.setName("request"); 056 def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); 057 058 TransactionStatus status = txManager.getTransaction(def); 059 context.set(status); 060 061 return true; 062 } 063 064 /** 065 * {@inheritDoc} 066 */ 067 @Override 068 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, 069 ModelAndView modelAndView) throws Exception { 070 completeTransaction(null); 071 } 072 073 /** 074 * {@inheritDoc} 075 */ 076 @Override 077 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) 078 throws Exception { 079 completeTransaction(ex); 080 } 081 082 /** 083 * Completes the request transaction if needed. 084 * 085 * @param ex any exception that might have been thrown, will cause a rollback 086 */ 087 protected void completeTransaction(Exception ex) { 088 TransactionStatus status = context.get(); 089 090 if (status == null) { 091 return; 092 } 093 094 try { 095 if (!status.isCompleted()) { 096 if (ex == null && !status.isRollbackOnly()) { 097 txManager.commit(status); 098 } else { 099 txManager.rollback(status); 100 } 101 } 102 } finally { 103 context.remove(); 104 } 105 } 106}