docs: private void rollback(final String patchID, final IdentityPatchContext context) throws PatchingException {
          try {
  
              // Load the patch history
              final PatchingTaskContext.Mode mode = context.getMode();
              final Patch originalPatch = loadPatchInformation(patchID, installedImage);
              final RollbackPatch rollbackPatch = loadRollbackInformation(patchID, installedImage);
              final Patch.PatchType patchType = rollbackPatch.getIdentity().getPatchType();
              final InstalledIdentity history = rollbackPatch.getIdentityState();
  
              // Process originals by type first
              final LinkedHashMap<String, PatchElement> originalLayers = new LinkedHashMap<String, PatchElement>();
              final LinkedHashMap<String, PatchElement> originalAddOns = new LinkedHashMap<String, PatchElement>();
              for (final PatchElement patchElement : originalPatch.getElements()) {
                  final PatchElementProvider provider = patchElement.getProvider();
                  final String layerName = provider.getName();
                  final LayerType layerType = provider.getLayerType();
                  final Map<String, PatchElement> originals;
                  switch (layerType) {
                      case Layer:
                          originals = originalLayers;
                          break;
                      case AddOn:
                          originals = originalAddOns;
                          break;
                      default:
                          throw new IllegalStateException();
                  }
                  if (!originals.containsKey(layerName)) {
                      originals.put(layerName, patchElement);
                  } else {
                      throw PatchLogger.ROOT_LOGGER.installationDuplicateLayer(layerType.toString(), layerName);
                  }
              }
              // Process the rollback xml
              for (final PatchElement patchElement : rollbackPatch.getElements()) {
                  final String elementPatchId = patchElement.getId();
                  final PatchElementProvider provider = patchElement.getProvider();
                  final String layerName = provider.getName();
                  final LayerType layerType = provider.getLayerType();
                  final LinkedHashMap<String, PatchElement> originals;
                  switch (layerType) {
                      case Layer:
                          originals = originalLayers;
                          break;
                      case AddOn:
                          originals = originalAddOns;
                          break;
                      default:
                          throw new IllegalStateException();
                  }
                  final PatchElement original = originals.remove(layerName);
                  if (original == null) {
                      throw PatchLogger.ROOT_LOGGER.noSuchLayer(layerName);
                  }
                  final IdentityPatchContext.PatchEntry entry = context.resolveForElement(patchElement);
                  // Create the rollback
                  PatchingTasks.rollback(elementPatchId, original.getModifications(), patchElement.getModifications(), entry, ContentItemFilter.ALL_BUT_MISC, mode);
                  entry.rollback(original.getId());
  
                  // We need to restore the previous state
                  final Patch.PatchType elementPatchType = provider.getPatchType();
                  final PatchableTarget.TargetInfo info;
                  if (layerType == LayerType.AddOn) {
                      info = history.getAddOn(layerName).loadTargetInfo();
                  } else {
                      info = history.getLayer(layerName).loadTargetInfo();
                  }
                  if (mode == ROLLBACK) {
                      restoreFromHistory(entry, elementPatchId, elementPatchType, info);
                  }
              }
              if (!originalLayers.isEmpty() || !originalAddOns.isEmpty()) {
                  throw PatchLogger.ROOT_LOGGER.invalidRollbackInformation();
              }
  
              // Rollback the patch
              final IdentityPatchContext.PatchEntry identity = context.getIdentityEntry();
              PatchingTasks.rollback(patchID, originalPatch.getModifications(), rollbackPatch.getModifications(), identity, ContentItemFilter.MISC_ONLY, mode);
              identity.rollback(patchID);
  
              // Restore previous state
              if (mode == ROLLBACK) {
                  final PatchableTarget.TargetInfo identityHistory = history.getIdentity().loadTargetInfo();
                  restoreFromHistory(identity, rollbackPatch.getPatchId(), patchType, identityHistory);
                  if(patchType == Patch.PatchType.CUMULATIVE) {
                      reenableNotOverridenModules(rollbackPatch, context);
                  }
              }
  
              if (patchType == Patch.PatchType.CUMULATIVE) {
                  final Identity.IdentityUpgrade upgrade = rollbackPatch.getIdentity().forType(Patch.PatchType.CUMULATIVE, Identity.IdentityUpgrade.class);
                  identity.setResultingVersion(upgrade.getResultingVersion());
              }
          } catch (Exception e) {
              throw rethrowException(e);
          }
      }