.classpath | 4 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeDatasource.java | 282 ++++++---- modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java | 2 3 files changed, 176 insertions(+), 112 deletions(-)
New commits: commit 59b91a699378df0cae55ea6575760e9f4ff6db2c Merge: 20c1c7a... 6d06818... Author: Jay Shaughnessy jshaughn@redhat.com Date: Thu Oct 7 09:32:46 2010 -0400
Merge branch 'master-jay'
commit 6d06818fbee4c424aa539baaed36634aa513c785 Merge: e7acef3... b1efc02... Author: Jay Shaughnessy jshaughn@redhat.com Date: Thu Oct 7 08:59:31 2010 -0400
Unfortunately ended up mixing a merge resolution with feature work: -- Fix ResourceTree rendering for direct nav to "deep" nodes (like JmsXA). There were a few issues here. So far there have been some changes to ensure proper ordering of tree nodes for parent-child relationships, and more protection against node duplication. This should fix the rendering but we have some other issues resulting in the attemot to add duplicate resource nodes, and also, I think, building the tree twice prior to rendering. I'll look into these issues now but at least the tree should render correctly. -- Merge branch 'master' into master-jay
Conflicts: modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/ResourceGWTService.java modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/ResourceGWTServiceImpl.java
diff --cc .classpath index 0b4abf3,1a1236c..7d1cd22 --- a/.classpath +++ b/.classpath @@@ -252,10 -252,9 +252,9 @@@ <classpathentry exported="true" kind="var" path="M2_REPO/com/google/gwt/gwt-user/2.0.3/gwt-user-2.0.3.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/com/google/gwt/gwt-dev/2.0.3/gwt-dev-2.0.3.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/com/smartgwt/smartgwt/2.2/smartgwt-2.2.jar"/> -- <classpathentry exported="true" kind="var" path="M2_REPO/com/google/code/gwt-log/gwt-log/3.0.3/gwt-log-3.0.3.jar"/> -- <classpathentry exported="true" kind="var" path="M2_REPO/ca/nanometrics/gflot/1.0.0/gflot-1.0.0.jar"/> ++ <classpathentry exported="true" kind="var" path="M2_REPO/com/google/code/gwt-log/gwt-log/3.0.3/gwt-log-3.0.3.jar"/> ++ <classpathentry exported="true" kind="var" path="M2_REPO/ca/nanometrics/gflot/1.0.0/gflot-1.0.0.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/com/jcraft/jsch/0.1.29/jsch-0.1.29.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/commons-jxpath/commons-jxpath/1.3/commons-jxpath-1.3.jar"/> - <classpathentry exported="true" kind="var" path="M2_REPO/com/google/code/gwt-log/gwt-log/3.0.3/gwt-log-3.0.3.jar"/> <classpathentry kind="output" path="eclipse-classes"/> </classpath> diff --cc modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeDatasource.java index d577c4d,d577c4d..17012f8 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeDatasource.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeDatasource.java @@@ -20,9 -20,9 +20,8 @@@ package org.rhq.enterprise.gui.coregui.
import java.util.ArrayList; import java.util.EnumSet; --import java.util.HashMap; ++import java.util.HashSet; import java.util.List; --import java.util.Map; import java.util.Set;
import com.google.gwt.user.client.rpc.AsyncCallback; @@@ -38,7 -38,7 +37,6 @@@ import com.smartgwt.client.widgets.tree
import org.rhq.core.domain.criteria.ResourceCriteria; import org.rhq.core.domain.resource.Resource; --import org.rhq.core.domain.resource.ResourceCategory; import org.rhq.core.domain.resource.ResourceSubCategory; import org.rhq.core.domain.resource.ResourceType; import org.rhq.core.domain.util.PageList; @@@ -132,7 -132,7 +130,8 @@@ public class ResourceTreeDatasource ext return;
} else { -- com.allen_sauer.gwt.log.client.Log.info("ResourceTreeDatasource: Loading Resource [" + parentResourceId + "]..."); ++ com.allen_sauer.gwt.log.client.Log.info("ResourceTreeDatasource: Loading Resource [" + parentResourceId ++ + "]...");
criteria.addFilterParentResourceId(Integer.parseInt(parentResourceId)); } @@@ -176,85 -176,85 +175,196 @@@ * @return */ public static TreeNode[] buildNodes(List<Resource> resources, List<Resource> lockedData) { -- ResourceTreeNode[] nodes = new ResourceTreeNode[resources.size()]; -- for (int i = 0; i < resources.size(); i++) { -- Resource resource = resources.get(i); ++ List<ResourceTreeNode> resourceNodes = new ArrayList<ResourceTreeNode>(resources.size()); ++ for (Resource resource : resources) { ResourceTreeNode node = new ResourceTreeNode(resource, lockedData.contains(resource)); -- nodes[i] = node; ++ resourceNodes.add(node); }
-- return introduceTypeAndCategoryNodes(nodes); ++ List<TreeNode> result = introduceTypeAndCategoryNodes(resourceNodes); ++ com.allen_sauer.gwt.log.client.Log.debug("\nSTARTING FINAL TREE\n"); ++ for (TreeNode node : result) { ++ com.allen_sauer.gwt.log.client.Log.debug("Final: " + node); ++ } ++ com.allen_sauer.gwt.log.client.Log.debug("\nENDING FINAL TREE\n"); ++ return result.toArray(new TreeNode[result.size()]); }
-- private static TreeNode[] introduceTypeAndCategoryNodes(ResourceTreeNode[] resourceNodes) { -- List<TreeNode> updatedNodes = new ArrayList<TreeNode>(); -- // Maps category node IDs to the corresponding category nodes. -- Map<String, SubCategoryTreeNode> subcategoryNodes = new HashMap<String, SubCategoryTreeNode>(); -- // Maps autogroup/type node IDs to the corresponding autogroup/type nodes. -- Map<String, AutoGroupTreeNode> autogroupNodes = new HashMap<String, AutoGroupTreeNode>(); ++ /** ++ * @param resourceNodes ordered such that referenced parent nodes have lower indexes than the referencing child. ++ * @return a new List, properly ordered and including AG and Subcategory nodes. ++ */ ++ private static List<TreeNode> introduceTypeAndCategoryNodes(final List<ResourceTreeNode> resourceNodes) { ++ // The resulting list of nodes, including AG and SC nodes. The list is ordered to ensure all ++ // referenced parent nodes have lower indexes than the referencing child. ++ List<TreeNode> allNodes = new ArrayList<TreeNode>(resourceNodes.size()); ++ // Keep track of the node IDs added so far to ensure we don't add the same node more than once. Note ++ // that the list of resourceNodes passed in may have duplicates as the caller may not be able to ++ // ensure a clean set. ++ Set<String> allNodeIds = new HashSet<String>(resourceNodes.size() * 2);
for (ResourceTreeNode resourceNode : resourceNodes) { -- updatedNodes.add(resourceNode); ++ if (allNodeIds.contains(resourceNode.getID())) { ++ com.allen_sauer.gwt.log.client.Log.debug("skipping duplicate resourceNode: " + resourceNode); ++ continue; ++ }
Resource resource = resourceNode.getResource(); -- ResourceType type = resource.getResourceType(); -- if (type.getCategory() != ResourceCategory.PLATFORM) { -- String autogroupNodeId = AutoGroupTreeNode.idOf(resource); -- if (!autogroupNodes.containsKey(autogroupNodeId)) { -- Resource parentResource = resource.getParentResource(); -- ResourceSubCategory subcategory = type.getSubCategory(); -- if (subcategory != null) { -- com.allen_sauer.gwt.log.client.Log.debug("Processing " + subcategory + "..."); -- do { -- String subcategoryNodeId = SubCategoryTreeNode.idOf(subcategory, parentResource); -- if (!subcategoryNodes.containsKey(subcategoryNodeId)) { -- SubCategoryTreeNode subcategoryNode = new SubCategoryTreeNode(subcategory, -- parentResource); -- subcategoryNodes.put(subcategoryNode.getID(), subcategoryNode); -- com.allen_sauer.gwt.log.client.Log.debug("Adding " + subcategoryNode + " to tree..."); -- updatedNodes.add(subcategoryNode); -- } -- } while ((subcategory = subcategory.getParentSubCategory()) != null); -- }
-- if (!type.isSingleton()) { -- AutoGroupTreeNode autogroupNode = new AutoGroupTreeNode(resource); -- autogroupNodes.put(autogroupNodeId, autogroupNode); -- com.allen_sauer.gwt.log.client.Log.debug("Adding " + autogroupNode + " to tree..."); -- updatedNodes.add(autogroupNode); ++ if (resourceNode.isParentSubCategory()) { ++ // If the parent node is a subcategory node, make sure the subcategory node is in the ++ // tree prior to the resource node. Note that it could itself be a tree of subcategories. ++ addSubCategoryNodes(allNodes, allNodeIds, resource); ++ ++ } else if (resourceNode.isParentAutoGroup()) { ++ ++ // If the parent node is an autogroup node, make sure the autogroup node is in the ++ // tree prior to the resource node. ++ ++ if (!allNodeIds.contains(resourceNode.getParentID())) { ++ AutoGroupTreeNode autogroupNode = new AutoGroupTreeNode(resource); ++ ++ if (autogroupNode.isParentSubcategory()) { ++ // If the parent node of the autogroup node is a subcategory node, make sure the subcategory ++ // node is in the tree prior to the autogroup node. Note that it could itself be a ++ // tree of subcategories. ++ addSubCategoryNodes(allNodes, allNodeIds, resource); ++ } ++ allNodeIds.add(resourceNode.getParentID()); ++ com.allen_sauer.gwt.log.client.Log.debug("Adding " + autogroupNode); ++ allNodes.add(autogroupNode); } } ++ ++ com.allen_sauer.gwt.log.client.Log.debug("Adding " + resourceNode + " to tree..."); ++ allNodeIds.add(resourceNode.getID()); ++ allNodes.add(resourceNode); ++ } ++ ++ return allNodes; ++ } ++ ++ // convenience routine to avoid code duplication ++ private static void addSubCategoryNodes(List<TreeNode> allNodes, Set<String> allNodeIds, Resource resource) { ++ Resource parentResource = resource.getParentResource(); ++ ResourceType type = resource.getResourceType(); ++ ResourceSubCategory subCategory = type.getSubCategory(); ++ String subCategoryNodeId = null; ++ int insertAt = allNodes.size(); ++ ++ do { ++ subCategoryNodeId = SubCategoryTreeNode.idOf(subCategory, parentResource); ++ ++ if (!allNodeIds.contains(subCategoryNodeId)) { ++ SubCategoryTreeNode subCategoryNode = new SubCategoryTreeNode(subCategory, parentResource); ++ allNodeIds.add(subCategoryNodeId); ++ com.allen_sauer.gwt.log.client.Log.debug("Adding " + subCategoryNode); ++ allNodes.add(insertAt, subCategoryNode); ++ } ++ } while ((subCategory = subCategory.getParentSubCategory()) != null); ++ } ++ ++ public static class ResourceTreeNode extends EnhancedTreeNode { ++ private Resource resource; ++ private boolean isLocked; ++ private boolean parentAutoGroup = false; ++ private boolean parentSubCategory = false; ++ ++ /** ++ * The parentID will be set to the parent resource at construction. It can be changed ++ * later (prior to tree linkage) if the resource node should logically be set to an ++ * autogroup or subcategory parent. ++ * @param resource ++ * @param isLocked ++ */ ++ private ResourceTreeNode(Resource resource, boolean isLocked) { ++ this.resource = resource; ++ this.isLocked = isLocked; ++ ++ String id = idOf(resource); ++ setID(id); ++ ++ // a resource node can have any of three different parent node types; resource, subcategory or autogroup. ++ // this can be determined at construction time so set it properly now and assume the proper node ++ // structure will be in place later. ++ Resource parentResource = resource.getParentResource(); ++ String parentId = null; ++ ++ if (null != parentResource) { ++ // non-singletons will always be autogrouped ++ if (!resource.getResourceType().isSingleton()) { ++ parentId = AutoGroupTreeNode.idOf(resource); ++ this.parentAutoGroup = true; ++ ++ } else { ++ ResourceSubCategory subCategory = resource.getResourceType().getSubCategory(); ++ if (null != subCategory) { ++ parentId = SubCategoryTreeNode.idOf(subCategory, parentResource); ++ this.parentSubCategory = true; ++ } else ++ parentId = ResourceTreeNode.idOf(parentResource); ++ } ++ } ++ this.setParentID(parentId); ++ ++ String name = resource.getName(); ++ setName(name); ++ ++ setAttribute(Attributes.DESCRIPTION, resource.getDescription()); ++ ++ Set<ResourceType> childTypes = resource.getResourceType().getChildResourceTypes(); ++ setIsFolder((childTypes != null && !childTypes.isEmpty())); ++ } ++ ++ public Resource getResource() { ++ return this.resource; ++ } ++ ++ public boolean isLocked() { ++ return isLocked; ++ } ++ ++ public boolean isParentAutoGroup() { ++ return parentAutoGroup; ++ } ++ ++ public boolean isParentSubCategory() { ++ return parentSubCategory; ++ } ++ ++ public static String idOf(Resource resource) { ++ return idOf(resource.getId()); }
-- return updatedNodes.toArray(new TreeNode[updatedNodes.size()]); ++ public static String idOf(int resourceId) { ++ return String.valueOf(resourceId); ++ } }
/** -- * The folder node for a Resource subcategory. ++ * The folder node for a Resource subCategory. */ public static class SubCategoryTreeNode extends EnhancedTreeNode { ++ public SubCategoryTreeNode(ResourceSubCategory category, Resource parentResource) { String id = idOf(category, parentResource); setID(id); -- setAttribute(Attributes.ID, id);
ResourceSubCategory parentCategory = category.getParentSubCategory(); String parentId = (parentCategory != null) ? SubCategoryTreeNode.idOf(parentCategory, parentResource) : ResourceTreeNode.idOf(parentResource); setParentID(parentId); -- setAttribute(Attributes.PARENT_ID, parentId);
-- // Note, subcategory names are typically already plural, so there's no need to pluralize them. ++ // Note, subCategory names are typically already plural, so there's no need to pluralize them. String name = category.getDisplayName(); setName(name); -- setAttribute(Attributes.NAME, name);
setAttribute(Attributes.DESCRIPTION, category.getDescription()); }
public static String idOf(ResourceSubCategory category, Resource parentResource) { -- return "subcat" + category.getId() + "_" + parentResource.getId(); ++ return "subcat_" + category.getId() + "_" + parentResource.getId(); } }
@@@ -265,6 -265,6 +375,7 @@@
private Resource parentResource; private ResourceType resourceType; ++ private boolean parentSubcategory = false;
/** * @param resource requires resourceType field be set. requires parentResource field be set (null for no parent) @@@ -276,15 -276,15 +387,21 @@@ String id = idOf(resource); setID(id);
-- String parentId = parentIdOf(resource); ++ // parent node is either a subCategory node or a resource node ++ String parentId; ++ ResourceSubCategory subcategory = this.resourceType.getSubCategory(); ++ if (subcategory != null) { ++ parentId = SubCategoryTreeNode.idOf(subcategory, this.parentResource); ++ this.parentSubcategory = true; ++ } else { ++ parentId = ResourceTreeNode.idOf(this.parentResource); ++ } setParentID(parentId);
-- ResourceType type = resource.getResourceType(); -- String name = StringUtility.pluralize(type.getName()); ++ String name = StringUtility.pluralize(this.resourceType.getName()); setName(name); -- setAttribute(Attributes.NAME, name);
-- setAttribute(Attributes.DESCRIPTION, type.getDescription()); ++ setAttribute(Attributes.DESCRIPTION, this.resourceType.getDescription()); }
public Resource getParentResource() { @@@ -306,6 -306,6 +423,10 @@@ return this.getParentResource().getName() + " ( " + this.getResourceType().getName() + " )"; }
++ public boolean isParentSubcategory() { ++ return parentSubcategory; ++ } ++ /** * Given a Resource, generate a unique ID for the AGNode. * @@@ -328,63 -328,63 +449,6 @@@ public static String idOf(Resource parentResource, ResourceType resourceType) { return (parentResource != null) ? "autogroup_" + resourceType.getId() + "_" + parentResource.getId() : null; } -- -- // parent node is either a subcategory node or a resouce node -- public static String parentIdOf(Resource resource) { -- ResourceType type = resource.getResourceType(); -- ResourceSubCategory parentCategory = type.getSubCategory(); -- return (parentCategory != null) ? SubCategoryTreeNode.idOf(parentCategory, resource.getParentResource()) -- : ResourceTreeNode.idOf(resource.getParentResource()); -- } }
-- public static class ResourceTreeNode extends EnhancedTreeNode { -- private Resource resource; -- private boolean isLocked; -- -- private ResourceTreeNode(Resource resource, boolean isLocked) { -- this.resource = resource; -- this.isLocked = isLocked; -- -- String id = idOf(resource); -- setID(id); -- setAttribute(Attributes.ID, id); -- -- Resource parentResource = resource.getParentResource(); -- String parentId; -- if (parentResource != null) { -- parentId = resource.getResourceType().isSingleton() ? AutoGroupTreeNode.parentIdOf(resource) -- : AutoGroupTreeNode.idOf(resource); -- } else { -- parentId = null; -- } -- setParentID(parentId); -- setAttribute(Attributes.PARENT_ID, parentId); -- -- String name = resource.getName(); -- setName(name); -- setAttribute(Attributes.NAME, name); -- -- setAttribute(Attributes.DESCRIPTION, resource.getDescription()); -- -- Set<ResourceType> childTypes = resource.getResourceType().getChildResourceTypes(); -- setIsFolder((childTypes != null && !childTypes.isEmpty())); -- } -- -- public Resource getResource() { -- return this.resource; -- } -- -- public boolean isLocked() { -- return isLocked; -- } -- -- public static String idOf(Resource resource) { -- return idOf(resource.getId()); -- } -- -- public static String idOf(int resourceId) { -- return String.valueOf(resourceId); -- } -- } } diff --cc modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java index 97a7d2f,97a7d2f..aefb031 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java @@@ -104,7 -104,7 +104,7 @@@ public class ResourceTreeView extends L private List<ResourceSelectListener> selectListeners = new ArrayList<ResourceSelectListener>();
// Maps autogroup/type backing group ids to the corresponding autogroup/type nodes. -- Map<Integer, AutoGroupTreeNode> autoGroupNodeMap = new HashMap<Integer, AutoGroupTreeNode>(); ++ private Map<Integer, AutoGroupTreeNode> autoGroupNodeMap = new HashMap<Integer, AutoGroupTreeNode>();
public ResourceTreeView(String locatorId) { super(locatorId);
commit e7acef3bd0f3bcc2122316cbbbc96366924c69f3 Merge: 87af918... 885a5f5... Author: Jay Shaughnessy jshaughn@redhat.com Date: Mon Oct 4 18:06:53 2010 -0400
Merge branch 'master' into master-jay
Conflicts: modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/CoreGUI.gwt.xml
commit 87af918747d582095353ede483dfa8e1c46b7a63 Author: Jay Shaughnessy jshaughn@redhat.com Date: Mon Oct 4 18:03:28 2010 -0400
Initial Manual Add Work
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/ResourceGWTService.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/ResourceGWTService.java index 7ad683a..8a0329e 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/ResourceGWTService.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/ResourceGWTService.java @@ -68,4 +68,6 @@ public interface ResourceGWTService extends RemoteService {
void unignoreResources(Integer[] resourceIds);
+ Resource manuallyAddResource(int resourceTypeId, int parentResourceId, Configuration pluginConfiguration); + } \ No newline at end of file diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java index d6cfdba..97a7d2f 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java @@ -300,9 +300,11 @@ public class ResourceTreeView extends LocatableVLayout { // Update breadcrumbs if (currentViewId != null) { currentViewId.getBreadcrumbs().clear(); - for (int i = parents.length - 1; i >= 0; i--) { - TreeNode n = parents[i]; - adjustBreadcrumb(n, currentViewId); + if (null != parents) { + for (int i = parents.length - 1; i >= 0; i--) { + TreeNode n = parents[i]; + adjustBreadcrumb(n, currentViewId); + } } adjustBreadcrumb(selectedNode, currentViewId); CoreGUI.refreshBreadCrumbTrail(); @@ -456,13 +458,15 @@ public class ResourceTreeView extends LocatableVLayout { for (final ResourceType childType : resourceType.getChildResourceTypes()) { if (childType.isCreatable()) { MenuItem createItem = new MenuItem(childType.getName()); - createChildSubMenu.addItem(createItem); + createItem.addClickHandler(new ClickHandler() { public void onClick(MenuItemClickEvent event) { ResourceFactoryCreateWizard.showCreateWizard(resource, childType); } });
+ createChildSubMenu.addItem(createItem); + } } createChildMenu.setSubmenu(createChildSubMenu); @@ -472,21 +476,30 @@ public class ResourceTreeView extends LocatableVLayout { // Manually Add Menu MenuItem importChildMenu = new MenuItem("Import"); Menu importChildSubMenu = new Menu(); - for (ResourceType childType : resourceType.getChildResourceTypes()) { + for (final ResourceType childType : resourceType.getChildResourceTypes()) { if (childType.isSupportsManualAdd()) { - importChildSubMenu.addItem(new MenuItem(childType.getName())); - //todo action + MenuItem importItem = new MenuItem(childType.getName()); + + importItem.addClickHandler(new ClickHandler() { + public void onClick(MenuItemClickEvent event) { + ResourceFactoryCreateWizard.showImportWizard(resource, childType); + } + }); + + importChildSubMenu.addItem(importItem); } } + if (resourceType.getCategory() == ResourceCategory.PLATFORM) { - loadManuallyAddServersToPlatforms(importChildSubMenu); + loadManuallyAddServersToPlatforms(importChildSubMenu, resource); } + importChildMenu.setSubmenu(importChildSubMenu); importChildMenu.setEnabled(importChildSubMenu.getItems().length > 0); resourceContextMenu.addItem(importChildMenu); }
- private void loadManuallyAddServersToPlatforms(final Menu manuallyAddMenu) { + private void loadManuallyAddServersToPlatforms(final Menu manuallyAddMenu, final Resource resource) { ResourceTypeGWTServiceAsync rts = GWTServiceLookup.getResourceTypeGWTService();
ResourceTypeCriteria criteria = new ResourceTypeCriteria(); @@ -498,9 +511,16 @@ public class ResourceTreeView extends LocatableVLayout { }
public void onSuccess(PageList<ResourceType> result) { - for (ResourceType type : result) { + for (final ResourceType type : result) { if (type.getParentResourceTypes() == null || type.getParentResourceTypes().isEmpty()) { MenuItem item = new MenuItem(type.getName()); + + item.addClickHandler(new ClickHandler() { + public void onClick(MenuItemClickEvent event) { + ResourceFactoryCreateWizard.showImportWizard(resource, type); + } + }); + manuallyAddMenu.addItem(item); } } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/factory/ConfigurationStep.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/factory/ConfigurationStep.java index 84c6b55..5d7fbdc 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/factory/ConfigurationStep.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/factory/ConfigurationStep.java @@ -49,6 +49,7 @@ public class ConfigurationStep extends AbstractWizardStep { }
public boolean nextPage() { + wizard.execute(); return true; }
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/factory/ConfigurationTemplateStep.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/factory/ConfigurationTemplateStep.java index 0db5af8..a588010 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/factory/ConfigurationTemplateStep.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/factory/ConfigurationTemplateStep.java @@ -20,6 +20,7 @@ package org.rhq.enterprise.gui.coregui.client.inventory.resource.factory;
import java.util.Map;
+import com.smartgwt.client.types.TitleOrientation; import com.smartgwt.client.widgets.Canvas; import com.smartgwt.client.widgets.form.DynamicForm; import com.smartgwt.client.widgets.form.fields.SelectItem; @@ -49,10 +50,17 @@ public class ConfigurationTemplateStep extends AbstractWizardStep {
form = new LocatableDynamicForm("ResFactConfigTemplate");
- TextItem nameItem = new TextItem("resourceName", "Resource Name"); - nameItem.setRequired(true); + TextItem nameItem = null;
- SelectItem templateSelect = new SelectItem("template", "Template"); + if (!this.wizard.isImport()) { + nameItem = new TextItem("resourceName", "New Resource Name"); + nameItem.setWidth(300); + nameItem.setRequired(true); + } + + SelectItem templateSelect = new SelectItem("template", "Connection Property Templates (Choose One)"); + templateSelect.setTitleOrientation(TitleOrientation.TOP); + templateSelect.setWidth(300);
ConfigurationDefinition definition = wizard.getConfigurationDefinition();
@@ -64,9 +72,14 @@ public class ConfigurationTemplateStep extends AbstractWizardStep { templateSelect.setDisabled(true); }
- form.setItems(nameItem, templateSelect); + if (null != nameItem) { + form.setItems(nameItem, templateSelect); + } else { + form.setItems(templateSelect); + }
} + return form; }
@@ -75,7 +88,7 @@ public class ConfigurationTemplateStep extends AbstractWizardStep { }
public String getName() { - return "New Resource"; + return "Resource Information"; }
public Configuration getConfiguration() { diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/factory/ResourceFactoryCreateWizard.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/factory/ResourceFactoryCreateWizard.java index bad2058..7968635 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/factory/ResourceFactoryCreateWizard.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/factory/ResourceFactoryCreateWizard.java @@ -19,14 +19,9 @@ package org.rhq.enterprise.gui.coregui.client.inventory.resource.factory;
import java.util.ArrayList; -import java.util.Collections; import java.util.EnumSet; -import java.util.List;
import com.google.gwt.user.client.rpc.AsyncCallback; -import com.smartgwt.client.widgets.IButton; -import com.smartgwt.client.widgets.events.ClickEvent; -import com.smartgwt.client.widgets.events.ClickHandler;
import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.definition.ConfigurationDefinition; @@ -48,6 +43,7 @@ public class ResourceFactoryCreateWizard extends AbstractWizard { private ConfigurationDefinition configurationDefinition; private Resource parentResource; private ResourceType createType; + private boolean isImport; // manual add vs. create new child
private WizardView view;
@@ -55,10 +51,11 @@ public class ResourceFactoryCreateWizard extends AbstractWizard { private ConfigurationStep configurationStep;
public ResourceFactoryCreateWizard(Resource parentResource, ResourceType createType, - ConfigurationDefinition configurationDefinition) { + ConfigurationDefinition configurationDefinition, boolean isImport) { this.parentResource = parentResource; this.createType = createType; this.configurationDefinition = configurationDefinition; + this.isImport = isImport;
assert parentResource != null; assert createType != null; @@ -66,8 +63,12 @@ public class ResourceFactoryCreateWizard extends AbstractWizard {
ArrayList<WizardStep> steps = new ArrayList<WizardStep>();
- configurationTemplateStep = new ConfigurationTemplateStep(this); - steps.add(configurationTemplateStep); + // skip the template step if this is an import (no resource name to be gathered) and the + // type has only the default template to offer for user selection. + if (!(this.isImport && this.configurationDefinition.getTemplates().size() < 2)) { + this.configurationTemplateStep = new ConfigurationTemplateStep(this); + steps.add(configurationTemplateStep); + }
configurationStep = new ConfigurationStep(this); steps.add(configurationStep); @@ -76,52 +77,57 @@ public class ResourceFactoryCreateWizard extends AbstractWizard { }
public String getWindowTitle() { - return "Resource Create Wizard"; + return isImport() ? "Import Resource Wizard" : "Resource Create Wizard"; }
public String getTitle() { - return "Create New " + createType.getName(); + return (isImport() ? "Import Resource of Type: " : "Create New Resource of Type: ") + createType.getName(); }
public String getSubtitle() { return null; }
- public List<IButton> getCustomButtons(int step) { - switch (step) { - case 1: - IButton createButton = new IButton("Create"); - createButton.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent clickEvent) { - execute(); - } - }); - return Collections.singletonList(createButton); - } - return null; - } - - private void execute() { + public void execute() {
- int parentReourceId = parentResource.getId(); + int parentResourceId = parentResource.getId(); int createTypeId = createType.getId(); - String newResourceName = configurationTemplateStep.getResourceName(); Configuration newConfiguration = configurationStep.getConfiguration();
- GWTServiceLookup.getResourceService().createResource(parentReourceId, createTypeId, newResourceName, - newConfiguration, new AsyncCallback<Void>() { - public void onFailure(Throwable caught) { - CoreGUI.getErrorHandler().handleError("Failed to create new resource", caught); - view.closeDialog(); - } - - public void onSuccess(Void result) { - CoreGUI.getMessageCenter().notify( - new Message("Submitted request to create new resource [" - + configurationTemplateStep.getResourceName() + "]", Message.Severity.Info)); - view.closeDialog(); - } - }); + if (isImport) { + GWTServiceLookup.getResourceService().manuallyAddResource(createTypeId, parentResourceId, newConfiguration, + new AsyncCallback<Resource>() { + public void onFailure(Throwable caught) { + CoreGUI.getErrorHandler().handleError("Failed to manually add resource", caught); + view.closeDialog(); + } + + public void onSuccess(Resource result) { + CoreGUI.getMessageCenter().notify( + new Message("Submitted request to manually add [" + createType.getName() + "]", + Message.Severity.Info)); + view.closeDialog(); + } + }); + + } else { + String newResourceName = configurationTemplateStep.getResourceName(); + + GWTServiceLookup.getResourceService().createResource(parentResourceId, createTypeId, newResourceName, + newConfiguration, new AsyncCallback<Void>() { + public void onFailure(Throwable caught) { + CoreGUI.getErrorHandler().handleError("Failed to create new resource", caught); + view.closeDialog(); + } + + public void onSuccess(Void result) { + CoreGUI.getMessageCenter().notify( + new Message("Submitted request to create new resource [" + + configurationTemplateStep.getResourceName() + "]", Message.Severity.Info)); + view.closeDialog(); + } + }); + } }
public void display() { @@ -135,7 +141,19 @@ public class ResourceFactoryCreateWizard extends AbstractWizard { new ResourceTypeRepository.TypeLoadedCallback() { public void onTypesLoaded(ResourceType type) { ResourceFactoryCreateWizard wizard = new ResourceFactoryCreateWizard(parentResource, type, type - .getResourceConfigurationDefinition()); + .getResourceConfigurationDefinition(), false); + wizard.display(); + } + }); + } + + public static void showImportWizard(final Resource parentResource, ResourceType childType) { + ResourceTypeRepository.Cache.getInstance().getResourceTypes(childType.getId(), + EnumSet.of(ResourceTypeRepository.MetadataType.pluginConfigurationDefinition), + new ResourceTypeRepository.TypeLoadedCallback() { + public void onTypesLoaded(ResourceType type) { + ResourceFactoryCreateWizard wizard = new ResourceFactoryCreateWizard(parentResource, type, type + .getPluginConfigurationDefinition(), true); wizard.display(); } }); @@ -146,7 +164,8 @@ public class ResourceFactoryCreateWizard extends AbstractWizard { }
public Configuration getConfiguration() { - return configurationTemplateStep.getConfiguration(); + return (null == configurationTemplateStep) ? this.configurationDefinition.getDefaultTemplate() + .createConfiguration() : configurationTemplateStep.getConfiguration(); }
public Resource getParentResource() { @@ -157,6 +176,10 @@ public class ResourceFactoryCreateWizard extends AbstractWizard { return createType; }
+ public boolean isImport() { + return isImport; + } + public void cancel() { // TODO: revert back to original state } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/ResourceGWTServiceImpl.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/ResourceGWTServiceImpl.java index 4e14b75..d256222 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/ResourceGWTServiceImpl.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/ResourceGWTServiceImpl.java @@ -202,7 +202,7 @@ public class ResourceGWTServiceImpl extends AbstractGWTServiceImpl implements Re platform.setChildren(servers); }
- return platforms; + return SerialUtility.prepare(platforms, "ResourceService.findRecentlyAddedResources"); } catch (Exception e) { throw new RuntimeException(ThrowableUtil.getAllMessages(e)); } @@ -281,4 +281,13 @@ public class ResourceGWTServiceImpl extends AbstractGWTServiceImpl implements Re } }
+ public Resource manuallyAddResource(int resourceTypeId, int parentResourceId, Configuration pluginConfiguration) { + try { + Resource result = discoveryBoss.manuallyAddResource(getSessionSubject(), resourceTypeId, parentResourceId, + pluginConfiguration); + return SerialUtility.prepare(result, "ResourceService.manuallyAddResource"); + } catch (Exception e) { + throw new RuntimeException(ThrowableUtil.getAllMessages(e)); + } + } } \ No newline at end of file
commit f4c316bed1ed30f33cc6365421f051b945710870 Author: Jay Shaughnessy jshaughn@redhat.com Date: Mon Oct 4 15:06:46 2010 -0400
Disable the experimental browser window logging out of the box
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/CoreGUI.gwt.xml b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/CoreGUI.gwt.xml index ed2ce42..93d7ecb 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/CoreGUI.gwt.xml +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/CoreGUI.gwt.xml @@ -38,7 +38,7 @@ 2. In hosted mode, the windows are not automatically closed, although you can easily close them manually in the usual way --> - <set-property name="log_WindowLogger" value="ENABLED" /> + <set-property name="log_WindowLogger" value="DISABLED" />
<!-- You probably will want to disable the default `DivLogger` as well:
commit 3e06a613d311af3100a6d0a605a43a07564c9406 Merge: e68906f... 614e969... Author: Jay Shaughnessy jshaughn@redhat.com Date: Fri Oct 1 21:12:36 2010 -0400
Merge branch 'master' into master-jay
commit e68906f5c7e3048921143a9d029a9e421c019f1d Merge: a524764... 54400ac... Author: Jay Shaughnessy jshaughn@redhat.com Date: Fri Oct 1 18:18:10 2010 -0400
Merge branch 'master' into master-jay
Conflicts: modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/ResourceGWTServiceImpl.java
diff --cc .classpath index 0a567d7,0a567d7..9a892fa --- a/.classpath +++ b/.classpath @@@ -255,5 -255,5 +255,6 @@@ <classpathentry exported="true" kind="var" path="M2_REPO/ca/nanometrics/gflot/1.0.0/gflot-1.0.0.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/com/jcraft/jsch/0.1.29/jsch-0.1.29.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/commons-jxpath/commons-jxpath/1.3/commons-jxpath-1.3.jar"/> ++ <classpathentry exported="true" kind="var" path="M2_REPO/com/google/code/gwt-log/gwt-log/3.0.3/gwt-log-3.0.3.jar"/> <classpathentry kind="output" path="eclipse-classes"/> </classpath>
commit a5247649b27165b9f2356a2d0d8dc983eaf7f8db Author: Jay Shaughnessy jshaughn@redhat.com Date: Fri Oct 1 18:00:25 2010 -0400
Reverting a change made in 6415ed10e3b0d967b712a7be0aa0a3fcf4ce95cb, it breaks rendering of single-element paths (like "#Bundles or #Reports). The BookmarkableView's renderView needs to be invoked.
I didn't see any ill effect of adding this back in, so I'm not sure of the intent of the original change. May need more work.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/CoreGUI.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/CoreGUI.java index 34cf23e..d685c41 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/CoreGUI.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/CoreGUI.java @@ -300,12 +300,19 @@ public class CoreGUI implements EntryPoint, ValueChangeHandler<String> { }
if (this.currentCanvas instanceof BookmarkableView) { - viewPath.next(); - if (!viewPath.isEnd()) { - ((BookmarkableView) this.currentCanvas).renderView(viewPath); - } + ((BookmarkableView) this.currentCanvas).renderView(viewPath.next()); }
+ // reverting this is as it breaks rendering of single-element paths (like "#Bundles or + // #Reports. the BookmarkableView's renderView needs to be invoked. + // + //if (this.currentCanvas instanceof BookmarkableView) { + // viewPath.next(); + // if (!viewPath.isEnd()) { + // ((BookmarkableView) this.currentCanvas).renderView(viewPath); + // } + //} + refreshBreadCrumbTrail(); } } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundleView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundleView.java index fb382fa..4dc2182 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundleView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundleView.java @@ -45,6 +45,7 @@ import org.rhq.enterprise.gui.coregui.client.Breadcrumb; import org.rhq.enterprise.gui.coregui.client.CoreGUI; import org.rhq.enterprise.gui.coregui.client.ViewId; import org.rhq.enterprise.gui.coregui.client.ViewPath; +import org.rhq.enterprise.gui.coregui.client.bundle.BundleTopView; import org.rhq.enterprise.gui.coregui.client.bundle.deploy.BundleDeployWizard; import org.rhq.enterprise.gui.coregui.client.bundle.deployment.BundleDeploymentView; import org.rhq.enterprise.gui.coregui.client.bundle.destination.BundleDestinationListView; @@ -98,7 +99,7 @@ public class BundleView extends LocatableVLayout implements BookmarkableView {
this.bundle = bundle;
- addMember(new BackButton(extendLocatorId("BackButton"), "Back to All Bundles", "Bundles")); + addMember(new BackButton(extendLocatorId("BackButton"), "Back to All Bundles", BundleTopView.VIEW_ID));
headerLabel = new HeaderLabel("subsystems/bundle/Bundle_24.png", bundle.getName());
commit fe8861d6f05baadd45f2ee9cad1deec2236970bf Author: Jay Shaughnessy jshaughn@redhat.com Date: Fri Oct 1 16:27:38 2010 -0400
add jxpath test dep lib
diff --git a/.classpath b/.classpath index c13d973..0a567d7 100644 --- a/.classpath +++ b/.classpath @@ -254,5 +254,6 @@ <classpathentry exported="true" kind="var" path="M2_REPO/com/smartgwt/smartgwt/2.2/smartgwt-2.2.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/ca/nanometrics/gflot/1.0.0/gflot-1.0.0.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/com/jcraft/jsch/0.1.29/jsch-0.1.29.jar"/> + <classpathentry exported="true" kind="var" path="M2_REPO/commons-jxpath/commons-jxpath/1.3/commons-jxpath-1.3.jar"/> <classpathentry kind="output" path="eclipse-classes"/> </classpath>
commit 346c2223929d9d776a5bdc280fe87fcd159e2cb2 Merge: af34961... 77a5659... Author: Jay Shaughnessy jshaughn@redhat.com Date: Fri Oct 1 10:04:07 2010 -0400
Merge branch 'master' into master-jay
commit 77a56598165197564c6e165211a04ec31a9979f8 Author: Jay Shaughnessy jshaughn@redhat.com Date: Tue Sep 28 12:35:44 2010 -0400
AutoGroup/ResourceTree work - Fix up breadcrumbs for AutoGroup selections and also fix up some path - issues that were happening when selecting AG resources.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/CoreGUI.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/CoreGUI.java index bb39f2d..34cf23e 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/CoreGUI.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/CoreGUI.java @@ -254,10 +254,13 @@ public class CoreGUI implements EntryPoint, ValueChangeHandler<String> { if (viewPath.matches("(" + ResourceTopView.VIEW_ID + "|" + ResourceGroupTopView.VIEW_ID + ")/[^/]*")) { // e.g. "Resource/10001" if (!currentViewPath.startsWith(viewPath)) { - // The Resource that was selected is not the same Resource that was previously selected - - // grab the end portion of the previous history URL and append it to the new history URL, - // so the same tab is selected for the new Resource. - String suffix = currentViewPath.replaceFirst("^[^/]*/[^/]*", ""); + // The Node that was selected is not the same Node that was previously selected - it + // may not even be the same node type. For example, the user could have moved from a + // resource to an autogroup in the same tree. Try to keep the tab selection sticky as best as + // possible while moving from one view to another by grabbing the end portion of the previous + // history URL and append it to the new history URL. The suffix is assumed to follow the + // ID (numeric) portion of the currentViewPath. + String suffix = currentViewPath.replaceFirst("\D*[^/]*", ""); viewPath += suffix; } } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java index 6a7cba9..0d16bea 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java @@ -236,7 +236,6 @@ public class ResourceTreeView extends LocatableVLayout { // get back to this node given the id of the backing group (from the viewpath) autoGroupNodeMap.put(result.getId(), agNode); callback.onSuccess(result); - //renderAutoGroup(result); } }); } else { @@ -302,6 +301,23 @@ public class ResourceTreeView extends LocatableVLayout { } }
+ private void adjustBreadcrumb(TreeNode node, ViewId viewId) { + if (node instanceof ResourceTreeNode) { + Resource nr = ((ResourceTreeNode) node).getResource(); + String display = node.getName() + " <span class="subtitle">" + nr.getResourceType().getName() + "</span>"; + String icon = "types/" + nr.getResourceType().getCategory().getDisplayName() + "_up_16.png"; + + viewId.getBreadcrumbs().add(new Breadcrumb(node.getAttribute("id"), display, icon, true)); + + } else if (node instanceof AutoGroupTreeNode) { + String name = ((AutoGroupTreeNode) node).getBackingGroupName(); + String display = node.getName() + " <span class="subtitle">" + name + "</span>"; + String icon = "types/" + ((AutoGroupTreeNode) node).getResourceType().getCategory() + "_up_16.png"; + + viewId.getBreadcrumbs().add(new Breadcrumb(node.getAttribute("id"), display, icon, true)); + } + } + private void showContextMenu(AutoGroupTreeNode agNode) { getAutoGroupBackingGroup(agNode, new AsyncCallback<ResourceGroup>() { public void onFailure(Throwable caught) { @@ -680,23 +696,6 @@ public class ResourceTreeView extends LocatableVLayout { } }
- private void adjustBreadcrumb(TreeNode node, ViewId viewId) { - if (node instanceof ResourceTreeNode) { - - Resource nr = ((ResourceTreeNode) node).getResource(); - String display = node.getName() + " <span class="subtitle">" + nr.getResourceType().getName() + "</span>"; - String icon = "types/" + nr.getResourceType().getCategory().getDisplayName() + "_up_16.png"; - - viewId.getBreadcrumbs().add(new Breadcrumb(node.getAttribute("id"), display, icon, true)); - - } else { - - // if (node.getName() != null) { - // viewId.getBreadcrumbs().add(new Breadcrumb(node.getAttribute("id"), node.getName(), null, true)); - // } - } - } - /*private List<Resource> preload(final List<Resource> lineage) {
final ArrayList<Resource> list = new ArrayList<Resource>(lineage); @@ -730,8 +729,9 @@ public class ResourceTreeView extends LocatableVLayout { currentViewId = viewPath.getCurrent(); String currentViewIdPath = currentViewId.getPath(); if ("AutoGroup".equals(currentViewIdPath)) { - ViewId nextViewId = viewPath.getNext(); - Integer autoGroupId = Integer.parseInt(nextViewId.getPath()); + // Move the currentViewId to the ID portion to play better with other code + currentViewId = viewPath.getNext(); + Integer autoGroupId = Integer.parseInt(currentViewId.getPath()); setSelectedAutoGroup(autoGroupId); } else { Integer resourceId = Integer.parseInt(currentViewId.getPath());
commit af349612d16eb487345a7bf9d9b2921c7854e475 Author: Jay Shaughnessy jshaughn@redhat.com Date: Fri Oct 1 09:57:45 2010 -0400
ResourceTree Authz work - support for locked nodes - support for autogroups for non-inventory managers. Now that AGs are backed by compat groups it's necessary for non-inv-managers to be able to create and access the private groups that they own. Private groups (aka subject-owned groups) are new, they are basically groups that are tagged with the creating subjectId. Those groups can be created (via a new slsb call) and fetched (via a new ResourceGroupCriteria filter) w/o inventory manager perms. - note: i had to move rhq_subject to auth-schema from authz-schema and slightly change the dbsetup order to make it ok for rhq_resource_group to reference rhq_subject. - schema spec bumped to 2.97 - added ResourceLineageComposite to combine Resource and locked/viewable info.
diff --git a/modules/core/dbutils/pom.xml b/modules/core/dbutils/pom.xml index 02aa606..4035ed5 100644 --- a/modules/core/dbutils/pom.xml +++ b/modules/core/dbutils/pom.xml @@ -22,7 +22,7 @@
<properties> <scm.module.path>modules/core/dbutils/</scm.module.path> - <db.schema.version>2.96</db.schema.version> + <db.schema.version>2.97</db.schema.version> </properties>
<dependencies> diff --git a/modules/core/dbutils/src/main/scripts/dbsetup-build.xml b/modules/core/dbutils/src/main/scripts/dbsetup-build.xml index f4993e5..b0ee520 100644 --- a/modules/core/dbutils/src/main/scripts/dbsetup-build.xml +++ b/modules/core/dbutils/src/main/scripts/dbsetup-build.xml @@ -39,7 +39,7 @@ To run the default target, you must set one of the following properties to true: <property name="dbsetup.scripts.dir" value="${basedir}/src/main/scripts/dbsetup" /> <property name="dbsetup.output.dir" value="${basedir}/target/dbsetup" /> <!-- away from classes so it doesn't go into the jar --> <!-- define the setup creation processing order. note, removals are done in the reverse order --> - <property name="dbsetup.subsystems" value="config,cluster,inventory,auth,authz,search,dashboard,operation,event,alert,sysconfig,scheduler,amps,measurement,content,resource-request,jms,obsolete"/> + <property name="dbsetup.subsystems" value="config,cluster,auth,inventory,authz,search,dashboard,operation,event,alert,sysconfig,scheduler,amps,measurement,content,resource-request,jms,obsolete"/> <property name="dbsetup.combined.schema" value="${dbsetup.output.dir}/all-schema.xml" /> <property name="dbsetup.combined.data" value="${dbsetup.output.dir}/all-data.xml" /> <property name="dbsetup.tstamp.file" value="${dbsetup.output.dir}/dbsetup-combine.tstamp" /> diff --git a/modules/core/dbutils/src/main/scripts/dbsetup/auth-schema.xml b/modules/core/dbutils/src/main/scripts/dbsetup/auth-schema.xml index d24b386..9b77256 100644 --- a/modules/core/dbutils/src/main/scripts/dbsetup/auth-schema.xml +++ b/modules/core/dbutils/src/main/scripts/dbsetup/auth-schema.xml @@ -16,5 +16,24 @@ </index>
</table> + + <table name="RHQ_SUBJECT"> + <column name="ID" default="sequence-only" initial="10001" + primarykey="true" required="true" type="INTEGER"/> + <column name="NAME" required="true" size="100" type="VARCHAR2"/> + <column name="CONFIGURATION_ID" type="INTEGER" references="RHQ_CONFIG"/> + <column name="FIRST_NAME" required="false" size="100" type="VARCHAR2"/> + <column name="LAST_NAME" required="false" size="100" type="VARCHAR2"/> + <column name="EMAIL_ADDRESS" size="100" type="VARCHAR2"/> + <column name="SMS_ADDRESS" size="100" type="VARCHAR2"/> + <column name="PHONE_NUMBER" size="100" type="VARCHAR2"/> + <column name="DEPARTMENT" size="100" type="VARCHAR2"/> + <column name="FACTIVE" required="true" type="BOOLEAN" default="true"/> + <column name="FSYSTEM" required="true" type="BOOLEAN" default="false"/> + + <index name="RHQ_SUBJECT_AUTH_KEY" unique="true"> + <field ref="NAME"/> + </index> + </table>
</dbsetup> diff --git a/modules/core/dbutils/src/main/scripts/dbsetup/authz-schema.xml b/modules/core/dbutils/src/main/scripts/dbsetup/authz-schema.xml index 8d9f738..b1385e9 100644 --- a/modules/core/dbutils/src/main/scripts/dbsetup/authz-schema.xml +++ b/modules/core/dbutils/src/main/scripts/dbsetup/authz-schema.xml @@ -50,25 +50,6 @@ </constraint> </table>
- <table name="RHQ_SUBJECT"> - <column name="ID" default="sequence-only" initial="10001" - primarykey="true" required="true" type="INTEGER"/> - <column name="NAME" required="true" size="100" type="VARCHAR2"/> - <column name="CONFIGURATION_ID" type="INTEGER" references="RHQ_CONFIG"/> - <column name="FIRST_NAME" required="false" size="100" type="VARCHAR2"/> - <column name="LAST_NAME" required="false" size="100" type="VARCHAR2"/> - <column name="EMAIL_ADDRESS" size="100" type="VARCHAR2"/> - <column name="SMS_ADDRESS" size="100" type="VARCHAR2"/> - <column name="PHONE_NUMBER" size="100" type="VARCHAR2"/> - <column name="DEPARTMENT" size="100" type="VARCHAR2"/> - <column name="FACTIVE" required="true" type="BOOLEAN" default="true"/> - <column name="FSYSTEM" required="true" type="BOOLEAN" default="false"/> - - <index name="RHQ_SUBJECT_AUTH_KEY" unique="true"> - <field ref="NAME"/> - </index> - </table> - <table name="RHQ_SUBJECT_ROLE_MAP"> <column name="SUBJECT_ID" required="true" type="INTEGER" references="RHQ_SUBJECT"/> <column name="ROLE_ID" required="true" type="INTEGER" references="RHQ_ROLE"/> diff --git a/modules/core/dbutils/src/main/scripts/dbsetup/inventory-schema.xml b/modules/core/dbutils/src/main/scripts/dbsetup/inventory-schema.xml index 6246880..5d89c2d 100644 --- a/modules/core/dbutils/src/main/scripts/dbsetup/inventory-schema.xml +++ b/modules/core/dbutils/src/main/scripts/dbsetup/inventory-schema.xml @@ -168,11 +168,14 @@
<column name="CATEGORY" type="VARCHAR2" size="20" required="true"/>
+ <!-- This is only set if this is a subject-owned group (like an autogroup) --> + <column name="SUBJECT_ID" type="INTEGER" references="RHQ_SUBJECT"/> + <!-- These two only set if this is a backing group for a resource auto-cluster --> <column name="CLUSTER_KEY" type="VARCHAR2" size="4000" required="false"/> <column name="CLUSTER_RESOURCE_GROUP_ID" type="INTEGER" references="RHQ_RESOURCE_GROUP"/>
- <!-- This only set if this is a backing group for a resource auto-group --> + <!-- This is only set if this is a backing group for a resource auto-group --> <column name="AUTO_GROUP_PARENT_RESOURCE_ID" type="INTEGER" references="RHQ_RESOURCE"/>
<column name="VISIBLE" type="BOOLEAN"/> diff --git a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml index f0940ab..b477b09 100644 --- a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml +++ b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml @@ -3226,9 +3226,21 @@ REFERENCES RHQ_RESOURCE (ID) </statement> </schema-directSQL> - </schemaSpec> - + + <schemaSpec version="2.97"> + <!-- Support subject-owned groups (e.g. autogroups) --> + <schema-addColumn table="RHQ_RESOURCE_GROUP" column="SUBJECT_ID" columnType="INTEGER" /> + <schema-directSQL> + <statement desc="Creating RHQ_RESOURCE_GROUP foreign key relation to RHQ_SUBJECT for owned groups"> + ALTER TABLE RHQ_RESOURCE_GROUP + ADD CONSTRAINT RHQ_RG_SUBJECT_ID_FK + FOREIGN KEY (SUBJECT_ID) + REFERENCES RHQ_SUBJECT (ID) + </statement> + </schema-directSQL> + </schemaSpec> + </dbupgrade> </target> </project> diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/auth/Subject.java b/modules/core/domain/src/main/java/org/rhq/core/domain/auth/Subject.java index 477a128..4a93c1f 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/auth/Subject.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/auth/Subject.java @@ -24,11 +24,13 @@ package org.rhq.core.domain.auth;
import java.io.Serializable; import java.util.HashSet; +import java.util.List; import java.util.Set;
import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @@ -37,6 +39,7 @@ import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; +import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.QueryHint; import javax.persistence.SequenceGenerator; @@ -47,6 +50,7 @@ import org.jetbrains.annotations.NotNull;
import org.rhq.core.domain.authz.Role; import org.rhq.core.domain.configuration.Configuration; +import org.rhq.core.domain.resource.group.ResourceGroup; import org.rhq.core.domain.util.Recordizable;
/** @@ -271,6 +275,10 @@ public class Subject implements Serializable, Recordizable { @ManyToMany private java.util.Set<Role> ldapRoles;
+ // When a subject is removed any owned groups should also be removed + @OneToMany(mappedBy = "subject", fetch = FetchType.LAZY) + private List<ResourceGroup> ownedGroups = null; + @Transient private Integer sessionId = null;
@@ -448,6 +456,14 @@ public class Subject implements Serializable, Recordizable { getLdapRoles().remove(role); }
+ public List<ResourceGroup> getOwnedGroups() { + return ownedGroups; + } + + public void setOwnedGroups(List<ResourceGroup> ownedGroups) { + this.ownedGroups = ownedGroups; + } + @Override public String toString() { return "org.rhq.core.domain.auth.Subject[id=" + id + ",name=" + name + "]"; diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/criteria/ResourceGroupCriteria.java b/modules/core/domain/src/main/java/org/rhq/core/domain/criteria/ResourceGroupCriteria.java index 2278c7f..835821a 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/criteria/ResourceGroupCriteria.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/criteria/ResourceGroupCriteria.java @@ -46,6 +46,7 @@ public class ResourceGroupCriteria extends TaggedCriteria { private Boolean filterRecursive; private Integer filterResourceTypeId; // requires overrides private String filterResourceTypeName; // requires overrides + private Integer filterSubjectId; // requires overrides private Integer filterAutoGroupParentResourceId; // requires overrides private String filterPluginName; // requires overrides private GroupCategory filterGroupCategory; @@ -56,6 +57,7 @@ public class ResourceGroupCriteria extends TaggedCriteria { private Integer filterExplicitResourceTypeId; // requires overrides private String filterExplicitResourceTypeName; // requires overrides private Integer filterGroupDefinitionId; // requires overrides + private Boolean filterPrivate; /* if true, show only private groups for the calling user */ private Boolean filterVisible = true; /* only show visible groups by default */
private boolean fetchExplicitResources; @@ -74,6 +76,7 @@ public class ResourceGroupCriteria extends TaggedCriteria { filterOverrides.put("resourceTypeId", "resourceType.id = ?"); filterOverrides.put("resourceTypeName", "resourceType.name like ?"); filterOverrides.put("autoGroupParentResourceId", "autoGroupParentResource.id = ?"); + filterOverrides.put("subjectId", "subject.id = ?"); filterOverrides.put("pluginName", "resourceType.plugin like ?"); filterOverrides.put("downMemberCount", "" // + "id IN ( SELECT implicitGroup.id " // @@ -148,6 +151,14 @@ public class ResourceGroupCriteria extends TaggedCriteria { this.filterResourceTypeName = filterResourceTypeName; }
+ /** + * Requires MANAGE_INVENTORY. Use addFilterPrivate(true) to filter on the caller's private groups. + * @param filterSubjectId. + */ + public void addFilterSubjectId(Integer filterSubjectId) { + this.filterSubjectId = filterSubjectId; + } + public void addFilterAutoGroupParentResourceId(Integer filterAutoGroupParentResourceId) { this.filterAutoGroupParentResourceId = filterAutoGroupParentResourceId; } @@ -199,6 +210,14 @@ public class ResourceGroupCriteria extends TaggedCriteria { this.filterGroupDefinitionId = filterGroupDefinitionId; }
+ public void addFilterPrivate(Boolean filterPrivate) { + this.filterPrivate = filterPrivate; + } + + public boolean isFilterPrivate() { + return (Boolean.TRUE.equals(this.filterPrivate)); + } + public void addFilterVisible(Boolean filterVisible) { this.filterVisible = filterVisible; } @@ -258,8 +277,8 @@ public class ResourceGroupCriteria extends TaggedCriteria {
@Override public boolean isInventoryManagerRequired() { - // presently only inventory managers can view/manage group definitions - return this.filterGroupDefinitionId != null; + // presently only inventory managers can view/manage group definitions or see other user's private groups + return this.filterGroupDefinitionId != null || this.filterSubjectId != null; }
} diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/ResourceLineageComposite.java b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/ResourceLineageComposite.java new file mode 100644 index 0000000..713a558 --- /dev/null +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/ResourceLineageComposite.java @@ -0,0 +1,51 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2010 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 as published by + * the Free Software Foundation version 2 of the License. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +package org.rhq.core.domain.resource.composite; + +import java.io.Serializable; + +import org.rhq.core.domain.resource.Resource; + +/** + * @author jay shaughnessy + */ +public class ResourceLineageComposite implements Serializable { + private static final long serialVersionUID = 1L; + + private Resource resource; + private boolean isLocked; + + // for gwt serialization + @SuppressWarnings("unused") + private ResourceLineageComposite() { + } + + public ResourceLineageComposite(Resource resource, boolean isLocked) { + this.resource = resource; + this.isLocked = isLocked; + } + + public Resource getResource() { + return resource; + } + + public boolean isLocked() { + return isLocked; + } +} \ No newline at end of file diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/group/ResourceGroup.java b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/group/ResourceGroup.java index 46d6bcb..5250c11 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/group/ResourceGroup.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/group/ResourceGroup.java @@ -55,6 +55,7 @@ import javax.xml.bind.annotation.XmlAccessorType; import org.jetbrains.annotations.NotNull;
import org.rhq.core.domain.alert.AlertDefinition; +import org.rhq.core.domain.auth.Subject; import org.rhq.core.domain.authz.Role; import org.rhq.core.domain.bundle.BundleDestination; import org.rhq.core.domain.configuration.group.AbstractGroupConfigurationUpdate; @@ -432,6 +433,12 @@ public class ResourceGroup extends Group { @ManyToOne private ResourceType resourceType; // if non-null, it implies a compatible group
+ // The group owner. Certain groups (like autogroups) are not associated with Roles. Instead, they + // are bound to specific owners. Subject-Owned groups defer to member-level authorization as needed. + @JoinColumn(name = "SUBJECT_ID", referencedColumnName = "ID", nullable = true) + @ManyToOne + private Subject subject = null; + @Column(name = "CLUSTER_KEY", nullable = true) private String clusterKey;
@@ -612,6 +619,25 @@ public class ResourceGroup extends Group { } }
+ public Subject getSubject() { + return subject; + } + + public void setSubject(Subject subject) { + if (this.id > 0 && null != this.subject) { + throw new IllegalStateException("The group owner can not be changed after the group is created."); + } + + this.subject = subject; + } + + /** + * @return true if this is a subject-owned group, private to the set subject + */ + public boolean isPrivateGroup() { + return (null != this.subject); + } + public String getClusterKey() { return clusterKey; } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/ResourceGWTService.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/ResourceGWTService.java index b282e41..7ad683a 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/ResourceGWTService.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/ResourceGWTService.java @@ -32,6 +32,7 @@ import org.rhq.core.domain.resource.composite.DisambiguationReport; import org.rhq.core.domain.resource.composite.ProblemResourceComposite; import org.rhq.core.domain.resource.composite.RecentlyAddedResourceComposite; import org.rhq.core.domain.resource.composite.ResourceComposite; +import org.rhq.core.domain.resource.composite.ResourceLineageComposite; import org.rhq.core.domain.util.PageControl; import org.rhq.core.domain.util.PageList;
@@ -44,9 +45,7 @@ public interface ResourceGWTService extends RemoteService {
PageList<ResourceComposite> findResourceCompositesByCriteria(ResourceCriteria criteria);
- List<Resource> getResourceLineage(int resourceId); - - List<Resource> getResourceLineageAndSiblings(int resourceId); + List<ResourceLineageComposite> getResourceLineageAndSiblings(int resourceId);
List<RecentlyAddedResourceComposite> findRecentlyAddedResources(long ctime, int maxItems);
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/ResourceGroupGWTService.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/ResourceGroupGWTService.java index d968e19..f48fd96 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/ResourceGroupGWTService.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/ResourceGroupGWTService.java @@ -37,6 +37,14 @@ public interface ResourceGroupGWTService extends RemoteService {
GroupDefinition createGroupDefinition(GroupDefinition groupDefinition);
+ /** + * The owner will be set to the session subject. + * @param group + * @param resourceIds initial members + * @return + */ + ResourceGroup createPrivateResourceGroup(ResourceGroup group, int[] resourceIds); + ResourceGroup createResourceGroup(ResourceGroup group, int[] resourceIds);
void deleteGroupDefinitions(int[] groupDefinitionIds); diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/AbstractTwoLevelTabSetView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/AbstractTwoLevelTabSetView.java index 50700f2..33b22e9 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/AbstractTwoLevelTabSetView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/AbstractTwoLevelTabSetView.java @@ -243,4 +243,9 @@ public abstract class AbstractTwoLevelTabSetView<T, U extends Layout> extends Lo public String getSubTabName() { return subTabName; } + + public String getBaseViewPath() { + return baseViewPath; + } + } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/ResourceGroupDetailView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/ResourceGroupDetailView.java index e5bfc72..90388fc 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/ResourceGroupDetailView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/ResourceGroupDetailView.java @@ -271,7 +271,12 @@ public class ResourceGroupDetailView extends AbstractTwoLevelTabSetView<Resource
ResourceGroupCriteria criteria = new ResourceGroupCriteria(); criteria.addFilterId(groupId); - criteria.addFilterVisible(null); + + // for autogroups we need to add more criteria + if (AUTO_GROUP_VIEW_PATH.equals(getBaseViewPath())) { + criteria.addFilterVisible(null); + criteria.addFilterPrivate(true); + }
GWTServiceLookup.getResourceGroupService().findResourceGroupCompositesByCriteria(criteria, new AsyncCallback<PageList<ResourceGroupComposite>>() { @@ -281,6 +286,11 @@ public class ResourceGroupDetailView extends AbstractTwoLevelTabSetView<Resource }
public void onSuccess(PageList<ResourceGroupComposite> result) { + if (result.isEmpty()) { + CoreGUI.getErrorHandler().handleError( + "Failed to load group composite for group with id " + groupId); + } + groupComposite = result.get(0); loadResourceType(groupComposite, viewPath, globalPermissions); } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/CustomResourceTreeGrid.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/CustomResourceTreeGrid.java index 71e6c61..f1dad07 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/CustomResourceTreeGrid.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/CustomResourceTreeGrid.java @@ -23,6 +23,7 @@ import com.smartgwt.client.widgets.tree.TreeNode;
import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.domain.resource.Resource; +import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.ResourceTreeDatasource.ResourceTreeNode; import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableTreeGrid;
/** @@ -40,15 +41,19 @@ public class CustomResourceTreeGrid extends LocatableTreeGrid { if (record instanceof TreeNode) { boolean open = getTree().isOpen((TreeNode) record);
- if (record instanceof ResourceTreeDatasource.ResourceTreeNode) { - Resource resource = ((ResourceTreeDatasource.ResourceTreeNode) record).getResource(); + if (record instanceof ResourceTreeNode) { + ResourceTreeNode node = (ResourceTreeNode) record;
- boolean up = resource.getCurrentAvailability().getAvailabilityType() == AvailabilityType.UP; + if (node.isLocked()) { + return "global/Locked_16.png";
- String category = resource.getResourceType().getCategory().getDisplayName(); - - return "types/" + category + "_" + (up ? "up" : "down") + "_16.png"; + } else { + Resource resource = ((ResourceTreeDatasource.ResourceTreeNode) record).getResource(); + String category = resource.getResourceType().getCategory().getDisplayName(); + boolean up = resource.getCurrentAvailability().getAvailabilityType() == AvailabilityType.UP;
+ return "types/" + category + "_" + (up ? "up" : "down") + "_16.png"; + } } else { return "resources/folder_group_" + (open ? "opened" : "closed") + ".png"; } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeDatasource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeDatasource.java index 3ad6835..5f9e07c 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeDatasource.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeDatasource.java @@ -30,7 +30,6 @@ import com.smartgwt.client.data.DSRequest; import com.smartgwt.client.data.DSResponse; import com.smartgwt.client.data.DataSource; import com.smartgwt.client.data.DataSourceField; -import com.smartgwt.client.data.fields.DataSourceImageField; import com.smartgwt.client.data.fields.DataSourceTextField; import com.smartgwt.client.rpc.RPCResponse; import com.smartgwt.client.types.DSDataFormat; @@ -38,8 +37,6 @@ import com.smartgwt.client.types.DSProtocol; import com.smartgwt.client.widgets.tree.TreeNode;
import org.rhq.core.domain.criteria.ResourceCriteria; -import org.rhq.core.domain.measurement.AvailabilityType; -import org.rhq.core.domain.measurement.ResourceAvailability; import org.rhq.core.domain.resource.Resource; import org.rhq.core.domain.resource.ResourceCategory; import org.rhq.core.domain.resource.ResourceSubCategory; @@ -61,15 +58,17 @@ import org.rhq.enterprise.gui.coregui.client.util.StringUtility; */ public class ResourceTreeDatasource extends DataSource { private List<Resource> initialData; + private List<Resource> lockedData;
private ResourceGWTServiceAsync resourceService = GWTServiceLookup.getResourceService();
- public ResourceTreeDatasource(List<Resource> initialData) { + public ResourceTreeDatasource(List<Resource> initialData, List<Resource> lockedData) { setClientOnly(false); setDataProtocol(DSProtocol.CLIENTCUSTOM); setDataFormat(DSDataFormat.CUSTOM);
this.initialData = initialData; + this.lockedData = (null != lockedData) ? lockedData : new ArrayList<Resource>();
DataSourceField idDataField = new DataSourceTextField("id", "ID"); idDataField.setPrimaryKey(true); @@ -80,22 +79,12 @@ public class ResourceTreeDatasource extends DataSource { DataSourceTextField descriptionDataField = new DataSourceTextField("description", "Description"); descriptionDataField.setCanEdit(false);
- DataSourceImageField availabilityDataField = new DataSourceImageField("currentAvailability", "Availability"); - descriptionDataField.setCanEdit(false); - DataSourceTextField parentIdField = new DataSourceTextField("parentId", "Parent ID"); parentIdField.setForeignKey("id"); - // parentIdField.setRootValue(rootId); - - // DataSourceTextField parentKeyField = new DataSourceTextField("parentKey", "Parent KEY"); - // parentKeyField.setForeignKey("id"); - // parentKeyField.setRootValue(rootId); - - // nameDataField.setType(FieldType.);
setDropExtraFields(false);
- setFields(idDataField, nameDataField, descriptionDataField, availabilityDataField); + setFields(idDataField, nameDataField, descriptionDataField); }
@Override @@ -127,7 +116,7 @@ public class ResourceTreeDatasource extends DataSource { }
public void executeFetch(final String requestId, final DSRequest request, final DSResponse response) { - final long start = System.currentTimeMillis(); + //final long start = System.currentTimeMillis();
String parentResourceId = request.getCriteria().getAttribute("parentId"); // System.out.println("All attributes: " + Arrays.toString(request.getCriteria().getAttributes())); @@ -173,7 +162,7 @@ public class ResourceTreeDatasource extends DataSource { ResourceTypeRepository.MetadataType.subCategory), new ResourceTypeRepository.ResourceTypeLoadedCallback() { public void onResourceTypeLoaded(List<Resource> result) { - TreeNode[] treeNodes = buildNodes(result); + TreeNode[] treeNodes = buildNodes(result, lockedData); response.setData(treeNodes); processResponse(requestId, response); response.setStatus(DSResponse.STATUS_SUCCESS); @@ -187,11 +176,11 @@ public class ResourceTreeDatasource extends DataSource { * @param resources * @return */ - public static TreeNode[] buildNodes(List<Resource> resources) { + public static TreeNode[] buildNodes(List<Resource> resources, List<Resource> lockedData) { ResourceTreeNode[] nodes = new ResourceTreeNode[resources.size()]; for (int i = 0; i < resources.size(); i++) { Resource resource = resources.get(i); - ResourceTreeNode node = new ResourceTreeNode(resource); + ResourceTreeNode node = new ResourceTreeNode(resource, lockedData.contains(resource)); nodes[i] = node; }
@@ -350,9 +339,11 @@ public class ResourceTreeDatasource extends DataSource {
public static class ResourceTreeNode extends EnhancedTreeNode { private Resource resource; + private boolean isLocked;
- private ResourceTreeNode(Resource resource) { + private ResourceTreeNode(Resource resource, boolean isLocked) { this.resource = resource; + this.isLocked = isLocked;
String id = idOf(resource); setID(id); @@ -369,21 +360,12 @@ public class ResourceTreeDatasource extends DataSource { setParentID(parentId); setAttribute(Attributes.PARENT_ID, parentId);
- // System.out.println(id + " / " + parentId); - // setAttribute("parentKey", resource.getParentResource() == null ? 0 : (resource.getParentResource().getId() + resource.getResourceType().getName())); - String name = resource.getName(); setName(name); setAttribute(Attributes.NAME, name);
setAttribute(Attributes.DESCRIPTION, resource.getDescription());
- ResourceAvailability currentAvail = resource.getCurrentAvailability(); - setAttribute( - "currentAvailability", - (null != currentAvail && currentAvail.getAvailabilityType() == AvailabilityType.UP) ? "/images/icons/availability_green_16.png" - : "/images/icons/availability_red_16.png"); - Set<ResourceType> childTypes = resource.getResourceType().getChildResourceTypes(); setIsFolder((childTypes != null && !childTypes.isEmpty())); } @@ -392,6 +374,10 @@ public class ResourceTreeDatasource extends DataSource { return this.resource; }
+ public boolean isLocked() { + return isLocked; + } + public static String idOf(Resource resource) { return idOf(resource.getId()); } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java index 0d16bea..4cea21b 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java @@ -63,6 +63,7 @@ import org.rhq.core.domain.operation.OperationDefinition; import org.rhq.core.domain.resource.Resource; import org.rhq.core.domain.resource.ResourceCategory; import org.rhq.core.domain.resource.ResourceType; +import org.rhq.core.domain.resource.composite.ResourceLineageComposite; import org.rhq.core.domain.resource.group.ResourceGroup; import org.rhq.core.domain.util.PageList; import org.rhq.enterprise.gui.coregui.client.Breadcrumb; @@ -142,14 +143,20 @@ public class ResourceTreeView extends LocatableVLayout { if (!selectionEvent.isRightButtonDown() && selectionEvent.getState()) { ListGridRecord selectedRecord = treeGrid.getSelectedRecord(); if (selectedRecord instanceof ResourceTreeNode) { - System.out.println("AutoGroup Node selected in tree: " + selectedRecord); - ResourceTreeNode resourceNode = (ResourceTreeNode) selectedRecord; - selectedNodeId = resourceNode.getID(); - String viewPath = "Resource/" + resourceNode.getResource().getId(); - String currentViewPath = History.getToken(); - if (!currentViewPath.startsWith(viewPath)) { - CoreGUI.goToView(viewPath); + + if (!resourceNode.isLocked()) { + System.out.println("Resource Node selected in tree: " + selectedRecord); + + selectedNodeId = resourceNode.getID(); + String viewPath = "Resource/" + resourceNode.getResource().getId(); + String currentViewPath = History.getToken(); + if (!currentViewPath.startsWith(viewPath)) { + CoreGUI.goToView(viewPath); + } + } else { + // TODO: Can we select the previous node? Or do we need a "Locked" hover etc... + treeGrid.deselectAllRecords(); } } else if (selectedRecord instanceof AutoGroupTreeNode) { System.out.println("AutoGroup Node selected in tree: " + selectedRecord); @@ -183,7 +190,9 @@ public class ResourceTreeView extends LocatableVLayout { if (event.getNode() instanceof AutoGroupTreeNode) { showContextMenu((AutoGroupTreeNode) event.getNode()); } else if (event.getNode() instanceof ResourceTreeNode) { - showContextMenu((ResourceTreeNode) event.getNode()); + if (!((ResourceTreeNode) event.getNode()).isLocked()) { + showContextMenu((ResourceTreeNode) event.getNode()); + } } } }); @@ -207,6 +216,7 @@ public class ResourceTreeView extends LocatableVLayout {
// get the backing group if it exists, otherwise create the group ResourceGroupCriteria criteria = new ResourceGroupCriteria(); + criteria.addFilterPrivate(true); criteria.addFilterResourceTypeId(agNode.getResourceType().getId()); criteria.addFilterAutoGroupParentResourceId(agNode.getParentResource().getId()); criteria.addFilterVisible(false); @@ -224,8 +234,7 @@ public class ResourceTreeView extends LocatableVLayout { backingGroup.setAutoGroupParentResource(agNode.getParentResource()); backingGroup.setResourceType(agNode.getResourceType()); backingGroup.setVisible(false); - backingGroup.setRecursive(false); - resourceGroupService.createResourceGroup(backingGroup, childIds, + resourceGroupService.createPrivateResourceGroup(backingGroup, childIds, new AsyncCallback<ResourceGroup>() { public void onFailure(Throwable caught) { CoreGUI.getErrorHandler().handleError("Failed to create resource autogroup", caught); @@ -596,65 +605,79 @@ public class ResourceTreeView extends LocatableVLayout { selectedNodeId = ResourceTreeNode.idOf(selectedResourceId);
final ResourceGWTServiceAsync resourceService = GWTServiceLookup.getResourceService(); - // This is an expensive call, but loads all nodes that are visible in the tree given a selected resource - resourceService.getResourceLineageAndSiblings(selectedResourceId, new AsyncCallback<List<Resource>>() { - public void onFailure(Throwable caught) { - CoreGUI.getErrorHandler().handleError("Failed to lookup platform for tree", caught); - }
- public void onSuccess(List<Resource> result) { - Resource root = result.get(0); + // This is an expensive call, but loads all nodes that are visible in the tree given a selected resource + resourceService.getResourceLineageAndSiblings(selectedResourceId, + new AsyncCallback<List<ResourceLineageComposite>>() {
- if (!root.equals(ResourceTreeView.this.rootResource)) { + public void onFailure(Throwable caught) { + CoreGUI.getErrorHandler().handleError("Failed to lookup platform for tree", caught); + }
- if (treeGrid != null) { - treeGrid.destroy(); - } - buildTree(); + public void onSuccess(List<ResourceLineageComposite> result) { + Resource root = result.get(0).getResource();
- setRootResource(root); + final List<Resource> lineage = new ArrayList<Resource>(result.size()); + final List<Resource> lockedData = new ArrayList<Resource>();
- // seed datasource with initial resource list - ResourceTreeDatasource dataSource = new ResourceTreeDatasource(result); - treeGrid.setDataSource(dataSource); + for (ResourceLineageComposite r : result) { + lineage.add(r.getResource()); + if (r.isLocked()) { + lockedData.add(r.getResource()); + } + }
- addMember(treeGrid); + if (!root.equals(ResourceTreeView.this.rootResource)) {
- treeGrid.fetchData(treeGrid.getCriteria(), new DSCallback() { - public void execute(DSResponse response, Object rawData, DSRequest request) { - System.out.println("Done fetching data for tree."); - updateSelection(); + if (treeGrid != null) { + treeGrid.destroy(); } - }); + buildTree();
- updateSelection(); + setRootResource(root);
- } else { - ResourceTypeRepository.Cache.getInstance().loadResourceTypes( - result, - EnumSet.of(ResourceTypeRepository.MetadataType.operations, - ResourceTypeRepository.MetadataType.children, - ResourceTypeRepository.MetadataType.subCategory), - new ResourceTypeRepository.ResourceTypeLoadedCallback() { - public void onResourceTypeLoaded(List<Resource> result) { - treeGrid.getTree().linkNodes(ResourceTreeDatasource.buildNodes(result)); - - TreeNode selectedNode = treeGrid.getTree().findById(selectedNodeId); - if (selectedNode != null) { - updateSelection(); - - } else { - CoreGUI.getMessageCenter().notify( - new Message("Failed to select Resource [" + selectedResourceId + "] in tree.", - Message.Severity.Warning)); - } + // seed datasource with initial resource list and which ancestor resources are locked + ResourceTreeDatasource dataSource = new ResourceTreeDatasource(lineage, lockedData); + treeGrid.setDataSource(dataSource);
+ addMember(treeGrid); + + treeGrid.fetchData(treeGrid.getCriteria(), new DSCallback() { + public void execute(DSResponse response, Object rawData, DSRequest request) { + System.out.println("Done fetching data for tree."); + updateSelection(); } });
+ updateSelection(); + + } else { + ResourceTypeRepository.Cache.getInstance().loadResourceTypes( + lineage, + EnumSet.of(ResourceTypeRepository.MetadataType.operations, + ResourceTypeRepository.MetadataType.children, + ResourceTypeRepository.MetadataType.subCategory), + new ResourceTypeRepository.ResourceTypeLoadedCallback() { + public void onResourceTypeLoaded(List<Resource> result) { + treeGrid.getTree() + .linkNodes(ResourceTreeDatasource.buildNodes(lineage, lockedData)); + + TreeNode selectedNode = treeGrid.getTree().findById(selectedNodeId); + if (selectedNode != null) { + updateSelection(); + + } else { + CoreGUI.getMessageCenter().notify( + new Message("Failed to select Resource [" + selectedResourceId + + "] in tree.", Message.Severity.Warning)); + } + + } + }); + + } } - } - }); + }); }
public void setSelectedAutoGroup(final Integer selectedAutoGroupId) { diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/ResourceGWTServiceImpl.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/ResourceGWTServiceImpl.java index 66a25be..2e2f6d6 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/ResourceGWTServiceImpl.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/ResourceGWTServiceImpl.java @@ -39,6 +39,7 @@ import org.rhq.core.domain.resource.composite.DisambiguationReport; import org.rhq.core.domain.resource.composite.ProblemResourceComposite; import org.rhq.core.domain.resource.composite.RecentlyAddedResourceComposite; import org.rhq.core.domain.resource.composite.ResourceComposite; +import org.rhq.core.domain.resource.composite.ResourceLineageComposite; import org.rhq.core.domain.util.PageControl; import org.rhq.core.domain.util.PageList; import org.rhq.core.util.IntExtractor; @@ -167,13 +168,8 @@ public class ResourceGWTServiceImpl extends AbstractGWTServiceImpl implements Re } };
- public List<Resource> getResourceLineage(int resourceId) { - return SerialUtility.prepare(resourceManager.getResourceLineage(resourceId), - "ResourceService.getResourceLineage"); - } - - public List<Resource> getResourceLineageAndSiblings(int resourceId) { - return SerialUtility.prepare(resourceManager.getResourceLineageAndSiblings(resourceId), + public List<ResourceLineageComposite> getResourceLineageAndSiblings(int resourceId) { + return SerialUtility.prepare(resourceManager.getResourceLineageAndSiblings(getSessionSubject(), resourceId), "ResourceService.getResourceLineageAndSiblings"); }
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/ResourceGroupGWTServiceImpl.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/ResourceGroupGWTServiceImpl.java index 1ddecc3..2015091 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/ResourceGroupGWTServiceImpl.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/ResourceGroupGWTServiceImpl.java @@ -87,6 +87,17 @@ public class ResourceGroupGWTServiceImpl extends AbstractGWTServiceImpl implemen } }
+ public ResourceGroup createPrivateResourceGroup(ResourceGroup group, int[] resourceIds) { + try { + Subject user = getSessionSubject(); + group = groupManager.createPrivateResourceGroup(user, group); + groupManager.setAssignedResources(user, group.getId(), resourceIds, true); + return SerialUtility.prepare(group, "ResourceGroupService.createResourceGroup"); + } catch (Throwable t) { + throw new RuntimeException(ThrowableUtil.getAllMessages(t)); + } + } + public ResourceGroup createResourceGroup(ResourceGroup group, int[] resourceIds) { try { Subject user = getSessionSubject(); diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SubjectManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SubjectManagerBean.java index 4e1a53d..37ec2c9 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SubjectManagerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SubjectManagerBean.java @@ -48,6 +48,7 @@ import org.rhq.core.domain.authz.Permission; import org.rhq.core.domain.authz.Role; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.criteria.SubjectCriteria; +import org.rhq.core.domain.resource.group.ResourceGroup; import org.rhq.core.domain.util.PageControl; import org.rhq.core.domain.util.PageList; import org.rhq.core.server.PersistenceUtility; @@ -58,6 +59,7 @@ import org.rhq.enterprise.server.authz.PermissionException; import org.rhq.enterprise.server.authz.RequiredPermission; import org.rhq.enterprise.server.core.CustomJaasDeploymentServiceMBean; import org.rhq.enterprise.server.exception.LoginException; +import org.rhq.enterprise.server.resource.group.ResourceGroupManagerLocal; import org.rhq.enterprise.server.system.SystemManagerLocal; import org.rhq.enterprise.server.util.CriteriaQueryGenerator; import org.rhq.enterprise.server.util.CriteriaQueryRunner; @@ -69,7 +71,6 @@ import org.rhq.enterprise.server.util.CriteriaQueryRunner; */ @Stateless public class SubjectManagerBean implements SubjectManagerLocal, SubjectManagerRemote { - @SuppressWarnings("unused") private final Log log = LogFactory.getLog(SubjectManagerBean.class);
@PersistenceContext(unitName = RHQConstants.PERSISTENCE_UNIT_NAME) @@ -79,6 +80,10 @@ public class SubjectManagerBean implements SubjectManagerLocal, SubjectManagerRe private AuthorizationManagerLocal authorizationManager;
@EJB + @IgnoreDependency + private ResourceGroupManagerLocal resourceGroupManager; + + @EJB private SystemManagerLocal systemManager;
@EJB @@ -508,6 +513,25 @@ public class SubjectManagerBean implements SubjectManagerLocal, SubjectManagerRe deletePrincipal(subject, doomedSubject); }
+ // one more thing, delete any owned groups + List<ResourceGroup> ownedGroups = doomedSubject.getOwnedGroups(); + if (!ownedGroups.isEmpty()) { + int size = ownedGroups.size(); + int[] ownedGroupIds = new int[size]; + for (int i = 0; (i < size); ++i) { + ownedGroupIds[i] = ownedGroups.get(i).getId(); + } + try { + resourceGroupManager.deleteResourceGroups(subject, ownedGroupIds); + } catch (Throwable t) { + if (log.isDebugEnabled()) { + log.error("Error deleting owned group " + ownedGroupIds, t); + } else { + log.error("Error deleting owned group " + ownedGroupIds + ": " + t.getMessage()); + } + } + } + deleteSubject(subject, doomedSubject); }
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/authz/AuthorizationManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/authz/AuthorizationManagerBean.java index d675177..1a14a56 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/authz/AuthorizationManagerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/authz/AuthorizationManagerBean.java @@ -18,6 +18,7 @@ */ package org.rhq.enterprise.server.authz;
+import java.util.ArrayList; import java.util.Collection; import java.util.EnumSet; import java.util.List; @@ -32,6 +33,8 @@ import javax.persistence.Query; import org.rhq.core.domain.auth.Subject; import org.rhq.core.domain.authz.Permission; import org.rhq.core.domain.authz.Permission.Target; +import org.rhq.core.domain.resource.Resource; +import org.rhq.core.domain.resource.group.ResourceGroup; import org.rhq.enterprise.server.RHQConstants;
/** @@ -117,12 +120,33 @@ public class AuthorizationManagerBean implements AuthorizationManagerLocal { return true; }
- Query query = entityManager.createNamedQuery(Subject.QUERY_HAS_GROUP_PERMISSION); - query.setParameter("subject", subject); - query.setParameter("permission", permission); - query.setParameter("groupId", groupId); - long count = (Long) query.getSingleResult(); - return (count != 0); + ResourceGroup group = entityManager.find(ResourceGroup.class, groupId); + Subject owner = group.getSubject(); + + if (null == owner) { + // role-owned group + Query query = entityManager.createNamedQuery(Subject.QUERY_HAS_GROUP_PERMISSION); + query.setParameter("subject", subject); + query.setParameter("permission", permission); + query.setParameter("groupId", groupId); + long count = (Long) query.getSingleResult(); + return (count != 0); + + } else { + // don't let a user other than the owner do anything with this group + if (!subject.equals(owner)) { + return false; + } + + // subject-owned group, requires perm check against each group member + Set<Resource> members = group.getExplicitResources(); + List<Integer> memberIds = new ArrayList<Integer>(members.size()); + for (Resource member : members) { + memberIds.add(member.getId()); + } + + return hasResourcePermission(owner, permission, memberIds); + } }
public boolean hasResourcePermission(Subject subject, Permission permission, int resourceId) { 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 0528b06..bf213c0 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 @@ -94,6 +94,7 @@ import org.rhq.core.domain.resource.composite.ResourceComposite; import org.rhq.core.domain.resource.composite.ResourceHealthComposite; import org.rhq.core.domain.resource.composite.ResourceIdFlyWeight; import org.rhq.core.domain.resource.composite.ResourceInstallCount; +import org.rhq.core.domain.resource.composite.ResourceLineageComposite; import org.rhq.core.domain.resource.composite.ResourcePermission; import org.rhq.core.domain.resource.composite.ResourceWithAvailability; import org.rhq.core.domain.resource.flyweight.FlyweightCache; @@ -721,27 +722,68 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage return resourceLineage; }
- public List<Resource> getResourceLineageAndSiblings(int resourceId) { - List<Resource> resourceLineage = getResourceLineage(resourceId); - List<Resource> result = new LinkedList<Resource>(); + public List<ResourceLineageComposite> getResourceLineageAndSiblings(Subject subject, int resourceId) { + boolean isInventoryManager = authorizationManager.isInventoryManager(subject);
- Resource platform = resourceLineage.get(0); - result.add(platform); - for (Resource resource : resourceLineage) { - if (resource.getParentResource() != null) { - // This ensures Hibernate actually fetches the parent Resource. - resource.getParentResource().getId(); - } - Set<Resource> childResources = resource.getChildResources(); - result.addAll(childResources); - for (Resource childResource : childResources) { - // This ensures Hibernate actually fetches the parent Resource. - childResource.getParentResource().getId(); - Set<Resource> grandchildResources = childResource.getChildResources(); - result.addAll(grandchildResources); - for (Resource grandchildResource : grandchildResources) { + // get the raw resource lineage up to the platform. We'll check the auth below + List<Resource> rawResourceLineage = getResourceLineage(resourceId); + int depth = rawResourceLineage.size(); + Resource parent = (depth > 1) ? rawResourceLineage.get(depth - 2) : null; + + // record which of the raw ancestry is locked from view + List<ResourceLineageComposite> resourceLineage = new ArrayList<ResourceLineageComposite>(rawResourceLineage + .size()); + for (Resource resource : rawResourceLineage) { + resourceLineage.add(new ResourceLineageComposite(resource, !authorizationManager.canViewResource(subject, + resource.getId()))); + } + + // fill out the tree, including only the direct ancestors and all viewable relations + List<ResourceLineageComposite> result = new LinkedList<ResourceLineageComposite>(); + + for (ResourceLineageComposite ancestor : resourceLineage) { + // always include a direct ancestor + result.add(ancestor); + + // if the ancestor is not locked, include relevant children. Also, always show viewable + // siblings of the target resource. + if (!ancestor.isLocked() || ancestor.getResource() == parent) { + + // get children + Set<Resource> children = ancestor.getResource().getChildResources(); + // only add the viewable children + List<Resource> viewableChildren = new ArrayList<Resource>(children.size()); + for (Resource child : children) { + boolean isCommitted = (child.getInventoryStatus() == InventoryStatus.COMMITTED); + boolean isViewable = (isInventoryManager || authorizationManager.canViewResource(subject, child + .getId())); + if (isCommitted && isViewable) { + // if not a direct ancestor add to the list (direct ancestors already added by default) + if (!rawResourceLineage.contains(child)) { + child.getParentResource().getId(); + result.add(new ResourceLineageComposite(child, false)); + } + viewableChildren.add(child); + } + } + + // get grandchildren + for (Resource child : viewableChildren) { // This ensures Hibernate actually fetches the parent Resource. - grandchildResource.getParentResource().getId(); + child.getParentResource().getId(); + Set<Resource> grandChildren = child.getChildResources(); + for (Resource grandChild : grandChildren) { + boolean isCommitted = (grandChild.getInventoryStatus() == InventoryStatus.COMMITTED); + boolean isViewable = (isInventoryManager || authorizationManager.canViewResource(subject, + grandChild.getId())); + if (isCommitted && isViewable) { + // if not a direct ancestor add to the list (direct ancestors already added by default) + if (!rawResourceLineage.contains(grandChild)) { + grandChild.getParentResource().getId(); + result.add(new ResourceLineageComposite(grandChild, false)); + } + } + } } } } 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 78ece78..6f2ae41 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 @@ -43,6 +43,7 @@ import org.rhq.core.domain.resource.composite.ResourceComposite; import org.rhq.core.domain.resource.composite.ResourceHealthComposite; import org.rhq.core.domain.resource.composite.ResourceIdFlyWeight; import org.rhq.core.domain.resource.composite.ResourceInstallCount; +import org.rhq.core.domain.resource.composite.ResourceLineageComposite; import org.rhq.core.domain.resource.composite.ResourceWithAvailability; import org.rhq.core.domain.resource.flyweight.ResourceFlyweight; import org.rhq.core.domain.resource.group.ResourceGroup; @@ -156,11 +157,13 @@ public interface ResourceManagerLocal {
/** * Returns the lineage of a resource plus all the siblings of the resources in the lineage. This is - * useful for prepopulating all the resources visible in an expanded tree. + * useful for prepopulating all the resources visible in an expanded tree. Composites are returned + * that indicate whether the resource is viewable or should be locked in the tree. + * * @param resourceId id of resource - * @return resoure lineage and siblings + * @return resource lineage and siblings */ - List<Resource> getResourceLineageAndSiblings(int resourceId); + List<ResourceLineageComposite> getResourceLineageAndSiblings(Subject subject, int resourceId);
/** * Looks up the root of a subtree in the inventory. This will generally find the platform on which diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/group/ResourceGroupManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/group/ResourceGroupManagerBean.java index 0e7500f..f75d32d 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/group/ResourceGroupManagerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/group/ResourceGroupManagerBean.java @@ -146,6 +146,15 @@ public class ResourceGroupManagerBean implements ResourceGroupManagerLocal, Reso } }
+ public ResourceGroup createPrivateResourceGroup(Subject subject, // + @XmlJavaTypeAdapter(ResourceGroupAdapter.class) ResourceGroup group) { + + group.setSubject(subject); + group.setRecursive(false); + + return resourceGroupManager.createResourceGroup(subjectManager.getOverlord(), group); + } + @RequiredPermission(Permission.MANAGE_INVENTORY) public ResourceGroup createResourceGroup(Subject user, // @XmlJavaTypeAdapter(ResourceGroupAdapter.class) ResourceGroup group) { @@ -1017,8 +1026,9 @@ public class ResourceGroupManagerBean implements ResourceGroupManagerLocal, Reso */ public PageList<ResourceGroupComposite> findResourceGroupCompositesByCriteria(Subject subject, ResourceGroupCriteria criteria) { - CriteriaQueryGenerator generator = new CriteriaQueryGenerator(subject, criteria); - ; + + CriteriaQueryGenerator generator = getCriteriaQueryGenerator(subject, criteria); + String replacementSelectList = "" + " new org.rhq.core.domain.resource.group.composite.ResourceGroupComposite( " + " ( SELECT COUNT(avail) FROM resourcegroup.explicitResources res JOIN res.currentAvailability avail ) AS explicitCount," @@ -1028,17 +1038,6 @@ public class ResourceGroupManagerBean implements ResourceGroupManagerLocal, Reso + " resourcegroup ) "; generator.alterProjection(replacementSelectList);
- if (criteria.isSecurityManagerRequired() - && !authorizationManager.hasGlobalPermission(subject, Permission.MANAGE_SECURITY)) { - throw new PermissionException("Subject [" + subject.getName() - + "] requires SecurityManager permission for requested query criteria."); - } - - if (authorizationManager.isInventoryManager(subject) == false) { - generator.setAuthorizationResourceFragment(CriteriaQueryGenerator.AuthorizationTokenType.GROUP, null, - subject.getId()); - } - CriteriaQueryRunner<ResourceGroupComposite> queryRunner = new CriteriaQueryRunner<ResourceGroupComposite>( criteria, generator, entityManager); PageList<ResourceGroupComposite> results = queryRunner.execute(); @@ -1299,18 +1298,35 @@ public class ResourceGroupManagerBean implements ResourceGroupManagerLocal, Reso public void setAssignedResources(Subject subject, int groupId, int[] resourceIds, boolean setType) throws ResourceGroupDeleteException {
+ ResourceGroup group = entityManager.find(ResourceGroup.class, groupId); + if (group.isPrivateGroup()) { + List<Integer> ids = new ArrayList<Integer>(resourceIds.length); + for (int id : resourceIds) { + ids.add(id); + } + if (!authorizationManager.canViewResources(subject, ids)) { + throw new PermissionException("Subject [" + subject.getName() + + "] does not have VIEW permission for all specified resources."); + } + } else { + if (!authorizationManager.isInventoryManager(subject)) { + throw new PermissionException("Subject [" + subject.getName() + + "] is not authorized for [ MANAGE_INVENTORY ]. Required for changing group membership "); + } + } + List<Integer> currentMembers = resourceManager.findExplicitResourceIdsByResourceGroup(groupId);
List<Integer> newMembers = ArrayUtils.wrapInList(resourceIds); // members needing addition newMembers.removeAll(currentMembers); if (newMembers.size() > 0) { - addResourcesToGroup(subject, groupId, ArrayUtils.unwrapCollection(newMembers)); + addResourcesToGroup(subjectManager.getOverlord(), groupId, ArrayUtils.unwrapCollection(newMembers)); }
List<Integer> extraMembers = new ArrayList<Integer>(currentMembers); // members needing removal extraMembers.removeAll(ArrayUtils.wrapInList(resourceIds)); if (extraMembers.size() > 0) { - removeResourcesFromGroup(subject, groupId, ArrayUtils.unwrapCollection(extraMembers)); + removeResourcesFromGroup(subjectManager.getOverlord(), groupId, ArrayUtils.unwrapCollection(extraMembers)); }
// As a result of the membership change ensure that the group type is set correctly. @@ -1461,28 +1477,45 @@ public class ResourceGroupManagerBean implements ResourceGroupManagerLocal, Reso
@SuppressWarnings("unchecked") public PageList<ResourceGroup> findResourceGroupsByCriteria(Subject subject, ResourceGroupCriteria criteria) { - CriteriaQueryGenerator generator = new CriteriaQueryGenerator(subject, criteria); - ;
+ CriteriaQueryGenerator generator = getCriteriaQueryGenerator(subject, criteria); + + CriteriaQueryRunner<ResourceGroup> queryRunner = new CriteriaQueryRunner(criteria, generator, entityManager); + PageList<ResourceGroup> result = queryRunner.execute(); + return result; + } + + private CriteriaQueryGenerator getCriteriaQueryGenerator(Subject subject, ResourceGroupCriteria criteria) { if (criteria.isSecurityManagerRequired() && !authorizationManager.hasGlobalPermission(subject, Permission.MANAGE_SECURITY)) { throw new PermissionException("Subject [" + subject.getName() + "] requires SecurityManager permission for requested query criteria."); }
- if (criteria.isInventoryManagerRequired() - && !authorizationManager.hasGlobalPermission(subject, Permission.MANAGE_INVENTORY)) { + boolean isInventoryManager = authorizationManager.isInventoryManager(subject); + boolean groupAuthzRequired = (!(criteria.isFilterPrivate() || isInventoryManager)); + + if (criteria.isInventoryManagerRequired() && !isInventoryManager) { throw new PermissionException("Subject [" + subject.getName() + "] requires InventoryManager permission for requested query criteria."); }
- if (authorizationManager.isInventoryManager(subject) == false) { + // if we're searching for private groups set the subject filter to the current user's subjectId + // setting it here prevents the caller from spoofing a different user. This is why the subject and + // private filters are different. The suject filter can specifiy any use and therefore requires + // inventory manager. + if (criteria.isFilterPrivate()) { + criteria.addFilterPrivate(null); + criteria.addFilterSubjectId(subject.getId()); + } + + CriteriaQueryGenerator generator = new CriteriaQueryGenerator(subject, criteria); + if (groupAuthzRequired) { generator.setAuthorizationResourceFragment(CriteriaQueryGenerator.AuthorizationTokenType.GROUP, null, subject.getId()); }
- CriteriaQueryRunner<ResourceGroup> queryRunner = new CriteriaQueryRunner(criteria, generator, entityManager); - return queryRunner.execute(); + return generator; }
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/group/ResourceGroupManagerLocal.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/group/ResourceGroupManagerLocal.java index de96dbf..a0481b1 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/group/ResourceGroupManagerLocal.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/group/ResourceGroupManagerLocal.java @@ -42,6 +42,28 @@ import org.rhq.core.domain.util.PageList; @Local public interface ResourceGroupManagerLocal {
+ /** + * NOTE: This is only used to support AutoGroups currently but the idea may be expanded in the future. + * + * Creates a private, "user-owned" (aka "subject-owned") resource group. This group differs from a role-owned + * group in that it can not be assigned to a role, instead it is owned by the user that creates it. It comprises + * only a set of resources for which the user has, minimally, view permission. Since a user's view permissions + * can change, membership and authz checking must be performed as needed when taking any action on the group. + * <br/><br/> + * A user does not need MANAGE_INVENTORY to create a sub-group because it is private to his view. + * <br/><br/> + * This call does not populate the group with members, it only creates the group. The group is automatically set + * to be non-recursive. + * <br/><br/> + * All user-owned groups are deleted if the the user is deleted. + * + * @param user The user for which the group will be created. + * @param group The group characteristics. Any membership defined here is ignored. The recursivity setting is + * ignored. + * @return The new group. + */ + ResourceGroup createPrivateResourceGroup(Subject user, ResourceGroup group); + ResourceGroup getResourceGroupById(Subject user, int id, GroupCategory category) throws ResourceGroupNotFoundException;
@@ -108,7 +130,10 @@ public interface ResourceGroupManagerLocal { /** * This method ensures that the explicit group membership is set to the specified resources. Members * will be added or removed as necessary. Make sure you pass the correct value for the <setType> - * parameter. + * parameter. + * <br/><br/> + * For global groups requires MANAGE_INVENTORY. For private groups requires VIEW permission on all specified + * resources. * * @param subject * @param groupId
commit 400635fb9e3cf30ac7d55d98330e4ad4e5c120b9 Merge: 1d94af7... 64abb7e... Author: Jay Shaughnessy jshaughn@redhat.com Date: Tue Sep 28 12:45:20 2010 -0400
Merge branch 'master' into master-jay
commit 1d94af7604a60412da8017e721ef0bb36504d8fd Author: Jay Shaughnessy jshaughn@redhat.com Date: Tue Sep 28 12:35:44 2010 -0400
AutoGroup/ResourceTree work - Fix up breadcrumbs for AutoGroup selections and also fix up some path - issues that were happening when selecting AG resources.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/CoreGUI.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/CoreGUI.java index b59edba..7c895e0 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/CoreGUI.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/CoreGUI.java @@ -339,10 +339,13 @@ public class CoreGUI implements EntryPoint, ValueChangeHandler<String> { if (viewPath.matches("(Resource|ResourceGroup)/[^/]*")) { // e.g. "Resource/10001" if (!currentViewPath.startsWith(viewPath)) { - // The Resource that was selected is not the same Resource that was previously selected - - // grab the end portion of the previous history URL and append it to the new history URL, - // so the same tab is selected for the new Resource. - String suffix = currentViewPath.replaceFirst("^[^/]*/[^/]*", ""); + // The Node that was selected is not the same Node that was previously selected - it + // may not even be the same node type. For example, the user could have moved from a + // resource to an autogroup in the same tree. Try to keep the tab selection sticky as best as + // possible while moving from one view to another by grabbing the end portion of the previous + // history URL and append it to the new history URL. The suffix is assumed to follow the + // ID (numeric) portion of the currentViewPath. + String suffix = currentViewPath.replaceFirst("\D*[^/]*", ""); viewPath += suffix; } } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java index 6a7cba9..0d16bea 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java @@ -236,7 +236,6 @@ public class ResourceTreeView extends LocatableVLayout { // get back to this node given the id of the backing group (from the viewpath) autoGroupNodeMap.put(result.getId(), agNode); callback.onSuccess(result); - //renderAutoGroup(result); } }); } else { @@ -302,6 +301,23 @@ public class ResourceTreeView extends LocatableVLayout { } }
+ private void adjustBreadcrumb(TreeNode node, ViewId viewId) { + if (node instanceof ResourceTreeNode) { + Resource nr = ((ResourceTreeNode) node).getResource(); + String display = node.getName() + " <span class="subtitle">" + nr.getResourceType().getName() + "</span>"; + String icon = "types/" + nr.getResourceType().getCategory().getDisplayName() + "_up_16.png"; + + viewId.getBreadcrumbs().add(new Breadcrumb(node.getAttribute("id"), display, icon, true)); + + } else if (node instanceof AutoGroupTreeNode) { + String name = ((AutoGroupTreeNode) node).getBackingGroupName(); + String display = node.getName() + " <span class="subtitle">" + name + "</span>"; + String icon = "types/" + ((AutoGroupTreeNode) node).getResourceType().getCategory() + "_up_16.png"; + + viewId.getBreadcrumbs().add(new Breadcrumb(node.getAttribute("id"), display, icon, true)); + } + } + private void showContextMenu(AutoGroupTreeNode agNode) { getAutoGroupBackingGroup(agNode, new AsyncCallback<ResourceGroup>() { public void onFailure(Throwable caught) { @@ -680,23 +696,6 @@ public class ResourceTreeView extends LocatableVLayout { } }
- private void adjustBreadcrumb(TreeNode node, ViewId viewId) { - if (node instanceof ResourceTreeNode) { - - Resource nr = ((ResourceTreeNode) node).getResource(); - String display = node.getName() + " <span class="subtitle">" + nr.getResourceType().getName() + "</span>"; - String icon = "types/" + nr.getResourceType().getCategory().getDisplayName() + "_up_16.png"; - - viewId.getBreadcrumbs().add(new Breadcrumb(node.getAttribute("id"), display, icon, true)); - - } else { - - // if (node.getName() != null) { - // viewId.getBreadcrumbs().add(new Breadcrumb(node.getAttribute("id"), node.getName(), null, true)); - // } - } - } - /*private List<Resource> preload(final List<Resource> lineage) {
final ArrayList<Resource> list = new ArrayList<Resource>(lineage); @@ -730,8 +729,9 @@ public class ResourceTreeView extends LocatableVLayout { currentViewId = viewPath.getCurrent(); String currentViewIdPath = currentViewId.getPath(); if ("AutoGroup".equals(currentViewIdPath)) { - ViewId nextViewId = viewPath.getNext(); - Integer autoGroupId = Integer.parseInt(nextViewId.getPath()); + // Move the currentViewId to the ID portion to play better with other code + currentViewId = viewPath.getNext(); + Integer autoGroupId = Integer.parseInt(currentViewId.getPath()); setSelectedAutoGroup(autoGroupId); } else { Integer resourceId = Integer.parseInt(currentViewId.getPath());