if (pids.isEmpty()) {
return null;
}
ProcessExecutionResults results;
ServerControl.Cli cli = control.cli().disconnected(true);
Result<List<PatchDetails>> history = getPatchHistory(control, operation);
if (history.failed()) {
return history.errorMessage;
}
List<PatchDetails> installedPatches = history.result;
List<String> pidsToRollback = new ArrayList<String>(pids);
List<String> noLongerRemovablePids = new ArrayList<String>();
Set<String> installedPids = new HashSet<String>();
int lastPidToRollback = 0;
int installedPidIdx = 0;
for (; installedPidIdx < installedPatches.size() &&
lastPidToRollback < pidsToRollback.size(); ++installedPidIdx) {
PatchDetails installed = installedPatches.get(installedPidIdx);
String pidToRollback = pidsToRollback.get(lastPidToRollback);
String installedId = installed.getId();
if (installedId.equals(pidToRollback)) {
lastPidToRollback++;
} else {
while (!installedId.equals(pidToRollback) && lastPidToRollback < pidsToRollback.size()) {
pidToRollback = pidsToRollback.get(lastPidToRollback);
noLongerRemovablePids.add(pidsToRollback.remove(lastPidToRollback));
}
if (installedId.equals(pidToRollback)) {
lastPidToRollback++;
}
}
installedPids.add(installedId);
}
for (; installedPidIdx < installedPatches.size(); ++installedPidIdx) {
installedPids.add(installedPatches.get(installedPidIdx).getId());
}
// remove pids that we have not seen installed
if (lastPidToRollback < pidsToRollback.size()) {
List<String> uninstalledPids = pidsToRollback.subList(lastPidToRollback, pidsToRollback.size());
noLongerRemovablePids.addAll(uninstalledPids);
uninstalledPids.clear();
}
boolean inconsistent = false;
for (String pid : noLongerRemovablePids) {
if (installedPids.contains(pid)) {
// the current patch state is inconsistent with what we're expecting, because
// we see pids that are still installed but are no longer on rollback-able positions
// even though they should.
// If they're no longer installed then that's actually OK, we'd be rolling them back anyway.
inconsistent = true;
break;
}
}
if (pidsToRollback.isEmpty()) {
if (noLongerRemovablePids.isEmpty()) {
audit(bmp, rd, "Rollback", "Nothing To Do", BundleResourceDeploymentHistory.Status.WARN,
"None of the patches " + pids + " is installed anymore.");
return null;
} else {
String message = "The following patches were not rolled back due to other patches having been applied in the meantime: " +
noLongerRemovablePids + ". No other patches can be rolled back.";
if (inconsistent) {
return message;
} else {
audit(bmp, rd, "Rollback", "Missing patches", BundleResourceDeploymentHistory.Status.WARN,
"The following patches were to be rolled back but they aren't installed anymore: " +
noLongerRemovablePids + ".");
}
}
}
Configuration deploymentConfiguration = rd.getBundleDeployment().getConfiguration();
//if the server is online, let's bring it down for the duration of the rollback.
Result<Boolean> stop = stopIfNeeded(connection, control, deploymentConfiguration, bmp, rd);
if (stop.failed()) {
return stop.errorMessage;
}
boolean serverWasUp = stop.result;
List<String> patchCommands = new ArrayList<String>();
for (String pid : pidsToRollback) {
patchCommands.add(PATCH_ROLLBACK_COMMAND + pid);
}
String errorMessage = null;
try {
int i = 0;
for (String command : patchCommands) {
results = cli.executeCliCommand(command);
switch (handleExecutionResults(results, bmp, rd, true)) {
case EXECUTION_ERROR:
return fullErrorMessage("Error trying to run patch rollback: " +
results.getError().getMessage(), pids, i - 1, "rolled back");
case TIMEOUT:
return fullErrorMessage("Patch rollback timed out. Captured output: " +
results.getCapturedOutput(), pids, i - 1, "rolled back");
case ERROR:
return fullErrorMessage("Patch rollback failed with error code " + results.getExitCode()
+ ".", pids, i - 1, "rolled back");
}
++i;
}