private void formatFirstBatch(UpgradeContext ctx, ManualTask task, List<StageWrapper> wrappers) {
      Set<String> names = new LinkedHashSet<>();
      Map<String, Set<String>> compLocations = new HashMap<>();

      for (StageWrapper sw : wrappers) {
        for (TaskWrapper tw : sw.getTasks()) {
          if (StringUtils.isNotEmpty(tw.getService()) &&
              StringUtils.isNotBlank(tw.getComponent())) {

            for (String host : tw.getHosts()) {
              if (!compLocations.containsKey(host)) {
                compLocations.put(host, new HashSet<>());
              }
              compLocations.get(host).add(tw.getComponent());
            }

            names.add(ctx.getComponentDisplay(
                tw.getService(), tw.getComponent()));
          }
        }
      }

      for(int i = 0; i < task.messages.size(); i++){
        String message = task.messages.get(i);
        // !!! add the display names to the message, if needed
        if (message.contains("{{components}}")) {
          StringBuilder sb = new StringBuilder();

          List<String> compNames = new ArrayList<>(names);

          if (compNames.size() == 1) {
            sb.append(compNames.get(0));
          } else if (names.size() > 1) {
            String last = compNames.remove(compNames.size() - 1);
            sb.append(StringUtils.join(compNames, ", "));
            sb.append(" and ").append(last);
          }

          message = message.replace("{{components}}", sb.toString());

          //Add the updated message back to the message list.
          task.messages.set(i, message);
        }
      }

      // !!! build the structured out to attach to the manual task
      JsonArray arr = new JsonArray();
      for (Entry<String, Set<String>> entry : compLocations.entrySet()) {
        JsonObject obj = new JsonObject();
        obj.addProperty("host_name", entry.getKey());

        JsonArray comps = new JsonArray();
        for (String comp : entry.getValue()) {
          comps.add(new JsonPrimitive(comp));
        }
        obj.add("components", comps);

        arr.add(obj);
      }

      JsonObject master = new JsonObject();
      master.add("topology", arr);

      task.structuredOut = master.toString();
    }
Formats the first batch's text and adds json for use if needed.
@param ctx       the upgrade context to load component display names
@param task      the manual task representing the verification message
@param wrappers  the list of stage wrappers
ambari-server/src/main/java/org/apache/ambari/server/stack/upgrade/ColocatedGrouping.java