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}