@Override
  public void process(ClusterEvent event) throws Exception {
    Cluster cluster = event.getAttribute("Cluster");
    Map<StateModelDefId, StateModelDefinition> stateModelDefMap = cluster.getStateModelMap();
    Map<ResourceId, ResourceConfig> resourceMap =
        event.getAttribute(AttributeName.RESOURCES.toString());
    ResourceCurrentState currentStateOutput =
        event.getAttribute(AttributeName.CURRENT_STATE.toString());
    BestPossibleStateOutput bestPossibleStateOutput =
        event.getAttribute(AttributeName.BEST_POSSIBLE_STATE.toString());
    MessageOutput messageGenOutput = event.getAttribute(AttributeName.MESSAGES_ALL.toString());
    if (cluster == null
        || resourceMap == null
        || currentStateOutput == null
        || messageGenOutput == null
        || bestPossibleStateOutput == null) {
      throw new StageException(
          "Missing attributes in event:"
              + event
              + ". Requires Cluster|RESOURCES|CURRENT_STATE|BEST_POSSIBLE_STATE|MESSAGES_ALL");
    }

    MessageOutput output = new MessageOutput();

    for (ResourceId resourceId : resourceMap.keySet()) {
      ResourceConfig resource = resourceMap.get(resourceId);
      StateModelDefinition stateModelDef =
          stateModelDefMap.get(resource.getIdealState().getStateModelDefId());

      if (stateModelDef == null) {
        LOG.info(
            "resource: "
                + resourceId
                + " doesn't have state-model-def; e.g. we add a resource config but not add the resource in ideal-states");
        continue;
      }

      // TODO have a logical model for transition
      Map<String, Integer> stateTransitionPriorities = getStateTransitionPriorityMap(stateModelDef);
      Resource configResource = cluster.getResource(resourceId);

      // if configResource == null, the resource has been dropped
      Map<State, Bounds> stateConstraints =
          computeStateConstraints(
              stateModelDef,
              configResource == null ? null : configResource.getIdealState(),
              cluster);

      // TODO fix it
      for (PartitionId partitionId :
          bestPossibleStateOutput.getResourceAssignment(resourceId).getMappedPartitionIds()) {
        List<Message> messages = messageGenOutput.getMessages(resourceId, partitionId);
        List<Message> selectedMessages =
            selectMessages(
                cluster.getLiveParticipantMap(),
                currentStateOutput.getCurrentStateMap(resourceId, partitionId),
                currentStateOutput.getPendingStateMap(resourceId, partitionId),
                messages,
                stateConstraints,
                stateTransitionPriorities,
                stateModelDef.getTypedInitialState());
        output.setMessages(resourceId, partitionId, selectedMessages);
      }
    }
    event.addAttribute(AttributeName.MESSAGES_SELECTED.toString(), output);
  }