modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/StandaloneManagedDeploymentComponent.java
| 67 ++--
modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/util/FileContentDelegate.java
| 157 +++++++++-
modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/util/JarContentDelegate.java
| 22 -
3 files changed, 188 insertions(+), 58 deletions(-)
New commits:
commit d4ba67e3e1739a2b368b2cc4c8f7a2677b6e6b9e
Author: Stefan Negrea <snegrea(a)redhat.com>
Date: Wed Dec 14 11:07:02 2011 -0600
[BZ 767393] Updated the plugin code to use SHA256 as the version and persist it inside
the manifest file. Also, add directory based SHA computation for default server
applications.
diff --git
a/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/StandaloneManagedDeploymentComponent.java
b/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/StandaloneManagedDeploymentComponent.java
index ebae861..a8eba4d 100644
---
a/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/StandaloneManagedDeploymentComponent.java
+++
b/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/StandaloneManagedDeploymentComponent.java
@@ -58,11 +58,10 @@ import org.rhq.core.pluginapi.content.ContentFacet;
import org.rhq.core.pluginapi.content.ContentServices;
import org.rhq.core.pluginapi.inventory.DeleteResourceFacet;
import org.rhq.core.pluginapi.measurement.MeasurementFacet;
-import org.rhq.core.util.MessageDigestGenerator;
import org.rhq.core.util.ZipUtil;
import org.rhq.core.util.exception.ThrowableUtil;
-import org.rhq.core.util.file.JarContentFileInfo;
import org.rhq.plugins.jbossas5.util.DeploymentUtils;
+import org.rhq.plugins.jbossas5.util.FileContentDelegate;
/**
* A resource component for managing a standalone/top-level Profile Service managed
deployment.
@@ -144,9 +143,8 @@ public class StandaloneManagedDeploymentComponent extends
AbstractManagedDeploym
+ getResourceDescription() + " does not exist.");
String fileName = this.deploymentFile.getName();
- JarContentFileInfo fileInfo = new JarContentFileInfo(this.deploymentFile);
- String sha256 = getSHA256(fileInfo);
- String version = getVersion(fileInfo, sha256);
+ String sha256 = getSHA256(this.deploymentFile);
+ String version = getVersion(sha256);
// Package name is the deployment's file name (e.g. foo.ear).
PackageDetailsKey key = new PackageDetailsKey(fileName, version, PKG_TYPE_FILE,
ARCHITECTURE);
ResourcePackageDetails packageDetails = new ResourcePackageDetails(key);
@@ -164,46 +162,29 @@ public class StandaloneManagedDeploymentComponent extends
AbstractManagedDeploym
return packages;
}
- // TODO: if needed we can speed this up by looking in the ResourceContainer's
installedPackage
- // list for previously discovered packages. If there use the sha256 from that record.
We'd have to
- // get access to that info by adding access in
org.rhq.core.pluginapi.content.ContentServices
- private String getSHA256(JarContentFileInfo fileInfo) {
-
+ /**
+ * Retrieve SHA256 for a deployed app.
+ *
+ * @param file application file
+ * @return SHA256 of the content
+ */
+ private String getSHA256(File file) {
String sha256 = null;
try {
- sha256 = fileInfo.getAttributeValue(RHQ_SHA256, null);
- if (null == sha256) {
- sha256 = new
MessageDigestGenerator(MessageDigestGenerator.SHA_256).calcDigestString(fileInfo
- .getContentFile());
- }
- } catch (IOException iex) {
- //log exception but move on, discovery happens often. No reason to hold up
anything.
+ FileContentDelegate fileContentDelegate = new FileContentDelegate(file, null,
null);
+ sha256 = fileContentDelegate.getSHA(file);
+ } catch (Exception iex) {
if (log.isDebugEnabled()) {
- log.debug("Problem calculating digest of package [" +
fileInfo.getContentFile().getPath() + "]."
- + iex.getMessage());
+ log.debug("Problem calculating digest of package [" +
file.getPath() + "]." + iex.getMessage());
}
}
return sha256;
}
- private String getVersion(JarContentFileInfo fileInfo, String sha256) {
- // Version string in order of preference
- // manifestVersion + sha256, sha256, manifestVersion, "0"
- String version = "0";
- String manifestVersion = fileInfo.getVersion(null);
-
- if ((null != manifestVersion) && (null != sha256)) {
- // this protects against the occasional differing binaries with poor manifest
maintenance
- version = manifestVersion + " [sha256=" + sha256 + "]";
- } else if (null != sha256) {
- version = "[sha256=" + sha256 + "]";
- } else if (null != manifestVersion) {
- version = manifestVersion;
- }
-
- return version;
+ private String getVersion(String sha256) {
+ return "[sha256=" + sha256 + "]";
}
public RemovePackagesResponse removePackages(Set<ResourcePackageDetails>
packages) {
@@ -238,8 +219,11 @@ public class StandaloneManagedDeploymentComponent extends
AbstractManagedDeploym
log.debug("Writing new EAR/WAR bits to temporary file...");
File tempFile;
+ String sha = null;
try {
tempFile = writeNewAppBitsToTempFile(contentServices, packageDetails);
+ FileContentDelegate fileContentDelegate = new FileContentDelegate(null, null,
null);
+ sha = fileContentDelegate.computeSHAForArchive(tempFile);
} catch (Exception e) {
return failApplicationDeployment("Error writing new application bits to
temporary file - cause: " + e,
packageDetails);
@@ -320,6 +304,19 @@ public class StandaloneManagedDeploymentComponent extends
AbstractManagedDeploym
// Deploy was successful!
deleteBackupOfOriginalFile(backupOfOriginalFile);
+ if (this.deploymentFile.isDirectory()) {
+ FileContentDelegate fileContentDelegate = new
FileContentDelegate(deploymentFile, null, null);
+ try {
+ //This is a simulation of create content from FileContentDelegate split
across
+ //this deployment method because JBoss AS5 is using a different
deployment model.
+ //The SHA256 was pre-computed earlier (at the time the temp content file
was created).
+ //The only thing left at this point is to store it in the manifest file.
+ fileContentDelegate.writeSHAToManifest(deploymentFile, sha);
+ } catch (IOException e) {
+ log.error("Unable to save SHA to manifest file for " +
this.deploymentFile.getPath() + ".", e);
+ }
+ }
+
DeployPackagesResponse response = new
DeployPackagesResponse(ContentResponseResult.SUCCESS);
DeployIndividualPackageResponse packageResponse = new
DeployIndividualPackageResponse(packageDetails.getKey(),
ContentResponseResult.SUCCESS);
diff --git
a/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/util/FileContentDelegate.java
b/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/util/FileContentDelegate.java
index 75f890a..915374a 100644
---
a/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/util/FileContentDelegate.java
+++
b/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/util/FileContentDelegate.java
@@ -26,16 +26,22 @@ import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Set;
+import java.util.Stack;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.rhq.core.domain.content.PackageDetails;
import org.rhq.core.domain.content.PackageDetailsKey;
import org.rhq.core.domain.content.transfer.ResourcePackageDetails;
import org.rhq.core.pluginapi.util.FileUtils;
+import org.rhq.core.util.MessageDigestGenerator;
import org.rhq.core.util.ZipUtil;
import org.rhq.core.util.file.FileUtil;
@@ -46,7 +52,9 @@ import org.rhq.core.util.file.FileUtil;
* @author Jason Dobies
*/
public class FileContentDelegate {
- // Attributes --------------------------------------------
+
+ private static final String RHQ_SHA_256 = "RHQ-Sha256";
+ private static final String MANIFEST_RELATIVE_PATH =
"META-INF/MANIFEST.MF";
private final Log log = LogFactory.getLog(FileContentDelegate.class);
@@ -55,16 +63,12 @@ public class FileContentDelegate {
private final String fileEnding;
private final String packageTypeName;
- // Constructors --------------------------------------------
-
public FileContentDelegate(File directory, String fileEnding, String packageTypeName)
{
this.directory = directory;
this.fileEnding = fileEnding;
this.packageTypeName = packageTypeName;
}
- // Public --------------------------------------------
-
public String getFileEnding() {
return fileEnding;
}
@@ -145,6 +149,44 @@ public class FileContentDelegate {
}
/**
+ * Retrieves the SHA256 for a deployed application.
+ * 1) If the app is exploded then return RHQ-Sha256 manifest attribute.
+ * 1.1) If RHQ-Sha256 is missing then compute it, save it and return the result.
+ * 2) If the app is an archive then compute SHA256 on fly and return it.
+ *
+ * @param deploymentFile deployment file
+ * @return
+ */
+ public String getSHA(File deploymentFile) {
+ String sha = null;
+ try {
+ if (deploymentFile.isDirectory()) {
+ File manifestFile = new File(deploymentFile.getAbsolutePath(),
MANIFEST_RELATIVE_PATH);
+ if (manifestFile.exists()) {
+ InputStream manifestStream = new FileInputStream(manifestFile);
+ Manifest manifest = null;
+ try {
+ manifest = new Manifest(manifestStream);
+ sha = manifest.getMainAttributes().getValue(RHQ_SHA_256);
+ } finally {
+ manifestStream.close();
+ }
+ }
+
+ if (sha == null || sha.trim().isEmpty()) {
+ sha = computeAndSaveSHA(deploymentFile);
+ }
+ } else {
+ sha = new
MessageDigestGenerator(MessageDigestGenerator.SHA_256).calcDigestString(deploymentFile);
+ }
+ } catch (IOException ex) {
+ throw new RuntimeException("Problem calculating digest of package
[" + deploymentFile.getPath() + "].", ex);
+ }
+
+ return sha;
+ }
+
+ /**
* Returns a stream from which the content of the specified package can be read.
*
* @param details package being loaded
@@ -185,4 +227,109 @@ public class FileContentDelegate {
*/
return null;
}
+
+ /**
+ * Computes SHA256 for an archive.
+ *
+ * @param contentFile content archive
+ * @return SHA256 of the archive
+ */
+ public String computeSHAForArchive(File contentFile) {
+ if (!contentFile.isDirectory()) {
+ try {
+ MessageDigestGenerator messageDigest = new
MessageDigestGenerator(MessageDigestGenerator.SHA_256);
+ return messageDigest.calcDigestString(contentFile);
+ } catch (Exception ex) {
+ log.error("Not able to compute SHA256 for " +
contentFile.getPath() + " .");
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Compute SHA256 for the content of an exploded war deployment. This method should
be used to
+ * compute the SHA256 for content deployed outside RHQ or for the initial content
delivered
+ * with the server.
+ *
+ * @param deploymentDirectory app deployment folder
+ * @return
+ */
+ private String computeAndSaveSHA(File deploymentDirectory) {
+ String sha = null;
+ try {
+ if (deploymentDirectory.isDirectory()) {
+ MessageDigestGenerator messageDigest = new
MessageDigestGenerator(MessageDigestGenerator.SHA_256);
+
+ Stack<File> unvisitedFolders = new Stack<File>();
+ unvisitedFolders.add(deploymentDirectory);
+ while (!unvisitedFolders.empty()) {
+ for (File file : unvisitedFolders.pop().listFiles()) {
+ if (file.isDirectory()) {
+ unvisitedFolders.add(file);
+ } else {
+ FileInputStream inputStream = null;
+ try {
+ inputStream = new FileInputStream(file);
+ messageDigest.add(inputStream);
+ } finally {
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ }
+ }
+ }
+ }
+
+ sha = messageDigest.getDigestString();
+ writeSHAToManifest(deploymentDirectory, sha);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Error creating artifact for contentFile:
" + deploymentDirectory, e);
+ }
+
+ return sha;
+ }
+
+ /**
+ * Write the SHA256 to the manifest using the RHQ-Sha256 attribute tag.
+ *
+ * @param deploymentFolder app deployment folder
+ * @param sha SHA256
+ * @throws IOException
+ */
+ public void writeSHAToManifest(File deploymentFolder, String sha) throws IOException
{
+ File manifestFile = new File(deploymentFolder, MANIFEST_RELATIVE_PATH);
+ Manifest manifest;
+ if (manifestFile.exists()) {
+ FileInputStream inputStream = new FileInputStream(manifestFile);
+ try {
+ manifest = new Manifest(inputStream);
+ } finally {
+ inputStream.close();
+ }
+ } else {
+ manifest = new Manifest();
+ manifestFile.getParentFile().mkdirs();
+ manifestFile.createNewFile();
+ }
+
+ Attributes attribs = manifest.getMainAttributes();
+
+ //The main section of the manifest file does not get saved if both of
+ //these two attributes are missing. Please see Attributes implementation.
+ if (!attribs.containsKey(Attributes.Name.MANIFEST_VERSION.toString())
+ &&
!attribs.containsKey(Attributes.Name.SIGNATURE_VERSION.toString())) {
+ attribs.putValue(Attributes.Name.MANIFEST_VERSION.toString(),
"1.0");
+ }
+
+ attribs.putValue(RHQ_SHA_256, sha);
+
+ FileOutputStream outputStream = new FileOutputStream(manifestFile);
+ try {
+ manifest.write(outputStream);
+ } finally {
+ outputStream.close();
+ }
+ }
}
diff --git
a/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/util/JarContentDelegate.java
b/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/util/JarContentDelegate.java
index d68f429..3bb920a 100644
---
a/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/util/JarContentDelegate.java
+++
b/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/util/JarContentDelegate.java
@@ -113,9 +113,9 @@ public class JarContentDelegate extends FileContentDelegate {
} catch (Exception e) {
// leave as null
}
- String version = getVersion(manifestVersion, sha256);
+
ResourcePackageDetails details = new ResourcePackageDetails(new
PackageDetailsKey(file.getName(),
- version, getPackageTypeName(), "noarch"));
+ getVersion(sha256), getPackageTypeName(), "noarch"));
packages.add(details);
details.setFileCreatedDate(file.lastModified()); // Why don't we have
a last modified time?
@@ -140,21 +140,7 @@ public class JarContentDelegate extends FileContentDelegate {
return packages;
}
- private String getVersion(String manifestVersion, String sha256) {
- // Version string in order of preference
- // manifestVersion + sha256, sha256, manifestVersion, "0"
- String version = "0";
-
- if ((null != manifestVersion) && (null != sha256)) {
- // this protects against the occasional differing binaries with poor manifest
maintenance
- version = manifestVersion + " [sha256=" + sha256 + "]";
- } else if (null != sha256) {
- version = "[sha256=" + sha256 + "]";
- } else if (null != manifestVersion) {
- version = manifestVersion;
- }
-
- return version;
+ private String getVersion(String sha256) {
+ return "[sha256=" + sha256 + "]";
}
-
}