// You can only update the one application file referenced by this resource, so punch out if multiple are
// specified.
if (packages.size() != 1) {
LOG.warn("Request to update " + resourceTypeName + " file contained multiple packages: " + packages);
DeployPackagesResponse response = new DeployPackagesResponse(ContentResponseResult.FAILURE);
response.setOverallRequestErrorMessage("Only one " + resourceTypeName + " can be updated at a time.");
return response;
}
ResourcePackageDetails packageDetails = packages.iterator().next();
if (LOG.isDebugEnabled()) {
LOG.debug("Updating EAR/WAR file '" + deploymentFile + "' using [" + packageDetails + "]...");
}
// Find location of existing application.
if (!deploymentFile.exists()) {
return failApplicationDeployment("Could not find application to update at location: " + deploymentFile,
packageDetails);
}
LOG.debug("Writing new EAR/WAR bits to temporary file...");
File tempFile;
try {
tempFile = writeNewAppBitsToTempFile(contentServices, packageDetails);
} catch (Exception e) {
return failApplicationDeployment("Error writing new application bits to temporary file - cause: " + e,
packageDetails);
}
if (LOG.isDebugEnabled()) {
LOG.debug("Wrote new EAR/WAR bits to temporary file '" + tempFile + "'.");
}
boolean deployExploded = deploymentFile.isDirectory();
// Backup the original app file/dir.
File tempDir = getResourceContext().getTemporaryDirectory();
File backupDir = new File(tempDir, "deployBackup" + UUID.randomUUID().getLeastSignificantBits());
File backupOfOriginalFile = new File(backupDir, deploymentFile.getName());
if (LOG.isDebugEnabled()) {
LOG.debug("Backing up existing EAR/WAR '" + deploymentFile + "' to '" + backupOfOriginalFile + "'...");
}
try {
if (backupOfOriginalFile.exists()) {
FileUtils.forceDelete(backupOfOriginalFile);
}
if (deploymentFile.isDirectory()) {
FileUtils.copyDirectory(deploymentFile, backupOfOriginalFile, true);
} else {
FileUtils.copyFile(deploymentFile, backupOfOriginalFile, true);
}
} catch (Exception e) {
throw new RuntimeException("Failed to backup existing " + resourceTypeName + "'" + deploymentFile
+ "' to '" + backupOfOriginalFile + "'.");
}
ProfileServiceConnection connection = getConnection();
if (connection == null) {
DeployPackagesResponse response = new DeployPackagesResponse(ContentResponseResult.FAILURE);
response.setOverallRequestErrorMessage("No profile service connection available");
return response;
}
DeploymentManager deploymentManager = connection.getDeploymentManager();
// as crazy as it might sound, there is apparently no way for you to ask the profile service
// if a deployment was deployed to the farm profile. Thus, we must resort to a poor man's solution:
// if the deployment name has the "farm/" directory in it, assume it needs to be deployed to the farm
boolean deployFarmed = getDeploymentKey().contains("/farm/");
if (deployFarmed) {
Collection<ProfileKey> profileKeys = deploymentManager.getProfiles();
boolean farmSupported = false;
for (ProfileKey profileKey : profileKeys) {
if (profileKey.getName().equals(FARM_PROFILE_KEY.getName())) {
farmSupported = true;
break;
}
}
if (!farmSupported) {
throw new IllegalStateException("This application server instance is not a node in a cluster, "
+ "so it does not support farmed deployments. Supported deployment profiles are " + profileKeys
+ ".");
}
if (deployExploded) {
throw new IllegalArgumentException(
"Deploying farmed applications in exploded form is not supported by the Profile Service.");
}
try {
deploymentManager.loadProfile(FARM_PROFILE_KEY);
} catch (Exception e) {
LOG.info("Failed to switch to farm profile - could not update " + resourceTypeName + " file '"
+ deploymentFile + "' using [" + packageDetails + "].");
String errorMessage = ThrowableUtil.getAllMessages(e);
return failApplicationDeployment(errorMessage, packageDetails);
}
}
String deploymentName = getDeploymentName();
if (deploymentName == null) {
DeployPackagesResponse response = new DeployPackagesResponse(ContentResponseResult.FAILURE);
response.setOverallRequestErrorMessage("Did not find deployment with key [" + getDeploymentKey() + "]");
return response;
}
// Now stop the original app.
try {
DeploymentProgress progress = deploymentManager.stop(deploymentName);
DeploymentUtils.run(progress);
} catch (Exception e) {
throw new RuntimeException("Failed to stop deployment [" + deploymentName + "].", e);
}
// And then remove it (this will delete the physical file/dir from the deploy dir).
try {
DeploymentProgress progress = deploymentManager.remove(deploymentName);
DeploymentUtils.run(progress);
} catch (Exception e) {
throw new RuntimeException("Failed to remove deployment [" + deploymentName + "].", e);
}
// Deploy away!
try {
if (LOG.isDebugEnabled()) {
LOG.debug("Deploying '" + tempFile + "'...");
}
DeploymentUtils.deployArchive(deploymentManager, tempFile, deployExploded);
} catch (Exception e) {
// Deploy failed - rollback to the original app file...
LOG.debug("Redeploy failed - rolling back to original archive...", e);
String errorMessage = ThrowableUtil.getAllMessages(e);
try {
// Try to delete the new app file, which failed to deploy, if it still exists.
if (deploymentFile.exists()) {
try {
FileUtils.forceDelete(deploymentFile);
} catch (IOException e1) {
if (LOG.isDebugEnabled()) {
LOG.debug("Failed to delete application file '" + deploymentFile
+ "' that failed to deploy.", e1);
}
}
}
// Now redeploy the original file - this generally should succeed.
DeploymentUtils.deployArchive(deploymentManager, backupOfOriginalFile, deployExploded);
errorMessage += " ***** ROLLED BACK TO ORIGINAL APPLICATION FILE. *****";
// If the redeployment of the original backup succeeded then cleanup the backup from disk
deleteTemporaryFile(backupDir);
// If the redeployment fails the original backup is preserved on disk until agent restart
} catch (Exception e1) {
LOG.debug("Rollback failed!", e1);
errorMessage += " ***** FAILED TO ROLLBACK TO ORIGINAL APPLICATION FILE. *****: "
+ ThrowableUtil.getAllMessages(e1);
}
//since the deployment failed remove the temp application downloaded for deployment
deleteTemporaryFile(tempFile);
LOG.info("Failed to update " + resourceTypeName + " file '" + deploymentFile + "' using [" + packageDetails
+ "].");
return failApplicationDeployment(errorMessage, packageDetails);
} finally {
// Make sure to switch back to the 'applications' profile if we switched to the 'farm' profile above.
if (deployFarmed) {
try {
deploymentManager.loadProfile(APPLICATIONS_PROFILE_KEY);
} catch (Exception e) {
LOG.debug("Failed to switch back to applications profile from farm profile", e);
}
}
}
// Store SHA256 in the agent file if deployment was exploded
if (deploymentFile.isDirectory()) {
FileContentDelegate fileContentDelegate = new FileContentDelegate();
fileContentDelegate.saveDeploymentSHA(tempFile, deploymentFile, getResourceContext()
.getResourceDataDirectory());
}
// Remove temporary files created by this deployment.
deleteTemporaryFile(backupDir);
deleteTemporaryFile(tempFile.getParentFile());
DeployPackagesResponse response = new DeployPackagesResponse(ContentResponseResult.SUCCESS);
DeployIndividualPackageResponse packageResponse = new DeployIndividualPackageResponse(packageDetails.getKey(),
ContentResponseResult.SUCCESS);
response.addPackageResponse(packageResponse);
if (LOG.isDebugEnabled()) {
LOG.debug("Updated " + resourceTypeName + " file '" + deploymentFile
+ "' successfully - returning response [" + response + "]...");
}