/**
   * Restore the configuration. Depending on reset-configuration this is going to replace the
   * original files with the backup, otherwise it will create a restored-configuration folder the
   * configuration directories.
   *
   * <p>TODO log a warning if the restored configuration files are different from the current one?
   * or should we check that before rolling back the patch to give the user a chance to save the
   * changes
   *
   * @param rollingBackPatchID the patch id
   * @param resetConfiguration whether to override the configuration files or not
   * @throws IOException for any error
   */
  void restoreConfiguration(final String rollingBackPatchID, final boolean resetConfiguration)
      throws IOException {

    final File backupConfigurationDir =
        new File(installedImage.getPatchHistoryDir(rollingBackPatchID), Constants.CONFIGURATION);
    final File ba = new File(backupConfigurationDir, Constants.APP_CLIENT);
    final File bd = new File(backupConfigurationDir, Constants.DOMAIN);
    final File bs = new File(backupConfigurationDir, Constants.STANDALONE);

    final String configuration;
    if (resetConfiguration) {
      configuration = Constants.CONFIGURATION;
    } else {
      configuration = Constants.CONFIGURATION + File.separator + Constants.RESTORED_CONFIGURATION;
    }

    if (ba.exists()) {
      final File a = new File(installedImage.getAppClientDir(), configuration);
      backupDirectory(ba, a);
    }
    if (bd.exists()) {
      final File d = new File(installedImage.getDomainDir(), configuration);
      backupDirectory(bd, d);
    }
    if (bs.exists()) {
      final File s = new File(installedImage.getStandaloneDir(), configuration);
      backupDirectory(bs, s);
    }
  }
 /**
  * Add a rollback loader for a give patch.
  *
  * @param patchId the patch id.
  * @param target the patchable target
  * @throws XMLStreamException
  * @throws IOException
  */
 private void recordRollbackLoader(final String patchId, PatchableTarget.TargetInfo target) {
   // setup the content loader paths
   final DirectoryStructure structure = target.getDirectoryStructure();
   final InstalledImage image = structure.getInstalledImage();
   final File historyDir = image.getPatchHistoryDir(patchId);
   final File miscRoot = new File(historyDir, PatchContentLoader.MISC);
   final File modulesRoot = structure.getModulePatchDirectory(patchId);
   final File bundlesRoot = structure.getBundlesPatchDirectory(patchId);
   final PatchContentLoader loader = PatchContentLoader.create(miscRoot, bundlesRoot, modulesRoot);
   //
   recordContentLoader(patchId, loader);
 }
  IdentityPatchContext(
      final File backup,
      final PatchContentProvider contentProvider,
      final ContentVerificationPolicy contentPolicy,
      final InstallationManager.InstallationModification modification,
      final PatchingTaskContext.Mode mode,
      final InstalledImage installedImage) {

    this.miscTargetRoot = installedImage.getJbossHome();

    this.mode = mode;
    this.contentProvider = contentProvider;
    this.contentPolicy = contentPolicy;
    this.modification = modification;
    this.installedImage = installedImage;
    this.history =
        PatchingHistory.Factory.getHistory(modification.getUnmodifiedInstallationState());

    if (backup != null) {
      this.miscBackup = new File(backup, PatchContentLoader.MISC);
      this.configBackup = new File(backup, Constants.CONFIGURATION);
    } else {
      this.miscBackup = null; // This will trigger a failure when the root is actually needed
      this.configBackup = null;
    }
    this.identityEntry = new PatchEntry(modification, null);
  }
  /**
   * Backup the current configuration as part of the patch history.
   *
   * @throws IOException for any error
   */
  void backupConfiguration() throws IOException {

    final String configuration = Constants.CONFIGURATION;

    final File a = new File(installedImage.getAppClientDir(), configuration);
    final File d = new File(installedImage.getDomainDir(), configuration);
    final File s = new File(installedImage.getStandaloneDir(), configuration);

    if (a.exists()) {
      final File ab = new File(configBackup, Constants.APP_CLIENT);
      backupDirectory(a, ab);
    }
    if (d.exists()) {
      final File db = new File(configBackup, Constants.DOMAIN);
      backupDirectory(d, db);
    }
    if (s.exists()) {
      final File sb = new File(configBackup, Constants.STANDALONE);
      backupDirectory(s, sb);
    }
  }
 /**
  * Complete the current operation and persist the current state to the disk. This will also
  * trigger the invalidation of outdated modules.
  *
  * @param modification the current modification
  * @param callback the completion callback
  */
 private void complete(
     final InstallationManager.InstallationModification modification,
     final FinalizeCallback callback) {
   final List<File> processed = new ArrayList<File>();
   try {
     try {
       // Update the state to invalidate and process module resources
       if (stateUpdater.compareAndSet(this, State.PREPARED, State.INVALIDATE)
           && mode == PatchingTaskContext.Mode.APPLY) {
         // Only invalidate modules when applying patches; on rollback files are immediately
         // restored
         for (final File invalidation : moduleInvalidations) {
           processed.add(invalidation);
           PatchModuleInvalidationUtils.processFile(invalidation, mode);
         }
       }
       modification.complete();
       callback.completed(this);
       state = State.COMPLETED;
     } catch (Exception e) {
       this.moduleInvalidations.clear();
       this.moduleInvalidations.addAll(processed);
       throw new RuntimeException(e);
     }
   } finally {
     if (state != State.COMPLETED) {
       try {
         modification.cancel();
       } finally {
         try {
           undoChanges();
         } finally {
           callback.operationCancelled(this);
         }
       }
     } else {
       try {
         if (checkForGarbageOnRestart) {
           final File cleanupMarker =
               new File(installedImage.getInstallationMetadata(), "cleanup-patching-dirs");
           cleanupMarker.createNewFile();
         }
       } catch (IOException e) {
         PatchLogger.ROOT_LOGGER.infof(e, "failed to create cleanup marker");
       }
     }
   }
 }