@Override
  public boolean hasNext() {
    while (next == null && toConsumeEvents.size() > 0) {
      WindowEvent toConsumeEvent = toConsumeEvents.removeFirst();
      String consumedId = toConsumeEvent.getWindowId();

      //
      PortletInfo consumerPortletInfo = context.getPortletInfo(consumedId);
      if (consumerPortletInfo == null) {
        log.trace(
            "Cannot deliver event "
                + toConsumeEvent
                + " because the consumer of the event does not have a portlet info");
        safeInvoker.eventDiscarded(
            context.getEventControllerContext(),
            this,
            toConsumeEvent,
            EventControllerContext.EVENT_CONSUMER_INFO_NOT_AVAILABLE);
        continue;
      }

      //
      if (!controller.getDistributeNonConsumableEvents()) {
        if (!consumerPortletInfo
            .getEventing()
            .getConsumedEvents()
            .containsKey(toConsumeEvent.getName())) {
          log.trace(
              "Cannot deliver event "
                  + toConsumeEvent
                  + " because the consumer of the event does not accept the event name");
          safeInvoker.eventDiscarded(
              context.getEventControllerContext(),
              this,
              toConsumeEvent,
              EventControllerContext.PORTLET_DOES_NOT_CONSUME_EVENT);
          continue;
        }
      }

      //
      next = toConsumeEvent;
    }

    //
    return next != null;
  }
  /**
   * Fill the UI component with both information from the persistent model and some coming from the
   * portlet.xml defined by the JSR 286 specification
   */
  private static <S> void toUIPortlet(UIPortlet<S, ?> uiPortlet, Application<S> model) {

    //
    PortletState<S> portletState = new PortletState<S>(model.getState(), model.getType());

    /*
     * Fill UI component object with info from the XML file that persist portlet information
     */
    uiPortlet.setWidth(model.getWidth());
    uiPortlet.setHeight(model.getHeight());
    uiPortlet.setState(portletState);
    uiPortlet.setTitle(model.getTitle());
    uiPortlet.setIcon(model.getIcon());
    uiPortlet.setDescription(model.getDescription());
    uiPortlet.setShowInfoBar(model.getShowInfoBar());
    uiPortlet.setShowWindowState(model.getShowApplicationState());
    uiPortlet.setShowPortletMode(model.getShowApplicationMode());
    uiPortlet.setProperties(model.getProperties());
    uiPortlet.setTheme(model.getTheme());
    if (model.getAccessPermissions() != null)
      uiPortlet.setAccessPermissions(model.getAccessPermissions());
    uiPortlet.setModifiable(model.isModifiable());

    Portlet portlet = uiPortlet.getProducedOfferedPortlet();
    if (portlet == null || portlet.getInfo() == null) return;

    PortletInfo portletInfo = portlet.getInfo();

    /*
     * Define which portlet modes the portlet supports and hence should be shown in the portlet info bar
     */
    Set<ModeInfo> modes = portletInfo.getCapabilities().getModes(MediaType.create("text/html"));
    List<String> supportModes = new ArrayList<String>();
    for (ModeInfo modeInfo : modes) {
      String modeName = modeInfo.getModeName().toLowerCase();
      if ("config".equals(modeInfo.getModeName())) {
        supportModes.add(modeName);
      } else {
        supportModes.add(modeName);
      }
    }

    if (supportModes.size() > 1) supportModes.remove("view");
    uiPortlet.setSupportModes(supportModes);
  }
  boolean push(WindowEvent consumedEvent, WindowEvent producedEvent) {
    String producerId = producedEvent.getWindowId();
    PortletInfo producerPortletInfo = context.getPortletInfo(producerId);

    //
    if (producerPortletInfo == null) {
      log.trace(
          "Cannot deliver event "
              + producedEvent
              + " because the producer does not have portlet info");
      safeInvoker.eventDiscarded(
          context.getEventControllerContext(),
          this,
          producedEvent,
          EventControllerContext.EVENT_PRODUCER_INFO_NOT_AVAILABLE);
      return true;
    } else {
      //
      if (!controller.getDistributeNonProduceableEvents()) {
        if (!producerPortletInfo
            .getEventing()
            .getProducedEvents()
            .containsKey(producedEvent.getName())) {
          log.trace(
              "Cannot deliver event "
                  + producedEvent
                  + " because the producer of the event does not produce the event name");
          safeInvoker.eventDiscarded(
              context.getEventControllerContext(),
              this,
              producedEvent,
              EventControllerContext.PORTLET_DOES_NOT_CONSUME_EVENT);
          return true;
        }
      }

      // Apply produced event quota if necessary
      int producedEventThreshold = controller.getProducedEventThreshold();
      if (producedEventThreshold >= 0) {
        if (producedEventSize + 1 > producedEventThreshold) {
          log.trace(
              "Event distribution interrupted because the maximum number of produced event is reached");
          safeInvoker.eventDiscarded(
              context.getEventControllerContext(),
              this,
              producedEvent,
              EventControllerContext.PRODUCED_EVENT_FLOODED);
          return false;
        }
      }

      //
      Iterable<WindowEvent> toConsume =
          safeInvoker.eventProduced(
              context.getEventControllerContext(), this, consumedEvent, producedEvent);

      //
      if (toConsume == null) {
        return false;
      } else {
        producedEventSize++;
        for (WindowEvent event : toConsume) {
          toConsumeEvents.add(event);
        }
        return true;
      }
    }
  }