private void compareSubsystemModels() {
    System.out.println("====== Comparing subsystem models ======");
    ResourceDefinition rootCurrentDefinition =
        new ResourceDefinition(trimNonSubsystem(currentResourceDefinitions), currentModelVersions);
    ResourceDefinition rootLegacyDefinition =
        new ResourceDefinition(trimNonSubsystem(legacyResourceDefinitions), legacyModelVersions);
    Map<String, ModelNode> currentSubsystems = rootCurrentDefinition.getChildren(SUBSYSTEM);
    Map<String, ModelNode> legacySubsystems = rootLegacyDefinition.getChildren(SUBSYSTEM);

    CompareContext context =
        new CompareContext(
            PathAddress.EMPTY_ADDRESS,
            PathAddress.EMPTY_ADDRESS,
            true,
            rootCurrentDefinition,
            rootLegacyDefinition);
    compareKeySetsAndRemoveMissing(context, "subsystems", currentSubsystems, legacySubsystems);

    for (Map.Entry<String, ModelNode> legacyEntry : legacySubsystems.entrySet()) {
      PathAddress subsystemAddress =
          PathAddress.pathAddress(PathElement.pathElement(SUBSYSTEM, legacyEntry.getKey()));
      ResourceDefinition currentDefinition =
          new ResourceDefinition(currentSubsystems.get(legacyEntry.getKey()), currentModelVersions);
      ResourceDefinition legacyDefinition =
          new ResourceDefinition(legacyEntry.getValue(), legacyModelVersions);
      context =
          new CompareContext(
              subsystemAddress, subsystemAddress, false, currentDefinition, legacyDefinition);
      if (!context.continuteWithCheck()) {
        continue;
      }
      compareModel(context);
    }
  }
  private void compareChildren(CompareContext context) {
    Set<String> legacyChildTypes = context.getLegacyDefinition().getChildTypes();
    Set<String> currentChildTypes = context.getCurrentDefinition().getChildTypes();

    compareSetsAndRemoveMissing(context, "child types", currentChildTypes, legacyChildTypes);

    for (String type : legacyChildTypes) {
      Map<String, ModelNode> legacyChildren = context.getLegacyDefinition().getChildren(type);
      Map<String, ModelNode> currentChildren = context.getCurrentDefinition().getChildren(type);

      compareKeySetsAndRemoveMissing(
          context, "child names for type=" + type, currentChildren, legacyChildren);

      for (Map.Entry<String, ModelNode> legacyChildEntry : legacyChildren.entrySet()) {
        String name = legacyChildEntry.getKey();
        ModelNode legacyChildDescription = legacyChildEntry.getValue();
        ModelNode currentChildDescription = currentChildren.get(name);

        CompareContext childContext;
        try {
          childContext =
              new CompareContext(
                  context.getRootAddress(),
                  context.getPathAddress().append(PathElement.pathElement(type, name)),
                  context.isCore(),
                  new ResourceDefinition(currentChildDescription, currentModelVersions),
                  new ResourceDefinition(legacyChildDescription, legacyModelVersions));
        } catch (RuntimeException e) {
          System.out.println(context.getPathAddress() + " + " + type + "=" + name);
          throw e;
        }
        compareModel(childContext);
      }
    }
  }
  private void compareValueType(
      CompareContext context, String id, ModelNode current, ModelNode legacy) {
    ModelNode currentValueType = current.get(VALUE_TYPE);
    ModelNode legacyValueType = legacy.get(VALUE_TYPE);
    if (!currentValueType.isDefined() && !legacyValueType.isDefined()) {
      return;
    }
    if (isType(legacyValueType) || isType(currentValueType)) {
      if (!currentValueType.equals(legacyValueType)) {
        context.println(
            "Different 'value-type' for "
                + id
                + ". Current: "
                + current.get(VALUE_TYPE)
                + "; legacy: "
                + legacy.get(VALUE_TYPE));
      }
    } else {
      Map<String, ModelNode> legacyValueTypes = createMapIndexedByKey(legacyValueType);
      Map<String, ModelNode> currentValueTypes = createMapIndexedByKey(currentValueType);

      compareKeySetsAndRemoveMissing(
          context, "value-type for " + id, currentValueTypes, legacyValueTypes);
      for (Map.Entry<String, ModelNode> entry : currentValueTypes.entrySet()) {
        ModelNode currentEntry = entry.getValue();
        ModelNode legacyEntry = legacyValueTypes.get(entry.getKey());
        compareAttributeOrOperationParameter(
            context,
            "value-type key '" + entry.getKey() + "' for " + id,
            currentEntry,
            legacyEntry);
      }
    }
  }
  private void compareAttributes(CompareContext context) {
    Map<String, ModelNode> legacyAttributes = context.getLegacyDefinition().getAttributes();
    Map<String, ModelNode> currentAttributes = context.getCurrentDefinition().getAttributes();

    compareKeySetsAndRemoveMissing(context, "attributes", currentAttributes, legacyAttributes);
    // TODO compare types, expressions etc.

    for (Map.Entry<String, ModelNode> legacyEntry : legacyAttributes.entrySet()) {
      ModelNode legacyAttribute = legacyEntry.getValue();
      ModelNode currentAttribute = currentAttributes.get(legacyEntry.getKey());

      String id = "attribute '" + legacyEntry.getKey() + "'";
      compareAttributeOrOperationParameter(context, id, currentAttribute, legacyAttribute);
      compareAccessType(context, id, currentAttribute, legacyAttribute);
      compareStorage(context, id, currentAttribute, legacyAttribute);
      compareDefault(context, id, currentAttribute, legacyAttribute);
    }
  }
 private void compareCoreModels() {
   System.out.println("====== Comparing core models ======");
   ResourceDefinition currentDefinition =
       new ResourceDefinition(trimSubsystem(currentResourceDefinitions), currentModelVersions);
   ResourceDefinition legacyDefinition =
       new ResourceDefinition(trimSubsystem(legacyResourceDefinitions), legacyModelVersions);
   CompareContext context =
       new CompareContext(
           PathAddress.EMPTY_ADDRESS,
           PathAddress.EMPTY_ADDRESS,
           true,
           currentDefinition,
           legacyDefinition);
   if (!context.continuteWithCheck()) {
     return;
   }
   compareModel(context);
 }
  private void compareOperations(CompareContext context) {
    Map<String, ModelNode> legacyOperations = context.getLegacyDefinition().getOperations();
    Map<String, ModelNode> currentOperations = context.getCurrentDefinition().getOperations();

    compareKeySetsAndRemoveMissing(context, "operations", currentOperations, legacyOperations);

    for (Map.Entry<String, ModelNode> legacyOpEntry : legacyOperations.entrySet()) {
      String operationName = legacyOpEntry.getKey();
      ModelNode legacyOperation = legacyOpEntry.getValue();
      ModelNode currentOperation = currentOperations.get(operationName);

      Map<String, ModelNode> legacyParameters =
          context.getLegacyDefinition().getOperationParameters(operationName);
      Map<String, ModelNode> currentParameters =
          context.getCurrentDefinition().getOperationParameters(operationName);

      compareKeySetsAndRemoveMissing(
          context,
          "parameters for operation '" + operationName + "'",
          currentParameters,
          legacyParameters);

      for (Map.Entry<String, ModelNode> legacyParamEntry : legacyParameters.entrySet()) {
        ModelNode legacyParameter = legacyParamEntry.getValue();
        ModelNode currentParameter = currentParameters.get(legacyParamEntry.getKey());

        String id =
            "parameter '" + legacyParamEntry.getKey() + "' of operation '" + operationName + "'";
        compareAttributeOrOperationParameter(context, id, currentParameter, legacyParameter);
      }

      ModelNode legacyReply = legacyOperation.get(REPLY_PROPERTIES);
      ModelNode currentReply = currentOperation.get(REPLY_PROPERTIES);
      compareAttributeOrOperationParameter(
          context,
          "'reply-properties' for operation '" + operationName + "'",
          currentReply,
          legacyReply);
      //            if (!currentReply.equals(legacyReply)) {
      //                context.println("Different 'reply-properties' for operation '" +
      // operationName + "'. Current: " + currentReply + "; legacy: " + legacyReply);
      //            }
    }
  }
 private void compareType(CompareContext context, String id, ModelNode current, ModelNode legacy) {
   if (!current.get(TYPE).equals(legacy.get(TYPE))) {
     context.println(
         "Different 'type' for "
             + id
             + ". Current: "
             + current.get(TYPE)
             + "; legacy: "
             + legacy.get(TYPE));
   }
 }
 private void compareAlternatives(
     CompareContext context, String id, ModelNode current, ModelNode legacy) {
   if (!current.get(ALTERNATIVES).equals(legacy.get(ALTERNATIVES))) {
     context.println(
         "Different 'alternatives' for "
             + id
             + ". Current: "
             + current.get(ALTERNATIVES)
             + "; legacy: "
             + legacy.get(ALTERNATIVES));
   }
 }
 private void compareDeprecated(
     CompareContext context, String id, ModelNode current, ModelNode legacy) {
   if (!current.get(DEPRECATED).equals(legacy.get(DEPRECATED))) {
     context.println(
         "Different 'deprecated' for "
             + id
             + ". Current: "
             + current.get(DEPRECATED)
             + "; legacy: "
             + legacy.get(DEPRECATED));
   }
 }
 private void compareDefault(
     CompareContext context, String id, ModelNode current, ModelNode legacy) {
   if (!current.get(DEFAULT).equals(legacy.get(DEFAULT))) {
     context.println(
         "Different 'default' for "
             + id
             + ". Current: "
             + current.get(DEFAULT)
             + "; legacy: "
             + legacy.get(DEFAULT));
   }
 }
 private void compareExpressionsAllowed(
     CompareContext context, String id, ModelNode current, ModelNode legacy) {
   boolean currentNillable = current.get(EXPRESSIONS_ALLOWED).asBoolean(false);
   boolean legacyNillable = legacy.get(EXPRESSIONS_ALLOWED).asBoolean(false);
   if (currentNillable != legacyNillable) {
     context.println(
         "Different 'expressions-allowed' for "
             + id
             + ". Current: "
             + currentNillable
             + "; legacy: "
             + legacyNillable);
   }
 }
 private void compareNillable(
     CompareContext context, String id, ModelNode current, ModelNode legacy) {
   boolean currentNillable = current.get(NILLABLE).asBoolean(false);
   boolean legacyNillable = legacy.get(NILLABLE).asBoolean(false);
   if (currentNillable != legacyNillable) {
     context.println(
         "Different 'nillable' for "
             + id
             + ". Current: "
             + currentNillable
             + "; legacy: "
             + legacyNillable);
   }
 }
  private Set<String> getMissingNames(
      CompareContext context, Set<String> possiblyMissing, Set<String> names) {
    Set<String> missing = new HashSet<String>(possiblyMissing);
    for (String name : names) {
      missing.remove(name);
    }

    // 7.1.2 did not have MANAGEMENT_MICRO_VERSION don't bother reporting that
    if (context.isVersionLevel()
        && missing.contains(MANAGEMENT_MICRO_VERSION)
        && names.contains(MANAGEMENT_MAJOR_VERSION)
        && names.contains(MANAGEMENT_MINOR_VERSION)) {
      missing.remove(MANAGEMENT_MICRO_VERSION);
    }

    return missing;
  }
  private void compareSetsAndRemoveMissing(
      CompareContext context, String type, Set<String> currentSet, Set<String> legacySet) {
    Set<String> extraInLegacy = getMissingNames(context, legacySet, currentSet);
    Set<String> extraInCurrent = getMissingNames(context, currentSet, legacySet);

    if (extraInLegacy.size() > 0 || extraInCurrent.size() > 0) {
      context.println(
          "Missing "
              + type
              + " in current: "
              + extraInLegacy
              + "; missing in legacy "
              + extraInCurrent);
      if (extraInCurrent.size() > 0) {
        currentSet.removeAll(extraInCurrent);
      }
      if (extraInLegacy.size() > 0) {
        legacySet.removeAll(extraInLegacy);
      }
    }
  }