001/**
002 * Copyright 2014 Tampere University of Technology, Pori Department
003 * 
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * 
008 *   http://www.apache.org/licenses/LICENSE-2.0
009 * 
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package core.tut.pori.context;
017
018import java.util.Collection;
019import java.util.Date;
020import java.util.concurrent.ExecutorService;
021
022import org.apache.log4j.Logger;
023import org.springframework.beans.BeansException;
024import org.springframework.context.ApplicationEvent;
025import org.springframework.context.ApplicationListener;
026import org.springframework.context.event.SimpleApplicationEventMulticaster;
027import org.springframework.context.support.ClassPathXmlApplicationContext;
028import org.springframework.core.ResolvableType;
029
030import core.tut.pori.utils.StringUtils;
031
032/**
033 * This class can be used to submit application events to the defined listeners. 
034 * 
035 * Listeners are defined by event context configuration and the defined annotations.
036 * 
037 * One should not initialize this handler directly, as an instantiated version is available from ServiceInitializer.
038 *
039 */
040public class EventHandler {
041  private static final Logger LOGGER = Logger.getLogger(EventHandler.class);
042  private static final String SERVLET_CONFIGURATION_FILE = "event-context.xml";
043  private ClassPathXmlApplicationContext _context = null;
044
045  /**
046   * 
047   * @throws BeansException
048   */
049  public EventHandler() throws BeansException{
050    initialize();
051  }
052  
053  /**
054   * 
055   * @throws BeansException on failure
056   */
057  private void initialize() throws BeansException{
058    LOGGER.debug("Initializing handler...");
059    Date started = new Date();
060    _context = new ClassPathXmlApplicationContext(core.tut.pori.properties.SystemProperty.CONFIGURATION_FILE_PATH+SERVLET_CONFIGURATION_FILE);
061
062    LOGGER.debug("Event Handler initialized in "+StringUtils.getDurationString(started, new Date()));
063  }
064
065  /**
066   * close this Service handler and release are resources associated with it
067   */
068  public void close(){
069    _context.close();
070    _context = null;
071  }
072  
073  /**
074   * 
075   * @param event
076   */
077  public void publishEvent(ApplicationEvent event){
078    _context.publishEvent(event);
079  }
080  
081  /**
082   * Implementation of an asynchronous event multicaster.
083   * 
084   * The default event delivery system will block whilst each event listener is in progress. 
085   * This class sends all events simultaneously to all receivers, though in practice the performance of this method is limited by the current load of the scheduler service.
086   */
087  public static class EventMulticaster extends SimpleApplicationEventMulticaster {
088
089    @Override
090    public void multicastEvent(final ApplicationEvent event) {
091      multicastEvent(event, null);
092    }
093
094    @SuppressWarnings("rawtypes")
095    @Override
096    public void multicastEvent(final ApplicationEvent event, ResolvableType type) {
097      Collection<ApplicationListener<?>> listeners = getApplicationListeners(event, (type == null ? ResolvableType.forClass(event.getClass()) : type));
098      if(listeners.isEmpty()){
099        LOGGER.debug("No listeners for event "+event.getClass().toString());
100        return;
101      }
102      
103      ExecutorService executor = ServiceInitializer.getExecutorHandler().getExecutor();
104      if(executor == null){
105        LOGGER.warn("No executor available. Ignoring multicast.");
106        return;
107      }
108      for(final ApplicationListener listener : listeners){
109        executor.execute(new Runnable() {
110          @SuppressWarnings("unchecked")
111          @Override
112          public void run() {
113            try {
114              listener.onApplicationEvent(event);
115            } catch (Throwable ex){
116              LOGGER.error(ex, ex);
117            }
118          }
119        });
120      }
121    }
122  } //  class EventMulticaster
123}