001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.reef.runtime.common.utils;
020
021import org.apache.reef.annotations.audience.DriverSide;
022import org.apache.reef.annotations.audience.Private;
023import org.apache.reef.tang.util.MonotonicHashMap;
024import org.apache.reef.util.ExceptionHandlingEventHandler;
025import org.apache.reef.wake.EventHandler;
026import org.apache.reef.wake.impl.ThreadPoolStage;
027
028import java.util.Collections;
029import java.util.Map;
030import java.util.Set;
031
032/**
033 * Delayed event router that dispatches messages to the proper event handler by type.
034 * This class is used in EvaluatorManager to isolate user threads from REEF.
035 */
036@Private
037@DriverSide
038public final class DispatchingEStage implements AutoCloseable {
039
040  /**
041   * A map of event handlers, populated in the register() method.
042   */
043  private final Map<Class<?>, EventHandler<?>> handlers =
044      Collections.synchronizedMap(new MonotonicHashMap<Class<?>, EventHandler<?>>());
045  /**
046   * Exception handler, one for all event handlers.
047   */
048  private final EventHandler<Throwable> errorHandler;
049  /**
050   * Thread pool to process delayed event handler invocations.
051   */
052  private final ThreadPoolStage<DelayedOnNext> stage;
053
054  /**
055   * @param errorHandler used for exceptions thrown from the event handlers registered.
056   * @param numThreads   number of threads to allocate to dispatch events.
057   * @param stageName    the name to use for the underlying stage. It will be carried over to name the Thread(s) spawned.
058   */
059  public DispatchingEStage(final EventHandler<Throwable> errorHandler,
060                           final int numThreads,
061                           final String stageName) {
062    this.errorHandler = errorHandler;
063    this.stage = new ThreadPoolStage<>(stageName,
064        new EventHandler<DelayedOnNext>() {
065          @Override
066          public void onNext(final DelayedOnNext promise) {
067            promise.handler.onNext(promise.message);
068          }
069        }, numThreads
070    );
071
072  }
073
074  /**
075   * Constructs a DispatchingEStage that uses the Thread pool and ErrorHandler of another one.
076   *
077   * @param other
078   */
079  public DispatchingEStage(final DispatchingEStage other) {
080    this.errorHandler = other.errorHandler;
081    this.stage = other.stage;
082  }
083
084  /**
085   * Register a new event handler.
086   *
087   * @param type     Message type to process with this handler.
088   * @param handlers A set of handlers that process that type of message.
089   * @param <T>      Message type.
090   * @param <U>      Type of message that event handler supports. Must be a subclass of T.
091   */
092  public <T, U extends T> void register(final Class<T> type, final Set<EventHandler<U>> handlers) {
093    this.handlers.put(type, new ExceptionHandlingEventHandler<>(
094        new BroadCastEventHandler<>(handlers), this.errorHandler));
095  }
096
097  /**
098   * Dispatch a new message by type.
099   *
100   * @param type    Type of event handler - must match the register() call.
101   * @param message A message to process. Must be a subclass of T.
102   * @param <T>     Message type that event handler supports.
103   * @param <U>     input message type. Must be a subclass of T.
104   */
105  @SuppressWarnings("unchecked")
106  public <T, U extends T> void onNext(final Class<T> type, final U message) {
107    final EventHandler<T> handler = (EventHandler<T>) this.handlers.get(type);
108    this.stage.onNext(new DelayedOnNext(handler, message));
109  }
110
111  /**
112   * Return true if there are no messages queued or in processing, false otherwise.
113   */
114  public boolean isEmpty() {
115    return this.stage.getQueueLength() == 0;
116  }
117
118  /**
119   * Close the internal thread pool.
120   *
121   * @throws Exception forwarded from EStage.close() call.
122   */
123  @Override
124  public void close() throws Exception {
125    this.stage.close();
126  }
127
128  /**
129   * Delayed EventHandler.onNext() call.
130   * Contains a message object and EventHandler to process it.
131   */
132  private static final class DelayedOnNext {
133
134    public final EventHandler<Object> handler;
135    public final Object message;
136
137    @SuppressWarnings("unchecked")
138    public <T, U extends T> DelayedOnNext(final EventHandler<T> handler, final U message) {
139      this.handler = (EventHandler<Object>) handler;
140      this.message = message;
141    }
142  }
143}