modules/core/domain/src/main/java/org/rhq/core/domain/resource/ResourceAncestryFormat.java
| 50 +++
modules/enterprise/server/ear/src/main/resources/alert-email-template.txt
| 47 +--
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/alert/AlertManagerBean.java
| 43 --
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java
| 145 ++++++++++
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerLocal.java
| 4
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerRemote.java
| 20 +
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/webservices/WebservicesManagerBean.java
| 23 -
7 files changed, 262 insertions(+), 70 deletions(-)
New commits:
commit 23820b201c04edcec4812d31ad4687abc30bf0ec
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Fri Mar 25 21:48:10 2011 -0400
Resource Ancestry (Disambiguation) Work
- Bug 602178 - Resource hierarchy in alert emails not disambiguated
- Add SLSB support for getting formatted resource ancestry and use this
for disambiguated resource info for alert email text. This also provides
missing support for CLI users that may need formatted ancestry strings.
- Tweaked the alert-email-template.txt to be slightly better formatted (is
this ok to do? Is this file being parsed by users?)
diff --git
a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/ResourceAncestryFormat.java
b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/ResourceAncestryFormat.java
new file mode 100644
index 0000000..5d87a7f
--- /dev/null
+++
b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/ResourceAncestryFormat.java
@@ -0,0 +1,50 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2008 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation, and/or the GNU Lesser
+ * General Public License, version 2.1, also as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License and the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.rhq.core.domain.resource;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlEnum;
+
+import org.rhq.enterprise.server.resource.ResourceManagerRemote;
+
+/**
+ * Used to request the desired diplay format for resource ancestry.
+ * @see {@link
ResourceManagerRemote#getResourcesAncestry(org.rhq.core.domain.auth.Subject, Integer[],
ResourceAncestryFormat)}
+ *
+ * @author Jay Shaughnessy
+ */
+@XmlEnum
+(a)XmlAccessorType(XmlAccessType.FIELD)
+public enum ResourceAncestryFormat {
+ /**
+ * <ul>
+ * <li>RAW: The raw, encoded value. This is already provided by the
Resource.ancestry field.
+ *
+ * <li>SIMPLE: Short, name only format: (eg. parentName < grandParentName
< etc...)
+ *
+ * <li>VERBOSE: Verbose, MultiLine format incorporating name, type and
indentation.
+ * </ul>
+ */
+ RAW, SIMPLE, VERBOSE
+}
\ No newline at end of file
diff --git a/modules/enterprise/server/ear/src/main/resources/alert-email-template.txt
b/modules/enterprise/server/ear/src/main/resources/alert-email-template.txt
index 40fb2cf..a791933 100644
--- a/modules/enterprise/server/ear/src/main/resources/alert-email-template.txt
+++ b/modules/enterprise/server/ear/src/main/resources/alert-email-template.txt
@@ -1,24 +1,23 @@
-Subject: [ALERT] priority of [@@@PRIORITY@@@] for alert [@@@ALERT_NAME@@@] on resource
[@@@RESOURCE_NAME@@@]
-
-The resource @@@RESOURCE_NAME@@@ has generated the following alert:
-
-------------------------------------------
-
-- Resource Name: @@@RESOURCE_NAME@@@
-- Alert Name: @@@ALERT_NAME@@@
-- Alert Severity: @@@PRIORITY@@@
-- Alert Date/Time: @@@TIMESTAMP@@@
-- Conditions: @@@CONDITIONS@@@
-
-------------------------------------------
-
-Resource Hierarchy was:
-
-@@@FULL_RESOURCE_HIERARCHY@@@
-
-
-------------------------------------------
-
-For additional details about this alert, go to @@@ALERT_URL@@@
-
-This message was delivered to you by RHQ.
+Subject: [ALERT] priority of [@@@PRIORITY@@@] for alert [@@@ALERT_NAME@@@] on resource
[@@@RESOURCE_NAME@@@]
+
+The resource @@@RESOURCE_NAME@@@ has generated the following alert:
+
+------------------------------------------
+
+Resource Name : @@@RESOURCE_NAME@@@
+Alert Name : @@@ALERT_NAME@@@
+Alert Severity : @@@PRIORITY@@@
+Alert Date/Time : @@@TIMESTAMP@@@
+Conditions: @@@CONDITIONS@@@
+
+------------------------------------------
+
+Resource Ancestry:
+
+@@@FULL_RESOURCE_HIERARCHY@@@
+
+------------------------------------------
+
+For additional details about this alert, go to @@@ALERT_URL@@@
+
+This message was delivered to you by RHQ.
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/alert/AlertManagerBean.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/alert/AlertManagerBean.java
index d25d1c4..02ae7b1 100644
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/alert/AlertManagerBean.java
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/alert/AlertManagerBean.java
@@ -64,6 +64,7 @@ import org.rhq.core.domain.measurement.MeasurementSchedule;
import org.rhq.core.domain.measurement.MeasurementUnits;
import org.rhq.core.domain.operation.OperationDefinition;
import org.rhq.core.domain.resource.Resource;
+import org.rhq.core.domain.resource.ResourceAncestryFormat;
import org.rhq.core.domain.util.PageList;
import org.rhq.core.server.MeasurementConverter;
import org.rhq.core.server.PersistenceUtility;
@@ -727,9 +728,11 @@ public class AlertManagerBean implements AlertManagerLocal,
AlertManagerRemote {
}
AlertDefinition alertDefinition = alert.getAlertDefinition();
- Map<String, String> alertMessage = emailManager.getAlertEmailMessage(
- prettyPrintResourceHierarchy(alertDefinition.getResource()), //
- alertDefinition.getResource().getName(), //
+ Resource resource = alertDefinition.getResource();
+ Map<Integer, String> ancestry =
resourceManager.getResourcesAncestry(subjectManager.getOverlord(),
+ new Integer[] { resource.getId() }, ResourceAncestryFormat.VERBOSE);
+ Map<String, String> alertMessage =
emailManager.getAlertEmailMessage(ancestry.get(resource.getId()), //
+ resource.getName(), //
alertDefinition.getName(), //
alertDefinition.getPriority().toString(), //
new Date(alert.getCtime()).toString(), //
@@ -755,40 +758,6 @@ public class AlertManagerBean implements AlertManagerLocal,
AlertManagerRemote {
private static String NEW_LINE = System.getProperty("line.separator");
- private String prettyPrintResourceHierarchy(Resource resource) {
- StringBuilder builder = new StringBuilder();
-
- List<Resource> lineage =
resourceManager.getResourceLineage(resource.getId());
-
- int depth = 0;
- for (Resource res : lineage) {
- if (depth == 0) {
- builder.append(" - ");
- } else {
- builder.append(NEW_LINE);
-
- for (int i = 0; i < depth; i++) {
- builder.append(" ");
- }
-
- builder.append("|");
- builder.append(NEW_LINE);
-
- for (int i = 0; i < depth; i++) {
- builder.append(" ");
- }
-
- builder.append("+- ");
- }
-
- builder.append(res.getName());
-
- depth++;
- }
-
- return builder.toString();
- }
-
/**
* Create a human readable description of the conditions that led to this alert.
* @param alert Alert to create human readable condition description
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java
index 384104a..30c2334 100644
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java
@@ -20,7 +20,9 @@ package org.rhq.enterprise.server.resource;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
@@ -66,6 +68,7 @@ import org.rhq.core.domain.content.InstalledPackageHistory;
import org.rhq.core.domain.content.PackageInstallationStep;
import org.rhq.core.domain.content.ResourceRepo;
import org.rhq.core.domain.criteria.ResourceCriteria;
+import org.rhq.core.domain.criteria.ResourceTypeCriteria;
import org.rhq.core.domain.event.Event;
import org.rhq.core.domain.event.EventSource;
import org.rhq.core.domain.measurement.Availability;
@@ -84,6 +87,7 @@ import org.rhq.core.domain.resource.CreateResourceHistory;
import org.rhq.core.domain.resource.DeleteResourceHistory;
import org.rhq.core.domain.resource.InventoryStatus;
import org.rhq.core.domain.resource.Resource;
+import org.rhq.core.domain.resource.ResourceAncestryFormat;
import org.rhq.core.domain.resource.ResourceCategory;
import org.rhq.core.domain.resource.ResourceError;
import org.rhq.core.domain.resource.ResourceErrorType;
@@ -827,6 +831,147 @@ public class ResourceManagerBean implements ResourceManagerLocal,
ResourceManage
return resourceLineage;
}
+ public Map<Integer, String> getResourcesAncestry(Subject subject, Integer[]
resourceIds,
+ ResourceAncestryFormat format) {
+ Map<Integer, String> result = new HashMap<Integer,
String>(resourceIds.length);
+
+ if (resourceIds.length == 0) {
+ return result;
+ }
+
+ ResourceCriteria resourceCriteria = new ResourceCriteria();
+ resourceCriteria.addFilterIds(resourceIds);
+ resourceCriteria.fetchResourceType(true);
+ List<Resource> resources = findResourcesByCriteria(subject,
resourceCriteria);
+
+ if (ResourceAncestryFormat.RAW == format) {
+ for (Resource resource : resources) {
+ result.put(resource.getId(), resource.getAncestry());
+ }
+ return result;
+ }
+
+ HashSet<Integer> typesSet = new HashSet<Integer>();
+ HashSet<String> ancestries = new HashSet<String>();
+ for (Resource resource : resources) {
+ ResourceType type = resource.getResourceType();
+ if (type != null) {
+ typesSet.add(type.getId());
+ }
+ ancestries.add(resource.getAncestry());
+ }
+
+ // In addition to the types of the result resources, get the types of their
ancestry
+ typesSet.addAll(getAncestryTypeIds(ancestries));
+
+ ResourceTypeCriteria resourceTypeCriteria = new ResourceTypeCriteria();
+ resourceTypeCriteria.addFilterIds(typesSet.toArray(new
Integer[typesSet.size()]));
+ List<ResourceType> types = typeManager.findResourceTypesByCriteria(subject,
resourceTypeCriteria);
+
+ for (Resource resource : resources) {
+ String decodedAncestry = getDecodedAncestry(resource, types, format);
+ result.put(resource.getId(), decodedAncestry);
+ }
+ return result;
+ }
+
+ /**
+ * Get the complete set of resource type Ids in the ancestries provided. This is
useful for
+ * being able to load all the types in advance of generating decoded values.
+ *
+ * @return
+ */
+ private HashSet<Integer> getAncestryTypeIds(Collection<String>
ancestries) {
+ HashSet<Integer> result = new HashSet<Integer>();
+
+ for (String ancestry : ancestries) {
+ if (null == ancestry) {
+ continue;
+ }
+ String[] ancestryEntries = ancestry.split(Resource.ANCESTRY_DELIM);
+ for (int i = 0; i < ancestryEntries.length; ++i) {
+ String[] entryTokens =
ancestryEntries[i].split(Resource.ANCESTRY_ENTRY_DELIM);
+ int rtId = Integer.valueOf(entryTokens[0]);
+ result.add(rtId);
+ }
+ }
+
+ return result;
+ }
+
+ private String getDecodedAncestry(Resource resource, List<ResourceType>
typeList, ResourceAncestryFormat format) {
+ String ancestry = resource.getAncestry();
+ StringBuilder sb = new StringBuilder();
+
+ if (ResourceAncestryFormat.VERBOSE != format) {
+ if (null == ancestry) {
+ sb.append("");
+ }
+
+ String[] ancestryEntries = ancestry.split(Resource.ANCESTRY_DELIM);
+ for (int i = 0; i < ancestryEntries.length; ++i) {
+ String[] entryTokens =
ancestryEntries[i].split(Resource.ANCESTRY_ENTRY_DELIM);
+ String ancestorName = entryTokens[2];
+
+ sb.append((i > 0) ? " < " : "");
+ sb.append(ancestorName);
+ }
+ } else {
+ Map<Integer, ResourceType> types = new HashMap<Integer,
ResourceType>(typeList.size());
+ for (ResourceType type : typeList) {
+ types.put(type.getId(), type);
+ }
+
+ ResourceType type = types.get(resource.getResourceType().getId());
+ String resourceLongName = getResourceLongName(resource.getName(), type);
+
+ // decode ancestry
+ if (null != ancestry) {
+ String[] ancestryEntries = ancestry.split(Resource.ANCESTRY_DELIM);
+ for (int i = ancestryEntries.length - 1, j = 0; i >= 0; --i, ++j) {
+ String[] entryTokens =
ancestryEntries[i].split(Resource.ANCESTRY_ENTRY_DELIM);
+ int ancestorTypeId = Integer.valueOf(entryTokens[0]);
+ String ancestorName = entryTokens[2];
+
+ // indent with spaces
+ if (j > 0) {
+ sb.append("\n");
+ for (int k = 0; k < j; ++k) {
+ sb.append(" ");
+ }
+ }
+ type = types.get(ancestorTypeId);
+ sb.append(getResourceLongName(ancestorName, type));
+ }
+
+ // add target resource, indent with spaces
+ sb.append("\n");
+ for (int k = 0; k <= ancestryEntries.length; ++k) {
+ sb.append(" ");
+ }
+ sb.append(resourceLongName);
+
+ } else {
+ // just show the resource name/type info
+ sb.append(resourceLongName);
+ }
+ }
+
+ return sb.toString();
+ }
+
+ private String getResourceLongName(String resourceName, ResourceType type) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(resourceName);
+ sb.append(" [");
+ sb.append(type.getPlugin());
+ sb.append(", ");
+ sb.append(type.getName());
+ sb.append("]");
+
+ return sb.toString();
+ }
+
@NotNull
public Resource getRootResourceForResource(int resourceId) {
Query q =
entityManager.createNamedQuery(Resource.QUERY_FIND_ROOT_PLATFORM_OF_RESOURCE);
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerLocal.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerLocal.java
index 02b0266..841428b 100644
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerLocal.java
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerLocal.java
@@ -32,6 +32,7 @@ import org.rhq.core.domain.measurement.ResourceAvailability;
import org.rhq.core.domain.resource.Agent;
import org.rhq.core.domain.resource.InventoryStatus;
import org.rhq.core.domain.resource.Resource;
+import org.rhq.core.domain.resource.ResourceAncestryFormat;
import org.rhq.core.domain.resource.ResourceCategory;
import org.rhq.core.domain.resource.ResourceError;
import org.rhq.core.domain.resource.ResourceErrorType;
@@ -506,4 +507,7 @@ public interface ResourceManagerLocal {
List<Integer> findIdsByTypeIds(List<Integer> resourceTypeIds);
Integer getResourceCount(List<Integer> resourceTypeIds);
+
+ Map<Integer, String> getResourcesAncestry(Subject subject, Integer[]
resourceIds, ResourceAncestryFormat format);
+
}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerRemote.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerRemote.java
index 46b8e08..9d1c269 100644
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerRemote.java
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerRemote.java
@@ -19,6 +19,7 @@
package org.rhq.enterprise.server.resource;
import java.util.List;
+import java.util.Map;
import javax.ejb.Remote;
import javax.jws.WebMethod;
@@ -31,6 +32,7 @@ import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.criteria.ResourceCriteria;
import org.rhq.core.domain.measurement.ResourceAvailability;
import org.rhq.core.domain.resource.Resource;
+import org.rhq.core.domain.resource.ResourceAncestryFormat;
import org.rhq.core.domain.util.PageControl;
import org.rhq.core.domain.util.PageList;
import org.rhq.enterprise.server.jaxb.adapter.ResourceListAdapter;
@@ -138,4 +140,22 @@ public interface ResourceManagerRemote {
Resource getParentResource( //
@WebParam(name = "subject") Subject subject, //
@WebParam(name = "resourceId") int resourceId);
+
+ /**
+ * Resource.ancestry is an encoded value that holds the resource's parental
ancestry. It is not suitable for display.
+ * This method can be used to get decoded and formatted ancestry values for a set of
resources. A typical usage
+ * would a criteria resource fetch, and then a subsequent call to this method for
ancestry display, potentially
+ * for resource disambiguation purposes.
+ *
+ * @param subject
+ * @param resourceIds
+ * @param format
+ * @return A Map of ResourceIds to FormattedAncestryStrings, one entry for each
unique, valid, resourceId passed in.
+ */
+ @WebMethod
+ Map<Integer, String> getResourcesAncestry( //
+ @WebParam(name = "subject") Subject subject, //
+ @WebParam(name = "resourceIds") Integer[] resourceIds, //
+ @WebParam(name = "format") ResourceAncestryFormat format);
+
}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/webservices/WebservicesManagerBean.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/webservices/WebservicesManagerBean.java
index 3a4910b..e06d5ae 100644
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/webservices/WebservicesManagerBean.java
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/webservices/WebservicesManagerBean.java
@@ -25,7 +25,6 @@ package org.rhq.enterprise.server.webservices;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
-import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@@ -115,6 +114,7 @@ import org.rhq.core.domain.operation.bean.ResourceOperationSchedule;
import org.rhq.core.domain.resource.CreateResourceHistory;
import org.rhq.core.domain.resource.DeleteResourceHistory;
import org.rhq.core.domain.resource.Resource;
+import org.rhq.core.domain.resource.ResourceAncestryFormat;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.domain.resource.composite.ProblemResourceComposite;
import org.rhq.core.domain.resource.group.ResourceGroup;
@@ -517,12 +517,12 @@ public class WebservicesManagerBean implements WebservicesRemote {
public PackageType findPackageType(Subject subject, Integer resourceTypeId, String
packageTypeName) {
return contentManager.findPackageType(subject, resourceTypeId, packageTypeName);
}
-
+
public PackageTypeAndVersionFormatComposite findPackageTypeWithVersionFormat(Subject
subject,
Integer resourceTypeId, String packageTypeName) {
return contentManager.findPackageTypeWithVersionFormat(subject, resourceTypeId,
packageTypeName);
}
-
+
public InstalledPackage getBackingPackageForResource(Subject subject, int resourceId)
{
return contentManager.getBackingPackageForResource(subject, resourceId);
}
@@ -533,15 +533,15 @@ public class WebservicesManagerBean implements WebservicesRemote {
public PageList<Package> findPackagesByCriteria(Subject subject,
PackageCriteria criteria) {
checkParametersPassedIn(subject, criteria);
- return contentManager.findPackagesByCriteria(subject, criteria);
+ return contentManager.findPackagesByCriteria(subject, criteria);
}
-
+
public PageList<PackageAndLatestVersionComposite>
findPackagesWithLatestVersion(Subject subject,
PackageCriteria criteria) {
checkParametersPassedIn(subject, criteria);
- return contentManager.findPackagesWithLatestVersion(subject, criteria);
+ return contentManager.findPackagesWithLatestVersion(subject, criteria);
}
-
+
//CONTENTMANAGER: END ----------------------------------
// //DATAACCESSMANAGER: BEGIN ----------------------------------
@@ -807,11 +807,11 @@ public class WebservicesManagerBean implements WebservicesRemote {
public PackageVersion getLatestPackageVersion(Subject subject, int packageId, int
repoId) {
return repoManager.getLatestPackageVersion(subject, packageId, repoId);
}
-
+
public boolean deletePackageVersionsFromRepo(Subject subject, int repoId, int[]
packageVersionIds) {
return repoManager.deletePackageVersionsFromRepo(subject, repoId,
packageVersionIds);
}
-
+
public PageList<Resource> findSubscribedResources(Subject subject, int repoId,
PageControl pc) {
return repoManager.findSubscribedResources(subject, repoId, pc);
}
@@ -911,6 +911,11 @@ public class WebservicesManagerBean implements WebservicesRemote {
return resourceManager.getResource(subject, resourceId);
}
+ public Map<Integer, String> getResourcesAncestry(Subject subject, Integer[]
resourceIds,
+ ResourceAncestryFormat format) {
+ return resourceManager.getResourcesAncestry(subject, resourceIds, format);
+ }
+
public List<Integer> uninventoryResources(Subject subject, int[] resourceIds)
{
return resourceManager.uninventoryResources(subject, resourceIds);
}