modules/core/domain/src/main/java/org/rhq/core/domain/resource/ResourceType.java | 165 ++++----
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceTypeManagerBean.java | 10
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/ResourceMetadataManagerBean.java | 192 +++++-----
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/ResourceMetadataManagerLocal.java | 57 +-
4 files changed, 225 insertions(+), 199 deletions(-)
New commits:
commit 55ee9efc60ff941d8e838430e8ee9dfe1387174c
Merge: f31dda5... 9b1dd9c...
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Wed Jul 21 17:12:08 2010 -0400
Merge branch 'master' into master-jay
commit f31dda5fb516089f0cb3847699ed8bbc64f6dabf
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Wed Jul 21 17:07:14 2010 -0400
[bz 616978] remove umbrella transaction from removal of obsolete types,
allowing more flexible type removal for large inventories.
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/ResourceType.java b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/ResourceType.java
index dbf95c7..8218909 100644
--- a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/ResourceType.java
+++ b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/ResourceType.java
@@ -52,7 +52,6 @@ import javax.persistence.OneToOne;
import javax.persistence.OrderBy;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
-import javax.persistence.QueryHint;
import javax.persistence.SequenceGenerator;
import javax.persistence.SqlResultSetMapping;
import javax.persistence.Table;
@@ -90,11 +89,8 @@ import org.rhq.core.domain.util.Summary;
query = "SELECT rt FROM ResourceType AS rt WHERE :parent MEMBER OF rt.parentResourceTypes AND rt.name = :name"),
/* authz'ed queries for ResourceTypeManagerBean */
- @NamedQuery(name = ResourceType.QUERY_FIND_CHILDREN, query = "SELECT res.resourceType "
- + "FROM Resource res, IN (res.implicitGroups) g, IN (g.roles) r, IN (r.subjects) s " + "WHERE s = :subject "
- + "AND res.parentResource = :parent"),
- @NamedQuery(name = ResourceType.QUERY_FIND_CHILDREN_admin, query = "SELECT res.resourceType "
- + "FROM Resource res " + "WHERE res.parentResource = :parent"),
+ @NamedQuery(name = ResourceType.QUERY_FIND_CHILDREN, query = "SELECT rt.childResourceTypes "
+ + "FROM ResourceType rt WHERE rt.id = :resourceTypeId "),
@NamedQuery(name = ResourceType.FIND_CHILDREN_BY_PARENT, query = "SELECT DISTINCT rt FROM ResourceType AS rt "
+ "JOIN FETCH rt.parentResourceTypes AS pa " + // also fetch parents, as we need them later
"WHERE pa IN (:resourceType)"),
@@ -251,7 +247,6 @@ public class ResourceType implements Serializable, Comparable<ResourceType> {
public static final String QUERY_FIND_BY_ID_WITH_ALL_OPERATIONS = "ResourceType.findByIdWithAllOperations";
public static final String QUERY_FIND_BY_CATEGORY = "ResourceType.findByCategory";
public static final String QUERY_FIND_CHILDREN = "ResourceType.findChildren";
- public static final String QUERY_FIND_CHILDREN_admin = "ResourceType.findChildren_admin";
/** find child resource types for resource :parentResource and category :category */
public static final String QUERY_FIND_CHILDREN_BY_CATEGORY = "ResourceType.findChildrenByCategory";
public static final String QUERY_FIND_CHILDREN_BY_CATEGORY_admin = "ResourceType.findChildrenByCategory_admin";
@@ -322,8 +317,7 @@ public class ResourceType implements Serializable, Comparable<ResourceType> {
@ManyToMany(cascade = CascadeType.PERSIST)
// persist so self-injecting plugins work
- @JoinTable(name = "RHQ_RESOURCE_TYPE_PARENTS", joinColumns = { @JoinColumn(name = "RESOURCE_TYPE_ID") },
- inverseJoinColumns = { @JoinColumn(name = "PARENT_RESOURCE_TYPE_ID") })
+ @JoinTable(name = "RHQ_RESOURCE_TYPE_PARENTS", joinColumns = { @JoinColumn(name = "RESOURCE_TYPE_ID") }, inverseJoinColumns = { @JoinColumn(name = "PARENT_RESOURCE_TYPE_ID") })
@OrderBy
//@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
private Set<ResourceType> parentResourceTypes;
@@ -818,87 +812,86 @@ public class ResourceType implements Serializable, Comparable<ResourceType> {
+ this.plugin + /*", parents=" + parents +*/"]";
}
+ /*
+ TODO: GWT
+ public void writeExternal(ObjectOutput out) throws IOException {
+ ExternalizableStrategy.Subsystem strategy = ExternalizableStrategy.getStrategy();
+ out.writeChar(strategy.id());
-/*
-TODO: GWT
- public void writeExternal(ObjectOutput out) throws IOException {
- ExternalizableStrategy.Subsystem strategy = ExternalizableStrategy.getStrategy();
- out.writeChar(strategy.id());
-
- if (ExternalizableStrategy.Subsystem.REMOTEAPI == strategy) {
- writeExternalRemote(out);
- } else if (ExternalizableStrategy.Subsystem.REFLECTIVE_SERIALIZATION == strategy) {
- EntitySerializer.writeExternalRemote(this, out);
- } else {
- writeExternalAgent(out);
+ if (ExternalizableStrategy.Subsystem.REMOTEAPI == strategy) {
+ writeExternalRemote(out);
+ } else if (ExternalizableStrategy.Subsystem.REFLECTIVE_SERIALIZATION == strategy) {
+ EntitySerializer.writeExternalRemote(this, out);
+ } else {
+ writeExternalAgent(out);
+ }
}
- }
- public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
- char c = in.readChar();
- if (ExternalizableStrategy.Subsystem.REMOTEAPI.id() == c) {
- readExternalRemote(in);
- } else if (ExternalizableStrategy.Subsystem.REFLECTIVE_SERIALIZATION.id() == c) {
- EntitySerializer.readExternalRemote(this, in);
- } else {
- readExternalAgent(in);
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+ char c = in.readChar();
+ if (ExternalizableStrategy.Subsystem.REMOTEAPI.id() == c) {
+ readExternalRemote(in);
+ } else if (ExternalizableStrategy.Subsystem.REFLECTIVE_SERIALIZATION.id() == c) {
+ EntitySerializer.readExternalRemote(this, in);
+ } else {
+ readExternalAgent(in);
+ }
+ }
+
+ public void writeExternalAgent(ObjectOutput out) throws IOException {
+ out.writeUTF(this.name);
+ out.writeUTF(this.plugin);
+ }
+
+ public void readExternalAgent(ObjectInput in) throws IOException, ClassNotFoundException {
+ this.name = in.readUTF();
+ this.plugin = in.readUTF();
}
- }
- public void writeExternalAgent(ObjectOutput out) throws IOException {
- out.writeUTF(this.name);
- out.writeUTF(this.plugin);
- }
-
- public void readExternalAgent(ObjectInput in) throws IOException, ClassNotFoundException {
- this.name = in.readUTF();
- this.plugin = in.readUTF();
- }
-
- public void writeExternalRemote(ObjectOutput out) throws IOException {
- out.writeInt(this.id);
- out.writeUTF(this.name);
- out.writeUTF((null == this.description) ? "" : this.description);
- out.writeObject(this.category);
- out.writeObject(this.creationDataType);
- out.writeObject(this.createDeletePolicy);
- out.writeBoolean(this.supportsManualAdd);
- out.writeBoolean(this.singleton);
- out.writeUTF(this.plugin);
- out.writeLong(this.ctime);
- out.writeLong(this.mtime);
- out.writeObject(this.subCategory);
- out.writeObject(this.bundleType);
- out.writeObject((null == childResourceTypes) ? null : new LinkedHashSet<ResourceType>(childResourceTypes));
- out.writeObject((null == parentResourceTypes) ? null : new LinkedHashSet<ResourceType>(parentResourceTypes));
- out.writeObject(pluginConfigurationDefinition);
- out.writeObject(resourceConfigurationDefinition);
- out.writeObject((null == metricDefinitions) ? null
- : new LinkedHashSet<MeasurementDefinition>(metricDefinitions));
- out.writeObject((null == eventDefinitions) ? null : new LinkedHashSet<EventDefinition>(eventDefinitions));
- out.writeObject((null == operationDefinitions) ? null : new LinkedHashSet<OperationDefinition>(
- operationDefinitions));
- out.writeObject((null == processScans) ? null : new LinkedHashSet<ProcessScan>(processScans));
- out.writeObject((null == packageTypes) ? null : new LinkedHashSet<PackageType>(packageTypes));
- out.writeObject((null == subCategories) ? null : new LinkedHashSet<ResourceSubCategory>(subCategories));
- out.writeObject((null == resources) ? null : new LinkedHashSet<Resource>(resources));
- out.writeObject((null == productVersions) ? null : new LinkedHashSet<ProductVersion>(productVersions));
- // not supplied by remote: helpText
- }
-
- public void readExternalRemote(ObjectInput in) throws IOException, ClassNotFoundException {
- this.id = in.readInt();
- this.name = in.readUTF();
- this.description = in.readUTF();
- this.category = (ResourceCategory) in.readObject();
- this.creationDataType = (ResourceCreationDataType) in.readObject();
- this.createDeletePolicy = (CreateDeletePolicy) in.readObject();
- this.supportsManualAdd = in.readBoolean();
- this.singleton = in.readBoolean();
- this.plugin = in.readUTF();
- this.ctime = in.readLong();
- this.mtime = in.readLong();
- }
-*/
+ public void writeExternalRemote(ObjectOutput out) throws IOException {
+ out.writeInt(this.id);
+ out.writeUTF(this.name);
+ out.writeUTF((null == this.description) ? "" : this.description);
+ out.writeObject(this.category);
+ out.writeObject(this.creationDataType);
+ out.writeObject(this.createDeletePolicy);
+ out.writeBoolean(this.supportsManualAdd);
+ out.writeBoolean(this.singleton);
+ out.writeUTF(this.plugin);
+ out.writeLong(this.ctime);
+ out.writeLong(this.mtime);
+ out.writeObject(this.subCategory);
+ out.writeObject(this.bundleType);
+ out.writeObject((null == childResourceTypes) ? null : new LinkedHashSet<ResourceType>(childResourceTypes));
+ out.writeObject((null == parentResourceTypes) ? null : new LinkedHashSet<ResourceType>(parentResourceTypes));
+ out.writeObject(pluginConfigurationDefinition);
+ out.writeObject(resourceConfigurationDefinition);
+ out.writeObject((null == metricDefinitions) ? null
+ : new LinkedHashSet<MeasurementDefinition>(metricDefinitions));
+ out.writeObject((null == eventDefinitions) ? null : new LinkedHashSet<EventDefinition>(eventDefinitions));
+ out.writeObject((null == operationDefinitions) ? null : new LinkedHashSet<OperationDefinition>(
+ operationDefinitions));
+ out.writeObject((null == processScans) ? null : new LinkedHashSet<ProcessScan>(processScans));
+ out.writeObject((null == packageTypes) ? null : new LinkedHashSet<PackageType>(packageTypes));
+ out.writeObject((null == subCategories) ? null : new LinkedHashSet<ResourceSubCategory>(subCategories));
+ out.writeObject((null == resources) ? null : new LinkedHashSet<Resource>(resources));
+ out.writeObject((null == productVersions) ? null : new LinkedHashSet<ProductVersion>(productVersions));
+ // not supplied by remote: helpText
+ }
+
+ public void readExternalRemote(ObjectInput in) throws IOException, ClassNotFoundException {
+ this.id = in.readInt();
+ this.name = in.readUTF();
+ this.description = in.readUTF();
+ this.category = (ResourceCategory) in.readObject();
+ this.creationDataType = (ResourceCreationDataType) in.readObject();
+ this.createDeletePolicy = (CreateDeletePolicy) in.readObject();
+ this.supportsManualAdd = in.readBoolean();
+ this.singleton = in.readBoolean();
+ this.plugin = in.readUTF();
+ this.ctime = in.readLong();
+ this.mtime = in.readLong();
+ }
+ */
}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceTypeManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceTypeManagerBean.java
index 7589096..a2a6ece 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceTypeManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceTypeManagerBean.java
@@ -113,14 +113,8 @@ public class ResourceTypeManagerBean implements ResourceTypeManagerLocal, Resour
public List<ResourceType> getChildResourceTypes(Subject subject, ResourceType parent) {
Query query = null;
- if (authorizationManager.isInventoryManager(subject)) {
- query = entityManager.createNamedQuery(ResourceType.QUERY_FIND_CHILDREN_admin);
- } else {
- query = entityManager.createNamedQuery(ResourceType.QUERY_FIND_CHILDREN);
- query.setParameter("subject", subject);
- }
-
- query.setParameter("parent", parent);
+ query = entityManager.createNamedQuery(ResourceType.QUERY_FIND_CHILDREN);
+ query.setParameter("resourceTypeId", parent.getId());
List<ResourceType> results = query.getResultList();
return results;
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/ResourceMetadataManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/ResourceMetadataManagerBean.java
index 1cc1b44..a136561 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/ResourceMetadataManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/ResourceMetadataManagerBean.java
@@ -284,26 +284,29 @@ public class ResourceMetadataManagerBean implements ResourceMetadataManagerLocal
return results;
}
+ // Start with no transaction so we can control the transactional boundaries. This is important for a
+ // few reasons. Registering the plugin and removing obsolete types are perfromed in different, subsequent,
+ // transactions. The register may update types, and that locks various rows of the database. Those rows
+ // must be unlocked before obsolete type removal. Type removal executes (resource) bulk delete under the covers,
+ // and that will deadlock with the rows locked by the type update (at least in oracle) if performed in the same
+ // transaction. Furthermore, as mentioned, obsolete type removal removes resources of the obsolete type. We
+ // need to avoid an umbrella transaction for the type removal because large inventories of obsolete resources
+ // will generate very large transactions. Potentially resulting in timeouts or other issues.
@RequiredPermission(Permission.MANAGE_SETTINGS)
- public void registerPlugin(Subject whoami, Plugin plugin, PluginDescriptor pluginDescriptor, File pluginFile,
+ @TransactionAttribute(TransactionAttributeType.NEVER)
+ public void registerPlugin(Subject subject, Plugin plugin, PluginDescriptor pluginDescriptor, File pluginFile,
boolean forceUpdate) throws Exception {
- // Registering the plugin is performed in a new transaction in order to allow the removal
- // of obsolete types, in a subsequent transaction. The register may update types, and that
- // locks various rows of the database. Those rows must be unlocked before type removal. Type
- // removal executes (resource) bulk delete under the covers, in another new trans, and that
- // trans will will deadlock with the rows locked by the type update (at least in oracle) if that
- // transaction has not been committed.
- boolean typesUpdated = resourceMetadataManager.registerPluginInNewTransaction(whoami, plugin, pluginDescriptor,
+ boolean typesUpdated = resourceMetadataManager.registerPluginTypes(subject, plugin, pluginDescriptor,
pluginFile, forceUpdate);
if (typesUpdated) {
- resourceMetadataManager.removeObsoleteTypesInNewTransaction(plugin.getName());
+ removeObsoleteTypes(subject, plugin.getName());
}
}
- @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
- public boolean registerPluginInNewTransaction(Subject whoami, Plugin plugin, PluginDescriptor pluginDescriptor,
+ @RequiredPermission(Permission.MANAGE_SETTINGS)
+ public boolean registerPluginTypes(Subject subject, Plugin plugin, PluginDescriptor pluginDescriptor,
File pluginFile, boolean forceUpdate) throws Exception {
// TODO GH: Consider how to remove features from plugins in updates without breaking everything
@@ -429,7 +432,7 @@ public class ResourceMetadataManagerBean implements ResourceMetadataManagerLocal
return;
}
- private void updateTypes(Set<ResourceType> resourceTypes) throws Exception {
+ private void updateTypes(Set<ResourceType> resourceTypes) throws Exception {
// Only process the type if it is a non-runs-inside type (i.e. not a child of some other type X at this same
// level in the type hierarchy). runs-inside types which we skip here will get processed at the next level down
// when we recursively process type X's children.
@@ -462,18 +465,56 @@ public class ResourceMetadataManagerBean implements ResourceMetadataManagerLocal
}
}
+ // NO TRANSACTION SHOULD BE ACTIVE ON ENTRY
+ // Start with no transaction so we can control the transactional boundaries. Obsolete type removal removes
+ // resources of the obsolete type. We need to avoid an umbrella transaction for the type removal because large
+ // inventories of obsolete resources will generate very large transactions. Potentially resulting in timeouts
+ // or other issues.
+ private void removeObsoleteTypes(Subject subject, String pluginName) {
+
+ Set<ResourceType> obsoleteTypes = new HashSet<ResourceType>();
+ Set<ResourceType> legitTypes = new HashSet<ResourceType>();
+
+ try {
+ resourceMetadataManager.getPluginTypes(subject, pluginName, legitTypes, obsoleteTypes);
+
+ if (!obsoleteTypes.isEmpty()) {
+ // TODO: Log this at DEBUG instead.
+ log.info("Removing " + obsoleteTypes.size() + " obsolete types: " + obsoleteTypes + "...");
+ removeResourceTypes(subject, obsoleteTypes, new HashSet<ResourceType>(obsoleteTypes));
+ }
+
+ // Now it's safe to remove any obsolete subcategories on the legit types.
+ for (ResourceType legitType : legitTypes) {
+ ResourceType updateType = PLUGIN_METADATA_MANAGER.getType(legitType.getName(), legitType.getPlugin());
+
+ // If we've got a type from the descriptor which matches an existing one,
+ // then let's see if we need to remove any subcategories from the existing one.
+ if (updateType != null) {
+ try {
+ resourceMetadataManager.removeObsoleteSubCategories(subject, updateType, legitType);
+ } catch (Exception e) {
+ throw new Exception("Failed to delete obsolete subcategories from " + legitType + ".", e);
+ }
+ }
+ }
+ } catch (Exception e) {
+ // Catch all exceptions, so a failure here does not cause the outer tx to rollback.
+ log.error("Failure during removal of obsolete ResourceTypes and Subcategories.", e);
+ }
+ }
+
+ @RequiredPermission(Permission.MANAGE_SETTINGS)
@SuppressWarnings("unchecked")
- @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
- public void removeObsoleteTypesInNewTransaction(String pluginName) {
+ public void getPluginTypes(Subject subject, String pluginName, Set<ResourceType> legitTypes,
+ Set<ResourceType> obsoleteTypes) {
try {
Query query = entityManager.createNamedQuery(ResourceType.QUERY_FIND_BY_PLUGIN);
query.setParameter("plugin", pluginName);
List<ResourceType> existingTypes = query.getResultList();
if (existingTypes != null) {
- Set<ResourceType> obsoleteTypes = new HashSet<ResourceType>();
- Set<ResourceType> legitTypes = new HashSet<ResourceType>();
- Subject overlord = subjectManager.getOverlord();
+
for (ResourceType existingType : existingTypes) {
if (PLUGIN_METADATA_MANAGER.getType(existingType.getName(), existingType.getPlugin()) == null) {
// The type is obsolete - (i.e. it's no longer defined by the plugin).
@@ -482,28 +523,6 @@ public class ResourceMetadataManagerBean implements ResourceMetadataManagerLocal
legitTypes.add(existingType);
}
}
-
- if (!obsoleteTypes.isEmpty()) {
- // TODO: Log this at DEBUG instead.
- log.info("Removing " + obsoleteTypes.size() + " obsolete types: " + obsoleteTypes + "...");
- removeResourceTypes(overlord, obsoleteTypes, new HashSet<ResourceType>(obsoleteTypes));
- }
-
- // Now it's safe to remove any obsolete subcategories on the legit types.
- for (ResourceType legitType : legitTypes) {
- ResourceType updateType = PLUGIN_METADATA_MANAGER.getType(legitType.getName(), legitType
- .getPlugin());
-
- // If we've got a type from the descriptor which matches an existing one,
- // then let's see if we need to remove any subcategories from the existing one.
- if (updateType != null) {
- try {
- removeObsoleteSubCategories(updateType, legitType);
- } catch (Exception e) {
- throw new Exception("Failed to delete obsolete subcategories from " + legitType + ".", e);
- }
- }
- }
}
} catch (Exception e) {
// Catch all exceptions, so a failure here does not cause the outer tx to rollback.
@@ -511,19 +530,20 @@ public class ResourceMetadataManagerBean implements ResourceMetadataManagerLocal
}
}
- private void removeResourceTypes(Subject overlord, Set<ResourceType> candidateTypes,
- Set<ResourceType> typesToBeRemoved)
- throws Exception {
+ // NO TRANSACTION SHOULD BE ACTIVE ON ENTRY
+ private void removeResourceTypes(Subject subject, Set<ResourceType> candidateTypes,
+ Set<ResourceType> typesToBeRemoved) throws Exception {
for (ResourceType candidateType : candidateTypes) {
// Remove obsolete descendant types first.
- Set<ResourceType> childTypes = candidateType.getChildResourceTypes();
+ //Set<ResourceType> childTypes = candidateType.getChildResourceTypes();
+ List<ResourceType> childTypes = resourceTypeManager.getChildResourceTypes(subject, candidateType);
if (childTypes != null && !childTypes.isEmpty()) {
// Wrap child types in new HashSet to avoid ConcurrentModificationExceptions.
- removeResourceTypes(overlord, new HashSet<ResourceType>(childTypes), typesToBeRemoved);
+ removeResourceTypes(subject, new HashSet<ResourceType>(childTypes), typesToBeRemoved);
}
if (typesToBeRemoved.contains(candidateType)) {
try {
- removeResourceType(overlord, candidateType);
+ removeResourceType(subject, candidateType);
} catch (Exception e) {
throw new Exception("Failed to remove " + candidateType + ".", e);
}
@@ -532,35 +552,44 @@ public class ResourceMetadataManagerBean implements ResourceMetadataManagerLocal
}
}
- private void removeResourceType(Subject overlord, ResourceType existingType) {
- log.info("Removing ResourceType [" + toConciseString(existingType) + "]...");
-
- if (entityManager.contains(existingType)) {
- entityManager.refresh(existingType);
- }
-
- // Completely remove the type from the type hierarchy.
- removeFromParents(existingType);
- removeFromChildren(existingType);
- entityManager.merge(existingType);
+ // NO TRANSACTION SHOULD BE ACTIVE ON ENTRY
+ private void removeResourceType(Subject subject, ResourceType existingType) {
+ log.info("Removing ResourceType [" + toConciseString(existingType) + "]...");
// Remove all Resources that are of the type.
- List<Resource> resources = existingType.getResources();
+ ResourceCriteria c = new ResourceCriteria();
+ c.addFilterResourceTypeId(existingType.getId());
+ List<Resource> resources = resourceManager.findResourcesByCriteria(subject, c);
if (resources != null) {
Iterator<Resource> resIter = resources.iterator();
while (resIter.hasNext()) {
Resource res = resIter.next();
- List<Integer> deletedIds = resourceManager.uninventoryResource(overlord, res.getId());
+ List<Integer> deletedIds = resourceManager.uninventoryResource(subject, res.getId());
// do this out of band because the current transaction is locking rows that due to
// updates that may need to get deleted. If you do it here the NewTrans used below
// may deadlock with the current transactions locks.
for (Integer deletedResourceId : deletedIds) {
- resourceManager.uninventoryResourceAsyncWork(overlord, deletedResourceId);
+ resourceManager.uninventoryResourceAsyncWork(subject, deletedResourceId);
}
resIter.remove();
}
}
- entityManager.flush();
+
+ resourceMetadataManager.completeRemoveResourceType(subject, existingType);
+ }
+
+ @RequiredPermission(Permission.MANAGE_SETTINGS)
+ public void completeRemoveResourceType(Subject subject, ResourceType existingType) {
+ existingType = entityManager.find(ResourceType.class, existingType.getId());
+
+ if (entityManager.contains(existingType)) {
+ entityManager.refresh(existingType);
+ }
+
+ // Completely remove the type from the type hierarchy.
+ removeFromParents(existingType);
+ removeFromChildren(existingType);
+ entityManager.merge(existingType);
// Remove all compatible groups that are of the type.
List<ResourceGroup> compatGroups = existingType.getResourceGroups();
@@ -569,7 +598,7 @@ public class ResourceMetadataManagerBean implements ResourceMetadataManagerLocal
while (compatGroupIterator.hasNext()) {
ResourceGroup compatGroup = compatGroupIterator.next();
try {
- resourceGroupManager.deleteResourceGroup(overlord, compatGroup.getId());
+ resourceGroupManager.deleteResourceGroup(subject, compatGroup.getId());
} catch (ResourceGroupDeleteException e) {
throw new RuntimeException(e);
}
@@ -623,7 +652,6 @@ public class ResourceMetadataManagerBean implements ResourceMetadataManagerLocal
}
}
- @SuppressWarnings("unchecked")
private void updateType(ResourceType resourceType) {
entityManager.flush();
@@ -635,8 +663,8 @@ public class ResourceMetadataManagerBean implements ResourceMetadataManagerLocal
ResourceType existingType;
try {
- existingType = resourceTypeManager.getResourceTypeByNameAndPlugin(resourceType.getName(),
- resourceType.getPlugin());
+ existingType = resourceTypeManager.getResourceTypeByNameAndPlugin(resourceType.getName(), resourceType
+ .getPlugin());
} catch (NonUniqueResultException nure) {
log.debug("Found more than one existing ResourceType for " + resourceType);
// TODO: Delete the redundant ResourceTypes to get the DB into a valid state.
@@ -701,8 +729,8 @@ public class ResourceMetadataManagerBean implements ResourceMetadataManagerLocal
// above already took care of any modifications to the ResourceSubCategories themselves).
} else if (newSubCat == null) {
if (oldSubCat != null) {
- log.debug("Metadata update: Subcategory of ResourceType [" + resourceType.getName()
- + "] changed from " + oldSubCat + " to " + newSubCat);
+ log.debug("Metadata update: Subcategory of ResourceType [" + resourceType.getName() + "] changed from "
+ + oldSubCat + " to " + newSubCat);
existingType.setSubCategory(null);
}
} else {
@@ -762,14 +790,14 @@ public class ResourceMetadataManagerBean implements ResourceMetadataManagerLocal
if (log.isDebugEnabled()) {
if (existingType != null) {
log.debug("Setting parent types on existing type: " + existingType + " to ["
- + newType.getParentResourceTypes() + "] - current parent types are ["
- + existingType.getParentResourceTypes() + "]...");
+ + newType.getParentResourceTypes() + "] - current parent types are ["
+ + existingType.getParentResourceTypes() + "]...");
} else {
- log.debug("Setting parent types on new type: " + newType
- + " to [" + newType.getParentResourceTypes() + "]...");
+ log.debug("Setting parent types on new type: " + newType + " to [" + newType.getParentResourceTypes()
+ + "]...");
}
}
-
+
Set<ResourceType> newParentTypes = newType.getParentResourceTypes();
newType.setParentResourceTypes(new HashSet<ResourceType>());
Set<ResourceType> originalExistingParentTypes = new HashSet<ResourceType>();
@@ -778,7 +806,7 @@ public class ResourceMetadataManagerBean implements ResourceMetadataManagerLocal
}
for (ResourceType newParentType : newParentTypes) {
try {
- boolean isExistingParent = originalExistingParentTypes.remove(newParentType);
+ boolean isExistingParent = originalExistingParentTypes.remove(newParentType);
if (existingType == null || !isExistingParent) {
ResourceType realParentType = (ResourceType) entityManager.createNamedQuery(
ResourceType.QUERY_FIND_BY_NAME_AND_PLUGIN).setParameter("name", newParentType.getName())
@@ -786,19 +814,19 @@ public class ResourceMetadataManagerBean implements ResourceMetadataManagerLocal
ResourceType type = (existingType != null) ? existingType : newType;
if (existingType != null) {
log.info("Adding ResourceType [" + toConciseString(type) + "] as child of ResourceType ["
- + toConciseString(realParentType) + "]...");
+ + toConciseString(realParentType) + "]...");
}
realParentType.addChildResourceType(type);
}
} catch (NoResultException nre) {
- throw new RuntimeException("Couldn't persist type [" + newType
- + "] because parent [" + newParentType + "] wasn't already persisted.");
+ throw new RuntimeException("Couldn't persist type [" + newType + "] because parent [" + newParentType
+ + "] wasn't already persisted.");
}
}
for (ResourceType obsoleteParentType : originalExistingParentTypes) {
log.info("Removing type [" + toConciseString(existingType) + "] from parent type ["
- + toConciseString(obsoleteParentType) + "]...");
+ + toConciseString(obsoleteParentType) + "]...");
obsoleteParentType.removeChildResourceType(existingType);
moveResourcesToNewParent(existingType, obsoleteParentType, newParentTypes);
}
@@ -810,7 +838,8 @@ public class ResourceMetadataManagerBean implements ResourceMetadataManagerLocal
return (type != null) ? (type.getPlugin() + ":" + type.getName() + "(id=" + type.getId() + ")") : "null";
}
- private void moveResourcesToNewParent(ResourceType existingType, ResourceType obsoleteParentType, Set<ResourceType> newParentTypes) {
+ private void moveResourcesToNewParent(ResourceType existingType, ResourceType obsoleteParentType,
+ Set<ResourceType> newParentTypes) {
Subject overlord = subjectManager.getOverlord();
ResourceCriteria criteria = new ResourceCriteria();
criteria.addFilterResourceTypeId(existingType.getId());
@@ -818,8 +847,7 @@ public class ResourceMetadataManagerBean implements ResourceMetadataManagerLocal
List<Resource> resources = resourceManager.findResourcesByCriteria(overlord, criteria);
for (Resource resource : resources) {
Resource newParent = null;
- newParentTypes:
- for (ResourceType newParentType : newParentTypes) {
+ newParentTypes: for (ResourceType newParentType : newParentTypes) {
Resource ancestorResource = resource.getParentResource();
while (ancestorResource != null) {
if (ancestorResource.getResourceType().equals(newParentType)) {
@@ -846,7 +874,7 @@ public class ResourceMetadataManagerBean implements ResourceMetadataManagerLocal
newParent.addChildResource(resource);
} else {
log.debug("We were unable to move " + resource + " from invalid parent " + resource.getParentResource()
- + " to a new valid parent with one of the following types: " + newParentTypes);
+ + " to a new valid parent with one of the following types: " + newParentTypes);
}
}
}
@@ -1326,8 +1354,10 @@ public class ResourceMetadataManagerBean implements ResourceMetadataManagerLocal
* @param newType new resource type containing updated definitions
* @param existingType old resource type with existing definitions
*/
- private void removeObsoleteSubCategories(ResourceType newType, ResourceType existingType) {
+ @RequiredPermission(Permission.MANAGE_SETTINGS)
+ public void removeObsoleteSubCategories(Subject subject, ResourceType newType, ResourceType existingType) {
// Remove all definitions that are in the existing type but not in the new type
+ existingType = entityManager.find(ResourceType.class, existingType.getId());
List<ResourceSubCategory> removedSubCategories = new ArrayList<ResourceSubCategory>(existingType
.getChildSubCategories());
removedSubCategories.removeAll(newType.getChildSubCategories());
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/ResourceMetadataManagerLocal.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/ResourceMetadataManagerLocal.java
index 683f287..d25f4cf 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/ResourceMetadataManagerLocal.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/ResourceMetadataManagerLocal.java
@@ -20,6 +20,7 @@ package org.rhq.enterprise.server.resource.metadata;
import java.io.File;
import java.util.List;
+import java.util.Set;
import javax.ejb.Local;
import javax.persistence.NoResultException;
@@ -28,6 +29,7 @@ import org.rhq.core.clientapi.descriptor.plugin.PluginDescriptor;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.plugin.Plugin;
import org.rhq.core.domain.resource.ResourceCategory;
+import org.rhq.core.domain.resource.ResourceType;
/**
* Provides functionality surrounding agent plugins and their resource metadata.
@@ -44,25 +46,6 @@ public interface ResourceMetadataManagerLocal {
void setPluginEnabledFlag(Subject subject, int pluginId, boolean enabled) throws Exception;
/**
- * For server-side registration of plugin archives. At server startup or as new plugins are runtime deployed the jar
- * will have its descriptor read and parsed and the metadata for the plugin will be updated in the db.
- * If you provide a non-null <code>pluginFile</code>, and the plugin is deemed to be new or updated, the content
- * of the file will be streamed to the database. Note that if you provide a non-null file, you must ensure
- * its MD5 matches that of the file (i.e. this method will not attempt to recompute the file's MD5, it will assume
- * the caller has already done that and provided the proper MD5 in <code>plugin</code>).
- * <br/><br/>
- * NOTE ** This call will register the plugin in a new transaction.
- *
- * @param plugin The plugin object being deployed
- * @param metadata The plugin descriptor file
- * @param pluginFile the actual plugin file whose content will be stored in the database (will be ignored if null)
- * @param forceUpdate if <code>true</code>, the plugin's types will be updated, even if the plugin hasn't changed since
- * the last time it was registered
- */
- void registerPlugin(Subject whoami, Plugin plugin, PluginDescriptor metadata, File pluginFile, boolean forceUpdate)
- throws Exception;
-
- /**
* Returns the list of all plugins deployed in the server.
*
* @return list of plugins deployed
@@ -82,10 +65,36 @@ public interface ResourceMetadataManagerLocal {
*/
Plugin getPlugin(String name);
- /** Exists only to have code execute within its own transaction. Not for general consumption. */
- boolean registerPluginInNewTransaction(Subject whoami, Plugin plugin, PluginDescriptor pluginDescriptor,
- File pluginFile, boolean forceUpdate) throws Exception;
+ /**
+ * For server-side registration of plugin archives. At server startup or as new plugins are runtime deployed the jar
+ * will have its descriptor read and parsed and the metadata for the plugin will be updated in the db.
+ * If you provide a non-null <code>pluginFile</code>, and the plugin is deemed to be new or updated, the content
+ * of the file will be streamed to the database. Note that if you provide a non-null file, you must ensure
+ * its MD5 matches that of the file (i.e. this method will not attempt to recompute the file's MD5, it will assume
+ * the caller has already done that and provided the proper MD5 in <code>plugin</code>).
+ * <br/><br/>
+ * NOTE ** This call will register the plugin in a new transaction.
+ *
+ * @param plugin The plugin object being deployed
+ * @param metadata The plugin descriptor file
+ * @param pluginFile the actual plugin file whose content will be stored in the database (will be ignored if null)
+ * @param forceUpdate if <code>true</code>, the plugin's types will be updated, even if the plugin hasn't changed since
+ * the last time it was registered
+ */
+ void registerPlugin(Subject subject, Plugin plugin, PluginDescriptor metadata, File pluginFile, boolean forceUpdate)
+ throws Exception;
+
+ /** Exists only to for transactional boundary reasons. Not for general consumption. */
+ boolean registerPluginTypes(Subject subject, Plugin plugin, PluginDescriptor pluginDescriptor, File pluginFile,
+ boolean forceUpdate) throws Exception;
+
+ /** Exists only to for transactional boundary reasons. Not for general consumption. */
+ void removeObsoleteSubCategories(Subject subject, ResourceType newType, ResourceType existingType);
+
+ /** Exists only to for transactional boundary reasons. Not for general consumption. */
+ void getPluginTypes(Subject subject, String pluginName, Set<ResourceType> legitTypes,
+ Set<ResourceType> obsoleteTypes);
- /** Exists only to have code execute within its own transaction. Not for general consumption. */
- void removeObsoleteTypesInNewTransaction(String pluginName);
+ /** Exists only to for transactional boundary reasons. Not for general consumption. */
+ void completeRemoveResourceType(Subject subject, ResourceType existingType);
}
\ No newline at end of file