001/*
002  GRANITE DATA SERVICES
003  Copyright (C) 2011 GRANITE DATA SERVICES S.A.S.
004
005  This file is part of Granite Data Services.
006
007  Granite Data Services is free software; you can redistribute it and/or modify
008  it under the terms of the GNU Library General Public License as published by
009  the Free Software Foundation; either version 2 of the License, or (at your
010  option) any later version.
011
012  Granite Data Services is distributed in the hope that it will be useful, but
013  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015  for more details.
016
017  You should have received a copy of the GNU Library General Public License
018  along with this library; if not, see <http://www.gnu.org/licenses/>.
019*/
020
021package org.granite.tide.ejb;
022
023import javax.interceptor.AroundInvoke;
024import javax.interceptor.Interceptor;
025import javax.interceptor.InvocationContext;
026import javax.naming.InitialContext;
027import javax.transaction.TransactionSynchronizationRegistry;
028
029import org.granite.tide.data.DataContext;
030import org.granite.tide.data.DataEnabled;
031import org.granite.tide.data.TideDataPublishingSynchronization;
032import org.granite.tide.data.DataEnabled.PublishMode;
033import org.granite.tide.data.JMSDataDispatcher;
034
035
036/**
037 * EJB interceptor to handle publishing of data changes instead of relying on the default behaviour
038 * This can be used outside of a HTTP Granite context and inside the security/transaction context
039 * @author William DRAI
040 *
041 */
042@Interceptor
043public class TideDataPublishingInterceptor {
044        
045        @AroundInvoke
046    public Object processPublishData(InvocationContext invocationContext) throws Exception {
047        if (invocationContext.getMethod() == null) {
048                // Lifecycle method
049                return invocationContext.proceed();
050        }
051        
052        DataEnabled dataEnabled = invocationContext.getTarget().getClass().getAnnotation(DataEnabled.class);
053        if (dataEnabled == null || !dataEnabled.useInterceptor())
054                return invocationContext.proceed();
055        
056        boolean shouldRemoveContextAtEnd = DataContext.get() == null;
057        boolean shouldInitContext = shouldRemoveContextAtEnd || DataContext.isNull();
058        boolean onCommit = false;
059        
060        if (shouldInitContext)
061                DataContext.init(new JMSDataDispatcher(dataEnabled.topic(), onCommit, dataEnabled.params()), dataEnabled.publish());
062        
063        DataContext.observe();
064        try {
065                if (dataEnabled.publish().equals(PublishMode.ON_COMMIT)) {
066                        InitialContext ctx = new InitialContext();
067                        TransactionSynchronizationRegistry tsr = (TransactionSynchronizationRegistry)ctx.lookup("java:comp/TransactionSynchronizationRegistry");
068                        tsr.registerInterposedSynchronization(new TideDataPublishingSynchronization(shouldRemoveContextAtEnd));
069                        onCommit = true;
070                }
071                
072                Object ret = invocationContext.proceed();
073                
074                DataContext.publish(PublishMode.ON_SUCCESS);
075                return ret;
076        }
077        finally {
078                if (shouldRemoveContextAtEnd && !onCommit)
079                        DataContext.remove();
080        }
081    }
082}