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    
021    package org.granite.tide.cdi;
022    
023    import javax.enterprise.event.Event;
024    import javax.enterprise.inject.Instance;
025    import javax.inject.Inject;
026    import javax.interceptor.AroundInvoke;
027    import javax.interceptor.Interceptor;
028    import javax.interceptor.InvocationContext;
029    
030    import org.granite.gravity.Gravity;
031    import org.granite.tide.data.DataContext;
032    import org.granite.tide.data.DataEnabled;
033    import org.granite.tide.data.DataEnabled.PublishMode;
034    import org.granite.tide.data.DataTopicParams;
035    import org.granite.tide.data.DataUpdatePostprocessor;
036    
037    
038    /**
039     * CDI interceptor to handle publishing of data changes instead of relying on the default behaviour
040     * This can be used outside of a HTTP Granite context and should be applied inside the security/transaction context
041     * 
042     * @author William DRAI
043     */
044    @DataEnabled(topic="", params=DataTopicParams.class, publish=PublishMode.MANUAL, useInterceptor=true)
045    @Interceptor
046    public class TideDataPublishingInterceptor {
047            
048            @Inject
049            private Gravity gravity;
050            
051            @Inject
052            private Instance<DataUpdatePostprocessor> dataUpdatePostprocessor;
053            
054            @Inject
055            private Event<TideDataPublishingEvent> dataPublishingEvent;
056            
057        @AroundInvoke
058        public Object processPublishData(InvocationContext invocationContext) throws Throwable {
059            DataEnabled dataEnabled = invocationContext.getMethod().getDeclaringClass().getAnnotation(DataEnabled.class);
060            if (dataEnabled == null || !dataEnabled.useInterceptor())
061                    return invocationContext.proceed();
062            
063            boolean shouldRemoveContextAtEnd = DataContext.get() == null;
064            boolean shouldInitContext = shouldRemoveContextAtEnd || DataContext.isNull();
065            boolean onCommit = false;
066            
067            if (shouldInitContext) {
068                    DataContext.init(gravity, dataEnabled.topic(), dataEnabled.params(), dataEnabled.publish());
069                    
070                    if (!dataUpdatePostprocessor.isUnsatisfied())
071                            DataContext.get().setDataUpdatePostprocessor(dataUpdatePostprocessor.get());
072            }
073            
074            DataContext.observe();
075            try {
076                    if (dataEnabled.publish().equals(PublishMode.ON_COMMIT)) {
077                            dataPublishingEvent.fire(new TideDataPublishingEvent(shouldRemoveContextAtEnd));
078                            onCommit = true;
079                    }
080                    
081                    Object ret = invocationContext.proceed();
082                    
083                    DataContext.publish(PublishMode.ON_SUCCESS);
084                    return ret;
085            }
086            finally {
087                    if (shouldRemoveContextAtEnd && !onCommit)
088                            DataContext.remove();
089            }
090        }
091    }