001/** 002 * GRANITE DATA SERVICES 003 * Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S. 004 * 005 * This file is part of the Granite Data Services Platform. 006 * 007 * Granite Data Services is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * Granite Data Services is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 015 * General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 020 * USA, or see <http://www.gnu.org/licenses/>. 021 */ 022 023package org.granite.tide.spring; 024 025import org.granite.gravity.Gravity; 026import org.granite.tide.data.DataEnabled; 027import org.granite.tide.data.DataUpdatePostprocessor; 028import org.granite.util.ThrowableCallable; 029import org.springframework.beans.factory.InitializingBean; 030import org.springframework.beans.factory.annotation.Autowired; 031import org.springframework.transaction.TransactionException; 032import org.springframework.transaction.TransactionStatus; 033import org.springframework.transaction.support.TransactionCallback; 034import org.springframework.transaction.support.TransactionTemplate; 035 036 037/** 038 * Extended Spring Transaction template which handles publishing of data changes 039 * This can be used outside of any Granite context and can replace the default Spring TransactionTemplate 040 * 041 * @author William DRAI 042 */ 043public class TideDataPublishingTransactionTemplate extends TransactionTemplate implements InitializingBean { 044 045 private static final long serialVersionUID = 1L; 046 047 //private static final Logger log = Logger.getLogger(TideDataPublishingTransactionTemplate.class); 048 049 private Gravity gravity; 050 private DataUpdatePostprocessor dataUpdatePostprocessor; 051 052 private TideDataPublishingWrapper tideDataPublishingWrapper = null; 053 054 @Autowired 055 public void setGravity(Gravity gravity) { 056 this.gravity = gravity; 057 } 058 059 public void setTideDataPublishingWrapper(TideDataPublishingWrapper tideDataPublishingWrapper) { 060 this.tideDataPublishingWrapper = tideDataPublishingWrapper; 061 } 062 063 @Autowired(required=false) 064 public void setDataUpdatePostprocessor(DataUpdatePostprocessor dataUpdatePostprocessor) { 065 this.dataUpdatePostprocessor = dataUpdatePostprocessor; 066 } 067 068 @Override 069 public void afterPropertiesSet() { 070 if (tideDataPublishingWrapper == null) 071 tideDataPublishingWrapper = new TideDataPublishingWrapper(gravity, dataUpdatePostprocessor); 072 } 073 074 @Override 075 public <T> T execute(TransactionCallback<T> action) throws TransactionException { 076 DataEnabled dataEnabled = null; 077 if (action.getClass().isAnnotationPresent(DataEnabled.class)) 078 dataEnabled = action.getClass().getAnnotation(DataEnabled.class); 079 else if ((action.getClass().isMemberClass() || action.getClass().isAnonymousClass()) && action.getClass().getEnclosingClass().isAnnotationPresent(DataEnabled.class)) 080 dataEnabled = action.getClass().getEnclosingClass().getAnnotation(DataEnabled.class); 081 082 if (dataEnabled == null || !dataEnabled.useInterceptor()) 083 return super.execute(action); 084 085 return super.execute(new DataEnabledTransactionCallback<T>(action, dataEnabled)); 086 } 087 088 private class DataEnabledTransactionCallback<T> implements TransactionCallback<T> { 089 090 private final TransactionCallback<T> action; 091 private final DataEnabled dataEnabled; 092 093 public DataEnabledTransactionCallback(TransactionCallback<T> action, DataEnabled dataEnabled) { 094 this.action = action; 095 this.dataEnabled = dataEnabled; 096 } 097 098 @Override 099 public T doInTransaction(final TransactionStatus status) { 100 try { 101 return tideDataPublishingWrapper.execute(dataEnabled, new ThrowableCallable<T>() { 102 public T call() throws Throwable { 103 return action.doInTransaction(status); 104 } 105 }); 106 } 107 catch (Error e) { 108 throw e; 109 } 110 catch (RuntimeException e) { 111 throw e; 112 } 113 catch (Throwable t) { 114 throw new RuntimeException("Error in transaction", t); 115 } 116 } 117 } 118}