001/**
002 *   GRANITE DATA SERVICES
003 *   Copyright (C) 2006-2014 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.seam21;
023
024import static org.jboss.seam.annotations.Install.FRAMEWORK;
025
026import java.io.Serializable;
027import java.lang.reflect.Method;
028
029import org.granite.tide.seam.AbstractSeamServiceContext;
030import org.granite.tide.seam.TideInvocation;
031import org.granite.tide.seam.async.AsyncContext;
032import org.jboss.seam.Component;
033import org.jboss.seam.ScopeType;
034import org.jboss.seam.annotations.AutoCreate;
035import org.jboss.seam.annotations.Install;
036import org.jboss.seam.annotations.Logger;
037import org.jboss.seam.annotations.Name;
038import org.jboss.seam.annotations.Scope;
039import org.jboss.seam.annotations.intercept.BypassInterceptors;
040import org.jboss.seam.async.AbstractDispatcher;
041import org.jboss.seam.async.Dispatcher;
042import org.jboss.seam.async.Schedule;
043import org.jboss.seam.core.Events;
044import org.jboss.seam.log.Log;
045
046
047/**
048 * TideEvents override to intercept Seam events handling
049 * 
050 * @author William DRAI
051 */
052@Name("org.jboss.seam.core.events")
053@Install(precedence=FRAMEWORK+1)
054@Scope(ScopeType.STATELESS)
055@BypassInterceptors
056@AutoCreate
057public class TideEvents extends Events {
058    
059    protected @Logger Log log;
060    
061    protected static final String ASYNC_EVENT = "org.granite.tide.seam.AsyncEvent";
062    
063    
064    @Override
065    public void raiseEvent(String type, Object... parameters) {
066        if (ASYNC_EVENT.equals(type)) {
067                TideInvocation.init();
068            AbstractSeamServiceContext serviceContext = (AbstractSeamServiceContext)Component.getInstance(AbstractSeamServiceContext.COMPONENT_NAME, true);
069            
070            WrappedEvent event = (WrappedEvent)parameters[0];
071            serviceContext.setAsyncContext(event.getAsyncContext());    // Reset context
072            
073            raiseEvent(event.getType(), event.getParams());
074            
075            // Send event through Gravity only 
076            serviceContext.sendEvent(null, null);
077        }
078        else {
079            super.raiseEvent(type, parameters);
080            
081            // Ignore built-in Seam events to avoid stack overflow in component initialization
082            if (!type.startsWith("org.jboss.seam.pre") && !type.startsWith("org.jboss.seam.post")) {
083                // Event should be always handled if we want to allow to send them through Gravity
084                AbstractSeamServiceContext serviceContext = (AbstractSeamServiceContext)Component.getInstance(AbstractSeamServiceContext.COMPONENT_NAME, false);
085                if (serviceContext != null)     // ServiceContext is null during Seam initialization
086                    serviceContext.raiseEvent(type, parameters);
087            }
088        }
089    }
090    
091    
092    @Override
093    public void raiseAsynchronousEvent(String type, Object... parameters) {
094        AbstractSeamServiceContext serviceContext = (AbstractSeamServiceContext)Component.getInstance(AbstractSeamServiceContext.COMPONENT_NAME, false);
095        String sessionId = serviceContext != null ? serviceContext.getSessionId() : null;
096        if (serviceContext != null && sessionId != null)
097            super.raiseAsynchronousEvent(ASYNC_EVENT, new WrappedEvent(serviceContext.getAsyncContext(), type, parameters));
098        else
099            super.raiseAsynchronousEvent(type, parameters);
100    }
101    
102        
103    // Seam 2.1
104    private static final Class<?>[] SEAM21_TIMED_EVENT_ARGS = new Class<?>[] { String.class, Schedule.class, Object[].class };
105    
106    @SuppressWarnings("all")
107    public void raiseTimedEvent(String type, Schedule schedule, Object... parameters) {
108        AbstractSeamServiceContext serviceContext = (AbstractSeamServiceContext)Component.getInstance(AbstractSeamServiceContext.COMPONENT_NAME, false);
109        
110        String sessionId = serviceContext != null ? serviceContext.getSessionId() : null;
111        Dispatcher dispatcher = AbstractDispatcher.instance();
112        if (dispatcher != null) {
113                try {
114                        Method m = dispatcher.getClass().getMethod("scheduleTimedEvent", SEAM21_TIMED_EVENT_ARGS);
115                        if (serviceContext != null && sessionId != null)
116                                m.invoke(dispatcher, ASYNC_EVENT, schedule, new Object[] { new WrappedEvent(serviceContext.getAsyncContext(), type, parameters) });
117                        else
118                                m.invoke(dispatcher, type, schedule, parameters);
119                }
120                catch (Exception e) {
121                        log.error("Could not raise timed event", e);
122                }
123        }
124    }
125    
126    
127    protected static class WrappedEvent implements Serializable {
128        
129        private static final long serialVersionUID = 1L;
130        
131        private AsyncContext asyncContext;
132        private String type;
133        private Object[] params;
134        
135        public WrappedEvent(AsyncContext asyncContext, String type, Object[] params) {
136            this.asyncContext = asyncContext;
137            this.type = type;
138            this.params = params;
139        }
140        
141        public AsyncContext getAsyncContext() {
142            return asyncContext;
143        }
144        
145        public String getType() {
146            return type;
147        }
148        
149        public Object[] getParams() {
150            return params;
151        }
152    }
153}