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.util;
022    
023    import java.lang.reflect.Method;
024    import java.util.ArrayList;
025    import java.util.HashMap;
026    import java.util.List;
027    import java.util.Map;
028    import java.util.Set;
029    
030    import org.granite.logging.Logger;
031    import org.granite.tide.invocation.ContextEvent;
032    
033    /**
034     * @author Franck WOLFF
035     */
036    public abstract class AbstractContext extends HashMap<String, Object> {
037    
038            private static final long serialVersionUID = 1L;
039            private static final Logger log = Logger.getLogger(AbstractContext.class);
040            private static final ThreadLocal<AbstractContext> contexts = new ThreadLocal<AbstractContext>();
041            
042            private final Map<String, Set<Method>> observers;
043            private final List<ContextEvent> remoteEvents;
044            
045            protected AbstractContext(Map<String, Set<Method>> observers) {
046                    synchronized (contexts) {
047                            if (contexts.get() != null)
048                                    throw new IllegalStateException("Context already created");
049                            
050                            this.observers = observers;
051                            this.remoteEvents = new ArrayList<ContextEvent>();
052                            
053                            contexts.set(this);
054                    }
055            }
056            
057            public List<ContextEvent> getRemoteEvents() {
058                    return remoteEvents;
059            }
060            
061            protected abstract Set<String> getRemoteObservers();
062            protected abstract Object callMethod(Method method, Object... args) throws Exception;
063            
064            public static AbstractContext instance() {
065                    return contexts.get();
066            }
067            
068            public static void raiseEvent(String name, Object... args) {
069                    AbstractContext instance = instance();
070                    Map<String, Set<Method>> observers = instance.observers;
071                    if (observers.containsKey(name)) {
072                            for (Method method : observers.get(name)) {
073                                    try {
074                                            instance.callMethod(method, args);
075                                    }
076                                    catch (Exception e) {
077                                            log.error(e, "Could not call method: %s", method);
078                                    }
079                            }
080                    }
081                    Set<String> remoteObservers = instance.getRemoteObservers();
082                    if (remoteObservers.contains(name))
083                            instance.remoteEvents.add(new ContextEvent(name, args));
084            }
085            
086            public static void remove() {
087                    AbstractContext context = contexts.get();
088                    if (context != null) {
089                            try {
090                                    context.clear();
091                                    context.remoteEvents.clear();
092                            }
093                            finally {
094                                    contexts.remove();
095                            }
096                    }
097            }
098    }