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 */ 022package org.granite.tide.ejb; 023 024import javax.interceptor.AroundInvoke; 025import javax.interceptor.Interceptor; 026import javax.interceptor.InvocationContext; 027import javax.naming.InitialContext; 028import javax.transaction.TransactionSynchronizationRegistry; 029 030import org.granite.tide.data.DataContext; 031import org.granite.tide.data.DataEnabled; 032import org.granite.tide.data.TideDataPublishingSynchronization; 033import org.granite.tide.data.DataEnabled.PublishMode; 034import org.granite.tide.data.JMSDataDispatcher; 035 036 037/** 038 * EJB interceptor to handle publishing of data changes instead of relying on the default behaviour 039 * This can be used outside of a HTTP Granite context and inside the security/transaction context 040 * @author William DRAI 041 * 042 */ 043@Interceptor 044public class TideDataPublishingInterceptor { 045 046 @AroundInvoke 047 public Object processPublishData(InvocationContext invocationContext) throws Exception { 048 if (invocationContext.getMethod() == null) { 049 // Lifecycle method 050 return invocationContext.proceed(); 051 } 052 053 DataEnabled dataEnabled = invocationContext.getTarget().getClass().getAnnotation(DataEnabled.class); 054 if (dataEnabled == null || !dataEnabled.useInterceptor()) 055 return invocationContext.proceed(); 056 057 boolean shouldRemoveContextAtEnd = DataContext.get() == null; 058 boolean shouldInitContext = shouldRemoveContextAtEnd || DataContext.isNull(); 059 boolean onCommit = false; 060 061 if (shouldInitContext) 062 DataContext.init(new JMSDataDispatcher(dataEnabled.topic(), onCommit, dataEnabled.params()), dataEnabled.publish()); 063 064 DataContext.observe(); 065 try { 066 if (dataEnabled.publish().equals(PublishMode.ON_COMMIT)) { 067 InitialContext ctx = new InitialContext(); 068 TransactionSynchronizationRegistry tsr = (TransactionSynchronizationRegistry)ctx.lookup("java:comp/TransactionSynchronizationRegistry"); 069 tsr.registerInterposedSynchronization(new TideDataPublishingSynchronization(shouldRemoveContextAtEnd)); 070 onCommit = true; 071 } 072 073 Object ret = invocationContext.proceed(); 074 075 DataContext.publish(PublishMode.ON_SUCCESS); 076 return ret; 077 } 078 finally { 079 if (shouldRemoveContextAtEnd && !onCommit) 080 DataContext.remove(); 081 } 082 } 083}