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    package org.granite.tide.seam21;
023    
024    import static org.jboss.seam.annotations.Install.FRAMEWORK;
025    
026    import java.io.Serializable;
027    import java.lang.reflect.Method;
028    
029    import org.granite.tide.seam.AbstractSeamServiceContext;
030    import org.granite.tide.seam.TideInvocation;
031    import org.granite.tide.seam.async.AsyncContext;
032    import org.jboss.seam.Component;
033    import org.jboss.seam.ScopeType;
034    import org.jboss.seam.annotations.AutoCreate;
035    import org.jboss.seam.annotations.Install;
036    import org.jboss.seam.annotations.Logger;
037    import org.jboss.seam.annotations.Name;
038    import org.jboss.seam.annotations.Scope;
039    import org.jboss.seam.annotations.intercept.BypassInterceptors;
040    import org.jboss.seam.async.AbstractDispatcher;
041    import org.jboss.seam.async.Dispatcher;
042    import org.jboss.seam.async.Schedule;
043    import org.jboss.seam.core.Events;
044    import 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
057    public 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    }