@SuppressWarnings("unchecked")
 public void sendTezEventToSourceTasks(TezEvent tezEvent) {
   if (!bufferEvents.get()) {
     switch (tezEvent.getEventType()) {
       case INPUT_READ_ERROR_EVENT:
         InputReadErrorEvent event = (InputReadErrorEvent) tezEvent.getEvent();
         TezTaskAttemptID destAttemptId = tezEvent.getSourceInfo().getTaskAttemptID();
         int destTaskIndex = destAttemptId.getTaskID().getId();
         int srcTaskIndex = edgeManager.routeEventToSourceTasks(destTaskIndex, event);
         int numConsumers =
             edgeManager.getDestinationConsumerTaskNumber(
                 srcTaskIndex, destinationVertex.getTotalTasks());
         TezTaskID srcTaskId = sourceVertex.getTask(srcTaskIndex).getTaskId();
         int taskAttemptIndex = event.getVersion();
         TezTaskAttemptID srcTaskAttemptId = new TezTaskAttemptID(srcTaskId, taskAttemptIndex);
         eventHandler.handle(
             new TaskAttemptEventOutputFailed(srcTaskAttemptId, tezEvent, numConsumers));
         break;
       default:
         throw new TezUncheckedException("Unhandled tez event type: " + tezEvent.getEventType());
     }
   } else {
     sourceEventBuffer.add(tezEvent);
   }
 }
 public void sendTezEventToDestinationTasks(TezEvent tezEvent) {
   if (!bufferEvents.get()) {
     List<Integer> destTaskIndices = new ArrayList<Integer>();
     boolean isDataMovementEvent = true;
     switch (tezEvent.getEventType()) {
       case INPUT_FAILED_EVENT:
         isDataMovementEvent = false;
       case DATA_MOVEMENT_EVENT:
         Event event = tezEvent.getEvent();
         TezTaskAttemptID sourceAttemptId = tezEvent.getSourceInfo().getTaskAttemptID();
         int sourceTaskIndex = sourceAttemptId.getTaskID().getId();
         if (isDataMovementEvent) {
           edgeManager.routeEventToDestinationTasks(
               (DataMovementEvent) event,
               sourceTaskIndex,
               destinationVertex.getTotalTasks(),
               destTaskIndices);
         } else {
           edgeManager.routeEventToDestinationTasks(
               (InputFailedEvent) event,
               sourceTaskIndex,
               destinationVertex.getTotalTasks(),
               destTaskIndices);
         }
         for (Integer destTaskIndex : destTaskIndices) {
           EventMetaData destMeta =
               new EventMetaData(
                   EventProducerConsumerType.INPUT,
                   destinationVertex.getName(),
                   sourceVertex.getName(),
                   null); // will be filled by Task when sending the event. Is it needed?
           if (isDataMovementEvent) {
             destMeta.setIndex(((DataMovementEvent) event).getTargetIndex());
           } else {
             destMeta.setIndex(((InputFailedEvent) event).getTargetIndex());
           }
           tezEvent.setDestinationInfo(destMeta);
           TezTaskID destTaskId = destinationVertex.getTask(destTaskIndex).getTaskId();
           sendEventToTask(destTaskId, tezEvent);
         }
         break;
       default:
         throw new TezUncheckedException("Unhandled tez event type: " + tezEvent.getEventType());
     }
   } else {
     destinationEventBuffer.add(tezEvent);
   }
 }
 public InputSpec getDestinationSpec(int destinationTaskIndex) {
   return new InputSpec(
       sourceVertex.getName(),
       edgeProperty.getEdgeDestination(),
       edgeManager.getNumDestinationTaskInputs(
           sourceVertex.getTotalTasks(), destinationTaskIndex));
 }
 public OutputSpec getSourceSpec(int sourceTaskIndex) {
   return new OutputSpec(
       destinationVertex.getName(),
       edgeProperty.getEdgeSource(),
       edgeManager.getNumSourceTaskOutputs(destinationVertex.getTotalTasks(), sourceTaskIndex));
 }