public LinkedHashMap<NamedWindowConsumerView, NamedWindowDeltaData> getDeltaPerConsumer(
     Object perStmtObj, EPStatementAgentInstanceHandle handle) {
   List<NamedWindowConsumerDispatchUnit> list = (List<NamedWindowConsumerDispatchUnit>) perStmtObj;
   LinkedHashMap<NamedWindowConsumerView, NamedWindowDeltaData> deltaPerConsumer =
       new LinkedHashMap<NamedWindowConsumerView, NamedWindowDeltaData>();
   for (NamedWindowConsumerDispatchUnit unit : list) // for each unit
   {
     for (NamedWindowConsumerView consumerView : unit.getDispatchTo().get(handle)) // each consumer
     {
       NamedWindowDeltaData deltaForConsumer = deltaPerConsumer.get(consumerView);
       if (deltaForConsumer == null) {
         deltaPerConsumer.put(consumerView, unit.getDeltaData());
       } else {
         NamedWindowDeltaData aggregated =
             new NamedWindowDeltaData(deltaForConsumer, unit.getDeltaData());
         deltaPerConsumer.put(consumerView, aggregated);
       }
     }
   }
   return deltaPerConsumer;
 }
  private void processDispatches(
      ExprEvaluatorContext exprEvaluatorContext, NamedWindowConsumerDispatchUnit[] dispatches) {

    if (dispatches.length == 1) {
      NamedWindowConsumerDispatchUnit unit = dispatches[0];
      EventBean[] newData = unit.getDeltaData().getNewData();
      EventBean[] oldData = unit.getDeltaData().getOldData();

      if (MetricReportingPath.isMetricsEnabled) {
        for (Map.Entry<EPStatementAgentInstanceHandle, List<NamedWindowConsumerView>> entry :
            unit.getDispatchTo().entrySet()) {
          EPStatementAgentInstanceHandle handle = entry.getKey();
          if (handle.getStatementHandle().getMetricsHandle().isEnabled()) {
            long cpuTimeBefore = MetricUtil.getCPUCurrentThread();
            long wallTimeBefore = MetricUtil.getWall();

            processHandle(handle, entry.getValue(), newData, oldData, exprEvaluatorContext);

            long wallTimeAfter = MetricUtil.getWall();
            long cpuTimeAfter = MetricUtil.getCPUCurrentThread();
            long deltaCPU = cpuTimeAfter - cpuTimeBefore;
            long deltaWall = wallTimeAfter - wallTimeBefore;
            metricReportingService.accountTime(
                handle.getStatementHandle().getMetricsHandle(), deltaCPU, deltaWall, 1);
          } else {
            processHandle(handle, entry.getValue(), newData, oldData, exprEvaluatorContext);
          }

          if ((isPrioritized) && (handle.isPreemptive())) {
            break;
          }
        }
      } else {
        for (Map.Entry<EPStatementAgentInstanceHandle, List<NamedWindowConsumerView>> entry :
            unit.getDispatchTo().entrySet()) {
          EPStatementAgentInstanceHandle handle = entry.getKey();
          processHandle(handle, entry.getValue(), newData, oldData, exprEvaluatorContext);

          if ((isPrioritized) && (handle.isPreemptive())) {
            break;
          }
        }
      }

      return;
    }

    // Multiple different-result dispatches to same or different statements are needed in two
    // situations:
    // a) an event comes in, triggers two insert-into statements inserting into the same named
    // window and the window produces 2 results
    // b) a time batch is grouped in the named window, and a timer fires for both groups at the same
    // time producing more then one result
    // c) two on-merge/update/delete statements fire for the same arriving event each updating the
    // named window

    // Most likely all dispatches go to different statements since most statements are not joins of
    // named windows that produce results at the same time. Therefore sort by statement handle.
    Map<EPStatementAgentInstanceHandle, Object> dispatchesPerStmt = dispatchesPerStmtTL.get();
    for (NamedWindowConsumerDispatchUnit unit : dispatches) {
      for (Map.Entry<EPStatementAgentInstanceHandle, List<NamedWindowConsumerView>> entry :
          unit.getDispatchTo().entrySet()) {
        EPStatementAgentInstanceHandle handle = entry.getKey();
        Object perStmtObj = dispatchesPerStmt.get(handle);
        if (perStmtObj == null) {
          dispatchesPerStmt.put(handle, unit);
        } else if (perStmtObj instanceof List) {
          List<NamedWindowConsumerDispatchUnit> list =
              (List<NamedWindowConsumerDispatchUnit>) perStmtObj;
          list.add(unit);
        } else // convert from object to list
        {
          NamedWindowConsumerDispatchUnit unitObj = (NamedWindowConsumerDispatchUnit) perStmtObj;
          List<NamedWindowConsumerDispatchUnit> list =
              new ArrayList<NamedWindowConsumerDispatchUnit>();
          list.add(unitObj);
          list.add(unit);
          dispatchesPerStmt.put(handle, list);
        }
      }
    }

    // Dispatch - with or without metrics reporting
    if (MetricReportingPath.isMetricsEnabled) {
      for (Map.Entry<EPStatementAgentInstanceHandle, Object> entry : dispatchesPerStmt.entrySet()) {
        EPStatementAgentInstanceHandle handle = entry.getKey();
        Object perStmtObj = entry.getValue();

        // dispatch of a single result to the statement
        if (perStmtObj instanceof NamedWindowConsumerDispatchUnit) {
          NamedWindowConsumerDispatchUnit unit = (NamedWindowConsumerDispatchUnit) perStmtObj;
          EventBean[] newData = unit.getDeltaData().getNewData();
          EventBean[] oldData = unit.getDeltaData().getOldData();

          if (handle.getStatementHandle().getMetricsHandle().isEnabled()) {
            long cpuTimeBefore = MetricUtil.getCPUCurrentThread();
            long wallTimeBefore = MetricUtil.getWall();

            processHandle(
                handle, unit.getDispatchTo().get(handle), newData, oldData, exprEvaluatorContext);

            long wallTimeAfter = MetricUtil.getWall();
            long cpuTimeAfter = MetricUtil.getCPUCurrentThread();
            long deltaCPU = cpuTimeAfter - cpuTimeBefore;
            long deltaWall = wallTimeAfter - wallTimeBefore;
            metricReportingService.accountTime(
                handle.getStatementHandle().getMetricsHandle(), deltaCPU, deltaWall, 1);
          } else {
            Map<EPStatementAgentInstanceHandle, List<NamedWindowConsumerView>> entries =
                unit.getDispatchTo();
            List<NamedWindowConsumerView> items = entries.get(handle);
            if (items != null) {
              processHandle(handle, items, newData, oldData, exprEvaluatorContext);
            }
          }

          if ((isPrioritized) && (handle.isPreemptive())) {
            break;
          }

          continue;
        }

        // dispatch of multiple results to a the same statement, need to aggregate per consumer view
        LinkedHashMap<NamedWindowConsumerView, NamedWindowDeltaData> deltaPerConsumer =
            getDeltaPerConsumer(perStmtObj, handle);
        if (handle.getStatementHandle().getMetricsHandle().isEnabled()) {
          long cpuTimeBefore = MetricUtil.getCPUCurrentThread();
          long wallTimeBefore = MetricUtil.getWall();

          processHandleMultiple(handle, deltaPerConsumer, exprEvaluatorContext);

          long wallTimeAfter = MetricUtil.getWall();
          long cpuTimeAfter = MetricUtil.getCPUCurrentThread();
          long deltaCPU = cpuTimeAfter - cpuTimeBefore;
          long deltaWall = wallTimeAfter - wallTimeBefore;
          metricReportingService.accountTime(
              handle.getStatementHandle().getMetricsHandle(), deltaCPU, deltaWall, 1);
        } else {
          processHandleMultiple(handle, deltaPerConsumer, exprEvaluatorContext);
        }

        if ((isPrioritized) && (handle.isPreemptive())) {
          break;
        }
      }
    } else {

      for (Map.Entry<EPStatementAgentInstanceHandle, Object> entry : dispatchesPerStmt.entrySet()) {
        EPStatementAgentInstanceHandle handle = entry.getKey();
        Object perStmtObj = entry.getValue();

        // dispatch of a single result to the statement
        if (perStmtObj instanceof NamedWindowConsumerDispatchUnit) {
          NamedWindowConsumerDispatchUnit unit = (NamedWindowConsumerDispatchUnit) perStmtObj;
          EventBean[] newData = unit.getDeltaData().getNewData();
          EventBean[] oldData = unit.getDeltaData().getOldData();

          processHandle(
              handle, unit.getDispatchTo().get(handle), newData, oldData, exprEvaluatorContext);

          if ((isPrioritized) && (handle.isPreemptive())) {
            break;
          }

          continue;
        }

        // dispatch of multiple results to a the same statement, need to aggregate per consumer view
        LinkedHashMap<NamedWindowConsumerView, NamedWindowDeltaData> deltaPerConsumer =
            getDeltaPerConsumer(perStmtObj, handle);
        processHandleMultiple(handle, deltaPerConsumer, exprEvaluatorContext);

        if ((isPrioritized) && (handle.isPreemptive())) {
          break;
        }
      }
    }

    dispatchesPerStmt.clear();
    return;
  }