modules/core/domain/src/main/java/org/rhq/core/domain/resource/Resource.java | 84 +++++++ modules/core/domain/src/main/java/org/rhq/core/domain/resource/ResourceType.java | 4 modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/DisambiguationReport.java | 69 +++++ modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/ResourceNamesDisambiguationResult.java | 90 +++++++ modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/ResourceParentFlyweight.java | 59 +++++ modules/core/util/src/main/java/org/rhq/core/util/IntExtractor.java | 44 +++ modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/common/paging/ResourceNameDisambiguatingPagedListDataModel.java | 117 +++++++++ modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/inventory/resource/ResourcePartialLineageComponent.java | 118 ++++++++++ modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/inventory/resource/ResourcePartialLineageRenderer.java | 88 +++++++ modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/navigation/resource/ResourceSelectUIBean.java | 70 +++++ modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemConfigurationUpdateUIBean.java | 25 +- modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemOOBHistoryUIBean.java | 21 + modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemOperationHistoryUIBean.java | 19 + modules/enterprise/gui/portal-war/src/main/webapp/WEB-INF/jsf-components/inventory-components.xml | 16 + modules/enterprise/gui/portal-war/src/main/webapp/WEB-INF/tags/on.component.taglib.xml | 8 modules/enterprise/gui/portal-war/src/main/webapp/rhq/common/menu/menuitem.xhtml | 15 - modules/enterprise/gui/portal-war/src/main/webapp/rhq/subsystem/configurationUpdate.xhtml | 36 +-- modules/enterprise/gui/portal-war/src/main/webapp/rhq/subsystem/oobHistory.xhtml | 26 -- modules/enterprise/gui/portal-war/src/main/webapp/rhq/subsystem/operationHistory.xhtml | 38 +-- modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java | 109 +++++++++ modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerLocal.java | 15 + 21 files changed, 989 insertions(+), 82 deletions(-)
New commits: commit 8a1014c8b07fcf22d81a9498eb0726cf696c76e6 Author: Lukas Krejci lkrejci@redhat.com Date: Fri Jan 29 18:30:57 2010 +0100
Operation history subsystem page converted to use disambiguation.
diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemOperationHistoryUIBean.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemOperationHistoryUIBean.java index 8839c13..103e29d 100644 --- a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemOperationHistoryUIBean.java +++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemOperationHistoryUIBean.java @@ -31,10 +31,11 @@ import org.rhq.core.domain.operation.composite.ResourceOperationHistoryComposite import org.rhq.core.domain.util.PageControl; import org.rhq.core.domain.util.PageList; import org.rhq.core.gui.util.FacesContextUtility; +import org.rhq.core.util.IntExtractor; import org.rhq.enterprise.gui.common.converter.SelectItemUtils; import org.rhq.enterprise.gui.common.framework.PagedDataTableUIBean; import org.rhq.enterprise.gui.common.paging.PageControlView; -import org.rhq.enterprise.gui.common.paging.PagedListDataModel; +import org.rhq.enterprise.gui.common.paging.ResourceNameDisambiguatingPagedListDataModel; import org.rhq.enterprise.gui.util.EnterpriseFacesContextUtility; import org.rhq.enterprise.server.subsystem.OperationHistorySubsystemManagerLocal; import org.rhq.enterprise.server.util.LookupUtil; @@ -57,6 +58,12 @@ public class SubsystemOperationHistoryUIBean extends PagedDataTableUIBean { private String statusFilter; private SelectItem[] statusFilterItems;
+ private static final IntExtractor<ResourceOperationHistoryComposite> RESOURCE_ID_EXTRATOR = new IntExtractor<ResourceOperationHistoryComposite>() { + public int extract(ResourceOperationHistoryComposite object) { + return object.getHistory().getResource().getId(); + } + }; + public SubsystemOperationHistoryUIBean() { datePattern = EnterpriseFacesContextUtility.getWebUser().getWebPreferences().getDateTimeDisplayPreferences() .getDateTimeFormatTrigger(); @@ -125,13 +132,13 @@ public class SubsystemOperationHistoryUIBean extends PagedDataTableUIBean { return dataModel; }
- private class ResultsDataModel extends PagedListDataModel<ResourceOperationHistoryComposite> { + private class ResultsDataModel extends ResourceNameDisambiguatingPagedListDataModel<ResourceOperationHistoryComposite> { public ResultsDataModel(PageControlView view, String beanName) { - super(view, beanName); + super(view, beanName, true); }
@Override - public PageList<ResourceOperationHistoryComposite> fetchPage(PageControl pc) { + public PageList<ResourceOperationHistoryComposite> fetchDataForPage(PageControl pc) { getDataFromRequest();
String resourceFilter = getResourceFilter(); @@ -148,6 +155,10 @@ public class SubsystemOperationHistoryUIBean extends PagedDataTableUIBean { return result; }
+ protected IntExtractor<ResourceOperationHistoryComposite> getResourceIdExtractor() { + return RESOURCE_ID_EXTRATOR; + } + private void getDataFromRequest() { SubsystemOperationHistoryUIBean outer = SubsystemOperationHistoryUIBean.this; outer.resourceFilter = FacesContextUtility.getOptionalRequestParameter(FORM_PREFIX + "resourceFilter"); diff --git a/modules/enterprise/gui/portal-war/src/main/webapp/rhq/subsystem/operationHistory.xhtml b/modules/enterprise/gui/portal-war/src/main/webapp/rhq/subsystem/operationHistory.xhtml index e2f7ee4..302037d 100644 --- a/modules/enterprise/gui/portal-war/src/main/webapp/rhq/subsystem/operationHistory.xhtml +++ b/modules/enterprise/gui/portal-war/src/main/webapp/rhq/subsystem/operationHistory.xhtml @@ -92,23 +92,17 @@ </f:facet>
<h:outputLink value="#{onf:getDefaultResourceTabURL()}"> - <f:param name="id" value="#{item.history.resource.id}" /> - <h:outputText value="#{item.history.resource.name}" /> + <f:param name="id" value="#{item.original.history.resource.id}" /> + <h:outputText value="#{item.original.history.resource.name}" /> </h:outputLink> </rich:column>
rich:column <f:facet name="header"> - <onc:sortableColumnHeader sort="parent.name"> - <h:outputText styleClass="headerText" value="Parent" /> - </onc:sortableColumnHeader> + <h:outputText styleClass="headerText" value="Parent" /> </f:facet>
- <h:outputLink value="#{onf:getDefaultResourceTabURL()}" - rendered="#{not empty item.parentResourceName}"> - <f:param name="id" value="#{item.parentResourceId}" /> - <h:outputText value="#{item.parentResourceName}" /> - </h:outputLink> + <onc:resourcePartialLineage parents="#{item.parents}" /> </rich:column>
rich:column @@ -118,7 +112,7 @@ </onc:sortableColumnHeader> </f:facet>
- <h:outputText value="#{item.history.createdTime}"> + <h:outputText value="#{item.original.history.createdTime}"> <f:converter converterId="UserDateTimeConverter" /> </h:outputText> </rich:column> @@ -130,7 +124,7 @@ </onc:sortableColumnHeader> </f:facet>
- <h:outputText value="#{item.history.modifiedTime}" rendered="#{item.history.status ne 'INPROGRESS'}" > + <h:outputText value="#{item.original.history.modifiedTime}" rendered="#{item.original.history.status ne 'INPROGRESS'}" > <f:converter converterId="UserDateTimeConverter" /> </h:outputText> </rich:column> @@ -143,9 +137,9 @@ </f:facet>
<h:outputLink value="/rhq/resource/operation/resourceOperationHistoryDetails.xhtml"> - <f:param name="id" value="#{item.history.resource.id}" /> - <f:param name="opId" value="#{item.history.id}" /> - <h:outputText value="#{item.history.operationDefinition.name}" /> + <f:param name="id" value="#{item.original.history.resource.id}" /> + <f:param name="opId" value="#{item.original.history.id}" /> + <h:outputText value="#{item.original.history.operationDefinition.name}" /> </h:outputLink> </rich:column>
@@ -156,14 +150,14 @@ </onc:sortableColumnHeader> </f:facet>
- <h:outputLink rendered="#{item.history.status eq 'FAILURE'}" - value="javascript:displayMessageModal('Stack Trace','#{item.history.errorMessage}')"> + <h:outputLink rendered="#{item.original.history.status eq 'FAILURE'}" + value="javascript:displayMessageModal('Stack Trace','#{item.original.history.errorMessage}')"> <h:graphicImage value="/images/icons/Operation_failed_16.png"/> - <h:outputText value="#{item.history.status}"/> + <h:outputText value="#{item.original.history.status}"/> </h:outputLink>
- <h:graphicImage value="/images/icons/Operation_ok_16.png" rendered="#{item.history.status ne 'FAILURE'}"/> - <h:outputText rendered="#{item.history.status ne 'FAILURE'}" value="#{item.history.status}"/> + <h:graphicImage value="/images/icons/Operation_ok_16.png" rendered="#{item.original.history.status ne 'FAILURE'}"/> + <h:outputText rendered="#{item.original.history.status ne 'FAILURE'}" value="#{item.original.history.status}"/> </rich:column>
rich:column @@ -173,8 +167,8 @@ </onc:sortableColumnHeader> </f:facet>
- <h:outputText value="#{item.history.subjectName}" rendered="#{not empty item.history.subjectName}" /> - <h:outputText value="Unknown" rendered="#{empty item.history.subjectName}" /> + <h:outputText value="#{item.original.history.subjectName}" rendered="#{not empty item.original.history.subjectName}" /> + <h:outputText value="Unknown" rendered="#{empty item.original.history.subjectName}" /> </rich:column>
<f:facet name="footer">
commit c70bd18629d4dea125579f2db860575d7c33a8c8 Author: Lukas Krejci lkrejci@redhat.com Date: Fri Jan 29 18:30:09 2010 +0100
Remove unnecessary @Override
diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemConfigurationUpdateUIBean.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemConfigurationUpdateUIBean.java index 6cb2f4c..0f5777f 100644 --- a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemConfigurationUpdateUIBean.java +++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemConfigurationUpdateUIBean.java @@ -141,7 +141,6 @@ public class SubsystemConfigurationUpdateUIBean extends PagedDataTableUIBean { super(view, beanName, true); }
- @Override public PageList<ConfigurationUpdateComposite> fetchDataForPage(PageControl pc) { getDataFromRequest();
commit 71ac35822e160e19bbb6a4aaa2968a9cf9feaf82 Author: Lukas Krejci lkrejci@redhat.com Date: Fri Jan 29 17:36:27 2010 +0100
OOB History subsystem page converted to use resource names disambiguation.
diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemOOBHistoryUIBean.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemOOBHistoryUIBean.java index fd386fa..94e262a 100644 --- a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemOOBHistoryUIBean.java +++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemOOBHistoryUIBean.java @@ -24,9 +24,10 @@ import org.rhq.core.domain.measurement.composite.MeasurementOOBComposite; import org.rhq.core.domain.util.PageControl; import org.rhq.core.domain.util.PageList; import org.rhq.core.gui.util.FacesContextUtility; +import org.rhq.core.util.IntExtractor; import org.rhq.enterprise.gui.common.framework.PagedDataTableUIBean; import org.rhq.enterprise.gui.common.paging.PageControlView; -import org.rhq.enterprise.gui.common.paging.PagedListDataModel; +import org.rhq.enterprise.gui.common.paging.ResourceNameDisambiguatingPagedListDataModel; import org.rhq.enterprise.server.measurement.MeasurementOOBManagerLocal; import org.rhq.enterprise.server.util.LookupUtil;
@@ -47,7 +48,13 @@ public class SubsystemOOBHistoryUIBean extends PagedDataTableUIBean {
private MeasurementOOBManagerLocal manager = LookupUtil.getOOBManager(); - + + private static final IntExtractor<MeasurementOOBComposite> RESOURCE_ID_EXTRACTOR = new IntExtractor<MeasurementOOBComposite>() { + public int extract(MeasurementOOBComposite value) { + return value.getResourceId(); + } + }; + public SubsystemOOBHistoryUIBean() {
} @@ -92,13 +99,13 @@ public class SubsystemOOBHistoryUIBean extends PagedDataTableUIBean { }
- private class ResultsDataModel extends PagedListDataModel<MeasurementOOBComposite> { + private class ResultsDataModel extends ResourceNameDisambiguatingPagedListDataModel<MeasurementOOBComposite> {
public ResultsDataModel(PageControlView view, String beanName) { - super(view, beanName); + super(view, beanName, true); }
- public PageList<MeasurementOOBComposite> fetchPage(PageControl pc) { + public PageList<MeasurementOOBComposite> fetchDataForPage(PageControl pc) { getDataFromRequest(); String metricFilter = getMetricFilter(); String resourceFilter = getResourceFilter(); @@ -111,6 +118,10 @@ public class SubsystemOOBHistoryUIBean extends PagedDataTableUIBean { return result; }
+ protected IntExtractor<MeasurementOOBComposite> getResourceIdExtractor() { + return RESOURCE_ID_EXTRACTOR; + } + private void getDataFromRequest() { SubsystemOOBHistoryUIBean outer = SubsystemOOBHistoryUIBean.this; outer.metricFilter = FacesContextUtility.getOptionalRequestParameter(FORM_PREFIX + "metricFilter"); diff --git a/modules/enterprise/gui/portal-war/src/main/webapp/rhq/subsystem/oobHistory.xhtml b/modules/enterprise/gui/portal-war/src/main/webapp/rhq/subsystem/oobHistory.xhtml index 48e753b..a7cebd5 100644 --- a/modules/enterprise/gui/portal-war/src/main/webapp/rhq/subsystem/oobHistory.xhtml +++ b/modules/enterprise/gui/portal-war/src/main/webapp/rhq/subsystem/oobHistory.xhtml @@ -80,12 +80,12 @@ </f:facet>
<h:outputLink value="/resource/common/monitor/Visibility.do"> - <f:param name="m" value="#{item.definitionId}"/> - <f:param name="id" value="#{item.resourceId}"/> + <f:param name="m" value="#{item.original.definitionId}"/> + <f:param name="id" value="#{item.original.resourceId}"/> <f:param name="mode" value="chartSingleMetricSingleResource" />
- <h:outputText value="#{item.scheduleName}"/> + <h:outputText value="#{item.original.scheduleName}"/> </h:outputLink> </rich:column>
@@ -97,37 +97,31 @@ </f:facet>
<h:outputLink value="#{onf:getDefaultResourceTabURL()}"> - <f:param name="id" value="#{item.resourceId}" /> - <h:outputText value="#{item.resourceName}" /> + <f:param name="id" value="#{item.original.resourceId}" /> + <h:outputText value="#{item.original.resourceName}" /> </h:outputLink> </rich:column>
rich:column <f:facet name="header"> - <onc:sortableColumnHeader sort="parent.name"> - <h:outputText styleClass="headerText" value="Parent" /> - </onc:sortableColumnHeader> + <h:outputText styleClass="headerText" value="Parent" /> </f:facet>
- <h:outputLink value="#{onf:getDefaultResourceTabURL()}" - rendered="#{not empty item.parentName}"> - <f:param name="id" value="#{item.parentId}" /> - <h:outputText value="#{item.parentName}" /> - </h:outputLink> + <onc:resourcePartialLineage parents="#{item.parents}"/> </rich:column>
rich:column <f:facet name="header"> <h:outputText styleClass="headerText" value="Band"/> </f:facet> - <h:outputText value="#{item.formattedBaseband}"/> + <h:outputText value="#{item.original.formattedBaseband}"/> </rich:column>
<rich:column style="text-align:right"> <f:facet name="header"> <h:outputText styleClass="headerText" value="Outlier value"/> </f:facet> - <h:outputText value="#{item.formattedOutlier}"/> + <h:outputText value="#{item.original.formattedOutlier}"/> </rich:column>
<rich:column style="background-color: rgb(216,216,216);text-align:right"> @@ -137,7 +131,7 @@ </onc:sortableColumnHeader> </f:facet>
- <h:outputText value="#{item.factor}%" > + <h:outputText value="#{item.original.factor}%" > </h:outputText> </rich:column>
commit 83f905719dd4da81baa2bbf4900c66d985321b99 Author: Lukas Krejci lkrejci@redhat.com Date: Fri Jan 29 17:35:20 2010 +0100
Abstracting out the disambiguation into a new abstract ResourceNameDisambiguatingPagedListDataModel that the UI beans can use instead of the former PagedListDataModel.
diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/common/paging/ResourceNameDisambiguatingPagedListDataModel.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/common/paging/ResourceNameDisambiguatingPagedListDataModel.java new file mode 100644 index 0000000..6cea5f8 --- /dev/null +++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/common/paging/ResourceNameDisambiguatingPagedListDataModel.java @@ -0,0 +1,117 @@ +/* + * 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.rhq.enterprise.gui.common.paging; + +import org.rhq.core.domain.resource.composite.DisambiguationReport; +import org.rhq.core.domain.resource.composite.ResourceNamesDisambiguationResult; +import org.rhq.core.domain.util.PageControl; +import org.rhq.core.domain.util.PageList; +import org.rhq.core.util.IntExtractor; +import org.rhq.enterprise.server.resource.ResourceManagerLocal; +import org.rhq.enterprise.server.util.LookupUtil; + +/** + * This is an extension to the {@link PagedListDataModel} that automatically + * performs the disambiguation of the resource names contained in the pages of fetched data. + * <p> + * This class implements the {@link PagedListDataModel#fetchPage(PageControl)} method and defers + * the actual loading of the data to a new {@link #fetchDataForPage(PageControl)} method. The result + * of that call is supplied to the {@link ResourceManagerLocal#disambiguate(java.util.List, boolean, IntExtractor)} + * method and the disambiguated results are then returned from the {@link #fetchPage(PageControl)} method. + * + * @author Lukas Krejci + */ +public abstract class ResourceNameDisambiguatingPagedListDataModel<T> extends + PagedListDataModel<DisambiguationReport<T>> { + + private boolean currentPageNeedsTypeResolution; + private boolean currentPageNeedsPluginResolution; + private boolean currentPageNeedsParentResolution; + private boolean alwaysIncludeParents; + + private ResourceManagerLocal resourceManager = LookupUtil.getResourceManager(); + + /** + * @param view + * @param beanName + * @param alwaysIncludeParents whether the disambiguation should always include the parent + * names even if they wouldn't be needed to make the resource names unique. + */ + public ResourceNameDisambiguatingPagedListDataModel(PageControlView view, String beanName, + boolean alwaysIncludeParents) { + super(view, beanName); + this.alwaysIncludeParents = alwaysIncludeParents; + } + + public PageList<DisambiguationReport<T>> fetchPage(PageControl pc) { + PageList<T> data = fetchDataForPage(pc); + + ResourceNamesDisambiguationResult<T> disambiguation = resourceManager.disambiguate(data, alwaysIncludeParents, + getResourceIdExtractor()); + + currentPageNeedsParentResolution = disambiguation.isParentResolutionNeeded(); + currentPageNeedsPluginResolution = disambiguation.isPluginResolutionNeeded(); + currentPageNeedsTypeResolution = disambiguation.isTypeResolutionNeeded(); + + return new PageList<DisambiguationReport<T>>(disambiguation.getResolution(), pc); + } + + /** + * @return true if the current page contains resources that need parent resolution + * in order to become uniquely named. + */ + public boolean isCurrentPageNeedsParentResolution() { + return currentPageNeedsParentResolution; + } + + /** + * @return true if the current page contains resources of types that have the same name + * and thus need to resolve those types using their plugin names. + */ + public boolean isCurrentPageNeedsPluginResolution() { + return currentPageNeedsPluginResolution; + } + + /** + * @return true if the current page contains resources that need type resolution + * in order to become uniquely named. + */ + public boolean isCurrentPageNeedsTypeResolution() { + return currentPageNeedsTypeResolution; + } + + /** + * This method is to be implemented by inheritors and is called to fetch the actual data + * that contain the resources to disambiguate. + * + * @param pc + * @return + */ + protected abstract PageList<T> fetchDataForPage(PageControl pc); + + /** + * @return an extractor for getting a resource id out of the instance of type T. + */ + protected abstract IntExtractor<T> getResourceIdExtractor(); +} diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemConfigurationUpdateUIBean.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemConfigurationUpdateUIBean.java index 1328d91..6cb2f4c 100644 --- a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemConfigurationUpdateUIBean.java +++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemConfigurationUpdateUIBean.java @@ -38,6 +38,7 @@ import org.rhq.enterprise.gui.common.converter.SelectItemUtils; import org.rhq.enterprise.gui.common.framework.PagedDataTableUIBean; import org.rhq.enterprise.gui.common.paging.PageControlView; import org.rhq.enterprise.gui.common.paging.PagedListDataModel; +import org.rhq.enterprise.gui.common.paging.ResourceNameDisambiguatingPagedListDataModel; import org.rhq.enterprise.gui.util.EnterpriseFacesContextUtility; import org.rhq.enterprise.server.resource.ResourceManagerLocal; import org.rhq.enterprise.server.subsystem.ConfigurationSubsystemManagerLocal; @@ -52,7 +53,6 @@ public class SubsystemConfigurationUpdateUIBean extends PagedDataTableUIBean { private final String CALENDAR_SUFFIX = "InputDate";
private ConfigurationSubsystemManagerLocal manager = LookupUtil.getConfigurationSubsystemManager(); - private ResourceManagerLocal resourceManager = LookupUtil.getResourceManager();
private static String datePattern; private String resourceFilter; @@ -136,13 +136,13 @@ public class SubsystemConfigurationUpdateUIBean extends PagedDataTableUIBean { return dataModel; }
- private class ResultsDataModel extends PagedListDataModel<DisambiguationReport<ConfigurationUpdateComposite>> { + private class ResultsDataModel extends ResourceNameDisambiguatingPagedListDataModel<ConfigurationUpdateComposite> { public ResultsDataModel(PageControlView view, String beanName) { - super(view, beanName); + super(view, beanName, true); }
@Override - public PageList<DisambiguationReport<ConfigurationUpdateComposite>> fetchPage(PageControl pc) { + public PageList<ConfigurationUpdateComposite> fetchDataForPage(PageControl pc) { getDataFromRequest();
String resourceFilter = getResourceFilter(); @@ -156,11 +156,14 @@ public class SubsystemConfigurationUpdateUIBean extends PagedDataTableUIBean { PageList<ConfigurationUpdateComposite> result; result = manager.getResourceConfigurationUpdates(getSubject(), resourceFilter, parentFilter, startMillis, endMillis, status, pc); - ResourceNamesDisambiguationResult<ConfigurationUpdateComposite> disambiguation = - resourceManager.disambiguate(result, true, RESOURCE_ID_EXTRACTOR); - return new PageList<DisambiguationReport<ConfigurationUpdateComposite>>(disambiguation.getResolution(), pc); + + return result; }
+ protected IntExtractor<ConfigurationUpdateComposite> getResourceIdExtractor() { + return RESOURCE_ID_EXTRACTOR; + } + private void getDataFromRequest() { SubsystemConfigurationUpdateUIBean outer = SubsystemConfigurationUpdateUIBean.this; outer.resourceFilter = FacesContextUtility.getOptionalRequestParameter(FORM_PREFIX + "resourceFilter");
commit 000b0da8ba6c47b4dd3a576a2627fb0dfa65d38c Author: Lukas Krejci lkrejci@redhat.com Date: Fri Jan 29 15:49:59 2010 +0100
configuration updates subsystem converted to use disambiguation.
diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/inventory/resource/ResourcePartialLineageComponent.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/inventory/resource/ResourcePartialLineageComponent.java index ee6e576..fdfde42 100644 --- a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/inventory/resource/ResourcePartialLineageComponent.java +++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/inventory/resource/ResourcePartialLineageComponent.java @@ -49,6 +49,7 @@ public class ResourcePartialLineageComponent extends UIComponentBase {
private Boolean renderLinks; private String separator; + private List<ResourceParentFlyweight> parents;
public String getFamily() { return COMPONENT_FAMILY; @@ -86,10 +87,20 @@ public class ResourcePartialLineageComponent extends UIComponentBase {
@SuppressWarnings("unchecked") public List<ResourceParentFlyweight> getParents() { - return FacesComponentUtility.getExpressionAttribute(this, PARENTS_ATTRIBUTE, List.class); + if (parents == null) { + //do *NOT* store this value into the parents explicitly + //unless dynamic updates (if the expression is in loop for example) + //won't work. + return FacesComponentUtility.getExpressionAttribute(this, PARENTS_ATTRIBUTE, List.class); + } else { + return parents; + } }
- + public void setParents(List<ResourceParentFlyweight> parents) { + this.parents = parents; + } + public Object saveState(FacesContext facesContext) { Object[] state = new Object[3]; state[0] = super.saveState(facesContext); diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/navigation/resource/ResourceSelectUIBean.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/navigation/resource/ResourceSelectUIBean.java index b291e14..6672fbe 100644 --- a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/navigation/resource/ResourceSelectUIBean.java +++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/navigation/resource/ResourceSelectUIBean.java @@ -113,7 +113,7 @@ public class ResourceSelectUIBean { result = resourceManager.findResourceComposites(EnterpriseFacesContextUtility.getSubject(), null, null, null, null, pref, true, pc);
- return wrap(resourceManager.disambiguate(result, RESOURCE_ID_EXTRACTOR)); + return wrap(resourceManager.disambiguate(result, false, RESOURCE_ID_EXTRACTOR)); }
private List<DisambiguationReportWrapper> wrap(ResourceNamesDisambiguationResult<ResourceComposite> result) { diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemConfigurationUpdateUIBean.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemConfigurationUpdateUIBean.java index d60d1f9..1328d91 100644 --- a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemConfigurationUpdateUIBean.java +++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/subsystem/SubsystemConfigurationUpdateUIBean.java @@ -28,14 +28,18 @@ import javax.faces.model.SelectItem;
import org.rhq.core.domain.configuration.ConfigurationUpdateStatus; import org.rhq.core.domain.configuration.composite.ConfigurationUpdateComposite; +import org.rhq.core.domain.resource.composite.DisambiguationReport; +import org.rhq.core.domain.resource.composite.ResourceNamesDisambiguationResult; import org.rhq.core.domain.util.PageControl; import org.rhq.core.domain.util.PageList; import org.rhq.core.gui.util.FacesContextUtility; +import org.rhq.core.util.IntExtractor; import org.rhq.enterprise.gui.common.converter.SelectItemUtils; import org.rhq.enterprise.gui.common.framework.PagedDataTableUIBean; import org.rhq.enterprise.gui.common.paging.PageControlView; import org.rhq.enterprise.gui.common.paging.PagedListDataModel; import org.rhq.enterprise.gui.util.EnterpriseFacesContextUtility; +import org.rhq.enterprise.server.resource.ResourceManagerLocal; import org.rhq.enterprise.server.subsystem.ConfigurationSubsystemManagerLocal; import org.rhq.enterprise.server.util.LookupUtil;
@@ -48,7 +52,8 @@ public class SubsystemConfigurationUpdateUIBean extends PagedDataTableUIBean { private final String CALENDAR_SUFFIX = "InputDate";
private ConfigurationSubsystemManagerLocal manager = LookupUtil.getConfigurationSubsystemManager(); - + private ResourceManagerLocal resourceManager = LookupUtil.getResourceManager(); + private static String datePattern; private String resourceFilter; private String parentFilter; @@ -57,6 +62,12 @@ public class SubsystemConfigurationUpdateUIBean extends PagedDataTableUIBean { private String statusFilter; private SelectItem[] statusFilterItems;
+ private static final IntExtractor<ConfigurationUpdateComposite> RESOURCE_ID_EXTRACTOR = new IntExtractor<ConfigurationUpdateComposite>() { + public int extract(ConfigurationUpdateComposite composite) { + return composite.getResourceId(); + } + }; + public SubsystemConfigurationUpdateUIBean() { datePattern = EnterpriseFacesContextUtility.getWebUser().getWebPreferences().getDateTimeDisplayPreferences() .getDateTimeFormatTrigger(); @@ -125,13 +136,13 @@ public class SubsystemConfigurationUpdateUIBean extends PagedDataTableUIBean { return dataModel; }
- private class ResultsDataModel extends PagedListDataModel<ConfigurationUpdateComposite> { + private class ResultsDataModel extends PagedListDataModel<DisambiguationReport<ConfigurationUpdateComposite>> { public ResultsDataModel(PageControlView view, String beanName) { super(view, beanName); }
@Override - public PageList<ConfigurationUpdateComposite> fetchPage(PageControl pc) { + public PageList<DisambiguationReport<ConfigurationUpdateComposite>> fetchPage(PageControl pc) { getDataFromRequest();
String resourceFilter = getResourceFilter(); @@ -145,7 +156,9 @@ public class SubsystemConfigurationUpdateUIBean extends PagedDataTableUIBean { PageList<ConfigurationUpdateComposite> result; result = manager.getResourceConfigurationUpdates(getSubject(), resourceFilter, parentFilter, startMillis, endMillis, status, pc); - return result; + ResourceNamesDisambiguationResult<ConfigurationUpdateComposite> disambiguation = + resourceManager.disambiguate(result, true, RESOURCE_ID_EXTRACTOR); + return new PageList<DisambiguationReport<ConfigurationUpdateComposite>>(disambiguation.getResolution(), pc); }
private void getDataFromRequest() { diff --git a/modules/enterprise/gui/portal-war/src/main/webapp/rhq/subsystem/configurationUpdate.xhtml b/modules/enterprise/gui/portal-war/src/main/webapp/rhq/subsystem/configurationUpdate.xhtml index e700638..a07d657 100644 --- a/modules/enterprise/gui/portal-war/src/main/webapp/rhq/subsystem/configurationUpdate.xhtml +++ b/modules/enterprise/gui/portal-war/src/main/webapp/rhq/subsystem/configurationUpdate.xhtml @@ -92,23 +92,17 @@ </f:facet>
<h:outputLink value="#{onf:getDefaultResourceTabURL()}"> - <f:param name="id" value="#{item.resourceId}" /> - <h:outputText value="#{item.resourceName}" /> + <f:param name="id" value="#{item.original.resourceId}" /> + <h:outputText value="#{item.original.resourceName}" /> </h:outputLink> </rich:column>
rich:column <f:facet name="header"> - <onc:sortableColumnHeader sort="parent.name"> - <h:outputText styleClass="headerText" value="Parent" /> - </onc:sortableColumnHeader> + <h:outputText styleClass="headerText" value="Parent" /> </f:facet>
- <h:outputLink value="#{onf:getDefaultResourceTabURL()}" - rendered="#{not empty item.parentResourceId}"> - <f:param name="id" value="#{item.parentResourceId}" /> - <h:outputText value="#{item.parentResourceName}" /> - </h:outputLink> + <onc:resourcePartialLineage parents="#{item.parents}" /> </rich:column>
rich:column @@ -119,9 +113,9 @@ </f:facet>
<h:outputLink value="/rhq/resource/configuration/history.xhtml"> - <f:param name="id" value="#{item.resourceId}" /> - <f:param name="configId" value="#{item.id}" /> - <h:outputText value="#{item.createdTime}"> + <f:param name="id" value="#{item.original.resourceId}" /> + <f:param name="configId" value="#{item.original.id}" /> + <h:outputText value="#{item.original.createdTime}"> <f:converter converterId="UserDateTimeConverter" /> </h:outputText> </h:outputLink> @@ -134,7 +128,7 @@ </onc:sortableColumnHeader> </f:facet>
- <h:outputText value="#{item.modifiedTime}" rendered="#{item.status ne 'INPROGRESS'}" > + <h:outputText value="#{item.original.modifiedTime}" rendered="#{item.original.status ne 'INPROGRESS'}" > <f:converter converterId="UserDateTimeConverter" /> </h:outputText> </rich:column> @@ -146,15 +140,15 @@ </onc:sortableColumnHeader> </f:facet>
- <h:outputLink rendered="#{item.status eq 'FAILURE'}" - value="javascript:displayMessageModal('Stack Trace','#{item.errorMessage}')"> + <h:outputLink rendered="#{item.original.status eq 'FAILURE'}" + value="javascript:displayMessageModal('Stack Trace','#{item.original.errorMessage}')"> <h:graphicImage value="/images/icons/Configure_failed_16.png"/> - <h:outputText value="#{item.status}"/> + <h:outputText value="#{item.original.status}"/> </h:outputLink>
- <h:graphicImage value="/images/icons/Configure_ok_16.png" rendered="#{item.status eq 'SUCCESS'}"/> + <h:graphicImage value="/images/icons/Configure_ok_16.png" rendered="#{item.original.status eq 'SUCCESS'}"/>
- <h:outputText rendered="#{item.status ne 'FAILURE'}" value="#{item.status}"/> + <h:outputText rendered="#{item.original.status ne 'FAILURE'}" value="#{item.original.status}"/> </rich:column>
rich:column @@ -164,8 +158,8 @@ </onc:sortableColumnHeader> </f:facet>
- <h:outputText value="#{item.subjectName}" rendered="#{not empty item.subjectName}" /> - <h:outputText value="External Change Detected" rendered="#{empty item.subjectName}" /> + <h:outputText value="#{item.original.subjectName}" rendered="#{not empty item.original.subjectName}" /> + <h:outputText value="External Change Detected" rendered="#{empty item.original.subjectName}" /> </rich:column>
<f:facet name="footer"> 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 031d79e..d3a4a67 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 @@ -2112,7 +2112,7 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage return (findChildResources(subject, parentResource, pageControl)); }
- public <T> ResourceNamesDisambiguationResult<T> disambiguate(List<T> results, IntExtractor<? super T> extractor) { + public <T> ResourceNamesDisambiguationResult<T> disambiguate(List<T> results, boolean alwaysIncludeParent, IntExtractor<? super T> extractor) { String query = Resource.NATIVE_QUERY_FIND_DISAMBIGUATION_LEVEL;
query = JDBCUtil.transformQueryForMultipleInParameters(query, "@@RESOURCE_IDS@@", results.size()); @@ -2137,6 +2137,10 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage } }
+ if (alwaysIncludeParent && disambiguationLevel == 0) { + disambiguationLevel = 1; + } + boolean typeResolutionNeeded = typeAndPluginCnt > 1; boolean pluginResolutionNeeded = typeAndPluginCnt > typeCnt; boolean parentResolutionNeeded = disambiguationLevel > 0; 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 b375fd7..9d586fc 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 @@ -443,8 +443,10 @@ public interface ResourceManagerLocal { * * @param <T> the type of the result elements * @param results the results to disambiguate + * @param alwayIncludeParent if true, the parent disambiguation will always be included in the result + * even if the results wouldn't have to be disambiguated using parents. * @param resourceIdExtractor an object able to extract resource id from an instance of type parameter. * @return the disambiguation result or null on error */ - <T> ResourceNamesDisambiguationResult<T> disambiguate(List<T> results, IntExtractor<? super T> resourceIdExtractor); + <T> ResourceNamesDisambiguationResult<T> disambiguate(List<T> results, boolean alwayIncludeParent, IntExtractor<? super T> resourceIdExtractor); } \ No newline at end of file
commit a11c2f023a7dc8c055df319914e2ad8b24df902c Author: Lukas Krejci lkrejci@redhat.com Date: Wed Jan 27 13:20:34 2010 +0100
Disambiguation in quick search in resource menu.
diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/inventory/resource/ResourcePartialLineageComponent.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/inventory/resource/ResourcePartialLineageComponent.java new file mode 100644 index 0000000..ee6e576 --- /dev/null +++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/inventory/resource/ResourcePartialLineageComponent.java @@ -0,0 +1,107 @@ +/* + * 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.rhq.enterprise.gui.inventory.resource; + +import java.util.List; + +import javax.faces.component.UIComponentBase; +import javax.faces.context.FacesContext; + +import org.rhq.core.domain.resource.composite.ResourceParentFlyweight; +import org.rhq.core.gui.util.FacesComponentUtility; + +/** + * A component for displaying partial resource lineage that comes out of the resource name + * disambiguation procedure. + * + * @author Lukas Krejci + */ +public class ResourcePartialLineageComponent extends UIComponentBase { + public static final String COMPONENT_TYPE = "org.jboss.on.ResourcePartialLineage"; + public static final String COMPONENT_FAMILY = "org.jboss.on.ResourcePartialLineage"; + + public static final String DEFAULT_SEPARATOR = " > "; + + private static final String PARENTS_ATTRIBUTE = "parents"; + private static final String RENDER_LINKS_ATTRIBUTE = "renderLinks"; + private static final String SEPARATOR_ATTRIBUTE = "separator"; + + private Boolean renderLinks; + private String separator; + + public String getFamily() { + return COMPONENT_FAMILY; + } + + public Boolean getRenderLinks() { + if (renderLinks == null) { + renderLinks = FacesComponentUtility.getExpressionAttribute(this, RENDER_LINKS_ATTRIBUTE, Boolean.class); + if (renderLinks == null) { + renderLinks = true; + } + } + return renderLinks; + } + + + public void setRenderLinks(Boolean renderLinks) { + this.renderLinks = renderLinks; + } + + + public String getSeparator() { + if (separator == null) { + separator = FacesComponentUtility.getExpressionAttribute(this, SEPARATOR_ATTRIBUTE, String.class); + if (separator == null) { + separator = DEFAULT_SEPARATOR; + } + } + return separator; + } + + public void setSeparator(String separator) { + this.separator = separator; + } + + @SuppressWarnings("unchecked") + public List<ResourceParentFlyweight> getParents() { + return FacesComponentUtility.getExpressionAttribute(this, PARENTS_ATTRIBUTE, List.class); + } + + + public Object saveState(FacesContext facesContext) { + Object[] state = new Object[3]; + state[0] = super.saveState(facesContext); + state[1] = this.renderLinks; + state[2] = this.separator; + return state; + } + + public void restoreState(FacesContext facesContext, Object stateValues) { + Object[] state = (Object[]) stateValues; + super.restoreState(facesContext, state[0]); + this.renderLinks = (Boolean) state[1]; + this.separator = (String) state[2]; + } +} diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/inventory/resource/ResourcePartialLineageRenderer.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/inventory/resource/ResourcePartialLineageRenderer.java new file mode 100644 index 0000000..a526a53 --- /dev/null +++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/inventory/resource/ResourcePartialLineageRenderer.java @@ -0,0 +1,88 @@ +/* + * 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.rhq.enterprise.gui.inventory.resource; + +import java.io.IOException; +import java.util.Iterator; +import java.util.List; + +import javax.faces.component.UIComponent; +import javax.faces.context.FacesContext; +import javax.faces.context.ResponseWriter; +import javax.faces.render.Renderer; + +import org.rhq.core.domain.resource.composite.ResourceParentFlyweight; + +/** + * Renderer for {@link ResourcePartialLineageComponent} + * + * @author Lukas Krejci + */ +public class ResourcePartialLineageRenderer extends Renderer { + private static final String RESOURCE_URL = "/rhq/resource/summary/overview.xhtml"; + + @Override + public void encodeBegin(FacesContext context, UIComponent component) throws IOException { + ResourcePartialLineageComponent lineageComponent = (ResourcePartialLineageComponent) component; + + String separator = lineageComponent.getSeparator(); + List<ResourceParentFlyweight> parents = lineageComponent.getParents(); + boolean renderLinks = lineageComponent.getRenderLinks(); + + if (parents != null && parents.size() > 0) { + ResponseWriter writer = context.getResponseWriter(); + + Iterator<ResourceParentFlyweight> parentsIt = parents.iterator(); + + if (renderLinks) { + encodeUrl(writer, parentsIt.next()); + while(parentsIt.hasNext()) { + writer.writeText(separator, null); + encodeUrl(writer, parentsIt.next()); + } + } else { + encodeSimple(writer, parentsIt.next()); + while(parentsIt.hasNext()) { + writer.writeText(separator, null); + encodeSimple(writer, parentsIt.next()); + } + } + } + } + + private void encodeUrl(ResponseWriter writer, ResourceParentFlyweight parent) throws IOException { + writer.startElement("a", null); + writer.writeAttribute("href", getUrl(parent), null); + encodeSimple(writer, parent); + writer.endElement("a"); + } + + private void encodeSimple(ResponseWriter writer, ResourceParentFlyweight parent) throws IOException { + writer.writeText(parent.getParentName(), null); + } + + private static String getUrl(ResourceParentFlyweight parent) { + return RESOURCE_URL + "?id=" + parent.getParentId(); + } +} diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/navigation/resource/ResourceSelectUIBean.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/navigation/resource/ResourceSelectUIBean.java index 5533ad0..b291e14 100644 --- a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/navigation/resource/ResourceSelectUIBean.java +++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/navigation/resource/ResourceSelectUIBean.java @@ -21,9 +21,16 @@ package org.rhq.enterprise.gui.navigation.resource; import java.util.ArrayList; import java.util.List;
+import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import org.rhq.core.domain.resource.Resource; +import org.rhq.core.domain.resource.composite.DisambiguationReport; import org.rhq.core.domain.resource.composite.ResourceComposite; +import org.rhq.core.domain.resource.composite.ResourceNamesDisambiguationResult; +import org.rhq.core.domain.resource.composite.ResourceParentFlyweight; import org.rhq.core.domain.util.PageControl; +import org.rhq.core.util.IntExtractor; import org.rhq.enterprise.gui.util.EnterpriseFacesContextUtility; import org.rhq.enterprise.server.resource.ResourceManagerLocal; import org.rhq.enterprise.server.util.LookupUtil; @@ -39,6 +46,47 @@ public class ResourceSelectUIBean {
private String searchString;
+ private Log log = LogFactory.getLog(this.getClass()); + + private static final IntExtractor<ResourceComposite> RESOURCE_ID_EXTRACTOR = new IntExtractor<ResourceComposite>() { + public int extract(ResourceComposite resource) { + return resource.getResource().getId(); + } + }; + + public static class DisambiguationReportWrapper extends DisambiguationReport<ResourceComposite> { + private static final long serialVersionUID = 1L; + + private boolean typeResolutionNeeded; + private boolean parentResolutionNeeded; + private boolean pluginResolutionNeeded; + + /** + * @param original + * @param parents + * @param resourceTypeName + * @param resourceTypePluginName + */ + public DisambiguationReportWrapper(DisambiguationReport<ResourceComposite> report, boolean typeResolutionNeeded, boolean parentResolutionNeeded, boolean pluginResolutionNeeded) { + super(report.getOriginal(), report.getParents(), report.getResourceTypeName(), report.getResourceTypePluginName()); + this.typeResolutionNeeded = typeResolutionNeeded; + this.parentResolutionNeeded = parentResolutionNeeded; + this.pluginResolutionNeeded = pluginResolutionNeeded; + } + + public boolean isTypeResolutionNeeded() { + return typeResolutionNeeded; + } + + public boolean isParentResolutionNeeded() { + return parentResolutionNeeded; + } + + public boolean isPluginResolutionNeeded() { + return pluginResolutionNeeded; + } + } + public Resource getResource() { return resource; } @@ -55,7 +103,7 @@ public class ResourceSelectUIBean { this.searchString = searchString; }
- public List<ResourceComposite> autocomplete(Object suggest) { + public List<DisambiguationReportWrapper> autocomplete(Object suggest) { String pref = (String) suggest; ArrayList<ResourceComposite> result;
@@ -65,6 +113,24 @@ public class ResourceSelectUIBean { result = resourceManager.findResourceComposites(EnterpriseFacesContextUtility.getSubject(), null, null, null, null, pref, true, pc);
- return result; + return wrap(resourceManager.disambiguate(result, RESOURCE_ID_EXTRACTOR)); + } + + private List<DisambiguationReportWrapper> wrap(ResourceNamesDisambiguationResult<ResourceComposite> result) { + List<DisambiguationReportWrapper> ret = new ArrayList<DisambiguationReportWrapper>(); + if (result == null) { + return ret; + } + + boolean typeRes = result.isTypeResolutionNeeded(); + boolean parentRes = result.isParentResolutionNeeded(); + boolean pluginRes = result.isPluginResolutionNeeded(); + + + for (DisambiguationReport<ResourceComposite> r : result.getResolution()) { + ret.add(new DisambiguationReportWrapper(r, typeRes, parentRes, pluginRes)); + } + + return ret; } } diff --git a/modules/enterprise/gui/portal-war/src/main/webapp/WEB-INF/jsf-components/inventory-components.xml b/modules/enterprise/gui/portal-war/src/main/webapp/WEB-INF/jsf-components/inventory-components.xml index ac34f7e..2d20275 100644 --- a/modules/enterprise/gui/portal-war/src/main/webapp/WEB-INF/jsf-components/inventory-components.xml +++ b/modules/enterprise/gui/portal-war/src/main/webapp/WEB-INF/jsf-components/inventory-components.xml @@ -14,6 +14,16 @@ </component-extension> </component>
+ <component> + <component-type>org.jboss.on.ResourcePartialLineage</component-type> + <component-class>org.rhq.enterprise.gui.inventory.resource.ResourcePartialLineageComponent</component-class> + + <component-extension> + <component-family>org.jboss.on.ResourcePartialLineage</component-family> + <renderer-type>org.jboss.on.ResourcePartialLineage</renderer-type> + </component-extension> + </component> + <render-kit> <renderer> <description>renderer for a ResourceLineage component</description> @@ -21,6 +31,12 @@ <renderer-type>org.jboss.on.ResourceLineage</renderer-type> <renderer-class>org.rhq.enterprise.gui.inventory.resource.ResourceLineageRenderer</renderer-class> </renderer> + <renderer> + <description>renderer for a ResourcePartialLineage component</description> + <component-family>org.jboss.on.ResourcePartialLineage</component-family> + <renderer-type>org.jboss.on.ResourcePartialLineage</renderer-type> + <renderer-class>org.rhq.enterprise.gui.inventory.resource.ResourcePartialLineageRenderer</renderer-class> + </renderer> </render-kit>
</faces-config> \ No newline at end of file diff --git a/modules/enterprise/gui/portal-war/src/main/webapp/WEB-INF/tags/on.component.taglib.xml b/modules/enterprise/gui/portal-war/src/main/webapp/WEB-INF/tags/on.component.taglib.xml index 1fc9928..665299a 100644 --- a/modules/enterprise/gui/portal-war/src/main/webapp/WEB-INF/tags/on.component.taglib.xml +++ b/modules/enterprise/gui/portal-war/src/main/webapp/WEB-INF/tags/on.component.taglib.xml @@ -97,6 +97,14 @@ </tag>
<tag> + <tag-name>resourcePartialLineage</tag-name> + <component> + <component-type>org.jboss.on.ResourcePartialLineage</component-type> + <renderer-type>org.jboss.on.ResourcePartialLineage</renderer-type> + </component> + </tag> + + <tag> <tag-name>sortableColumnHeader</tag-name> <component> <component-type>org.jboss.on.SortableColumnHeader</component-type> diff --git a/modules/enterprise/gui/portal-war/src/main/webapp/rhq/common/menu/menuitem.xhtml b/modules/enterprise/gui/portal-war/src/main/webapp/rhq/common/menu/menuitem.xhtml index 9731b9f..3bbce89 100644 --- a/modules/enterprise/gui/portal-war/src/main/webapp/rhq/common/menu/menuitem.xhtml +++ b/modules/enterprise/gui/portal-war/src/main/webapp/rhq/common/menu/menuitem.xhtml @@ -9,6 +9,7 @@ xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:rich="http://richfaces.ajax4jsf.org/rich" xmlns:a4j="https://ajax4jsf.dev.java.net/ajax" + xmlns:onc="http://jboss.org/on/component" xmlns:onf="http://jboss.org/on/function%22%3E
<body> @@ -218,7 +219,7 @@ currentMenuItem - the org.rhq.enterprise.server.perspective.menuItem to render suggestionAction="#{ResourceSelectUIBean.autocomplete}" var="result" data="foo" - fetchValue="#{result.resource.id}" + fetchValue="#{result.original.resource.id}" nothingLabel="No matching resources found" style="background-color: #cccccc;" onselect="document.location.href='#{onf:getDefaultResourceTabURL()}?id=' + #{rich:element('selectedResource')}.value" @@ -228,15 +229,19 @@ currentMenuItem - the org.rhq.enterprise.server.perspective.menuItem to render <h:column> <f:facet name="header">Avail</f:facet> <h:graphicImage - value="/images/icons/availability_#{result.availability == 'UP' ? 'green' : 'red'}_16.png" /> + value="/images/icons/availability_#{result.original.availability == 'UP' ? 'green' : 'red'}_16.png" /> </h:column> <h:column> <f:facet name="header">Resource</f:facet> - <h:outputText value="#{result.resource.name}" /> + <h:outputText value="#{result.original.resource.name}" /> </h:column> - <h:column> + <h:column rendered="#{result.typeResolutionNeeded}"> + <f:facet name="header">Type</f:facet> + <h:outputText value="#{result.resourceTypeName}"/> + </h:column> + <h:column rendered="#{result.parentResolutionNeeded}"> <f:facet name="header">Parent</f:facet> - <h:outputText value="#{result.parent.name}" /> + <onc:resourcePartialLineage parents="#{result.parents}" renderLinks="false" /> </h:column> </rich:suggestionbox> </h:panelGroup>
commit 58c764fdea3ae81d1a698255bf4cd9de741687d5 Author: Lukas Krejci lkrejci@redhat.com Date: Wed Jan 27 13:20:02 2010 +0100
First implementation of resource names disambiguation algorithm.
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/Resource.java b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/Resource.java index 9541d1e..4ace566 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/Resource.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/Resource.java @@ -726,10 +726,11 @@ import org.rhq.core.domain.util.serial.ExternalizableStrategy;
}) @SequenceGenerator(name = "RHQ_RESOURCE_SEQ", sequenceName = "RHQ_RESOURCE_ID_SEQ") -@Table(name = "RHQ_RESOURCE") +@Table(name = Resource.TABLE_NAME) @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement public class Resource implements Comparable<Resource>, Externalizable { + public static final String TABLE_NAME = "RHQ_RESOURCE"; public static final String QUERY_FIND_PROBLEM_RESOURCES_ALERT = "Resource.findProblemResourcesAlert"; public static final String QUERY_FIND_PROBLEM_RESOURCES_ALERT_ADMIN = "Resource.findProblemResourcesAlert_admin"; public static final String QUERY_FIND_PROBLEM_RESOURCES_ALERT_COUNT = "Resource.findProblemResourcesAlertCount"; @@ -853,6 +854,87 @@ public class Resource implements Comparable<Resource>, Externalizable { public static final String QUERY_RESOURCE_REPORT = "Resource.findResourceReport"; public static final String QUERY_RESOURCE_VERSION_REPORT = "Resource.findResourceVersionReport";
+ public static final int MAX_SUPPORTED_RESOURCE_HIERARCHY_DEPTH = 7; + + private static final String NAME_CONCAT_SEPARATOR = "~!@#)))"; + + /** + * Helper for {@link #NATIVE_QUERY_FIND_DISAMBIGUATION_LEVEL}. + * We need to guard against concatenation with a NULL value which + * would yield a NULL result. We don't want that in that query, otherwise + * we'd get skewed results for combination of resources on different + * levels in the resource hierarchy. + * + * @param column + * @return + */ + private static String guardNullCase(String column) { + return "(CASE WHEN " + column + " IS NULL THEN 'null' ELSE " + column + " END)"; + } + + /** + * We're trying to find the minimum ancestry level that provides the disambiguate paths + * (in terms of unique resource names) for given resources. Obviously this query only works + * for hierarchies at most 7 levels deep (as the rest of the named queries above). + * + * <ul> + * <li>target_cnt gives us the number of resources we're trying to disambiguate. + * <li>l1_cnt gives us the number of resources with unique names, + * <li>l2_cnt gives us the number of resources with unique names with the names of the parent taken into account, + * <li>l3_cnt is the number of resource with unique names when parent and grandparent are included, etc. + * </ul> + * + * So when the caller gets the result row of this query, s/he can reason as follows: + * <ul> + * <li>l1_cnt = target_cnt: the names of the resources are unique in the given set + * <li>l2_cnt = target_cnt: the names + parent names are unique + * <li>... + * </ul> + * + * we need to do the concatenation of names instead of doing a DISTINCT over + * more columns because (at least in Postgres) a set of columns doesn't define + * equality operator to be used in the COUNT aggregate. + * Thus we need to add the "unlikely separator" hack. + * + * This query has to be native because Hibernate doesn't understand the + * COUNT(DISTINCT ...)) where ... is anything else than a path to a property in Hibernate terminology. + */ + public static final String NATIVE_QUERY_FIND_DISAMBIGUATION_LEVEL = "" + + "SELECT COUNT(r.ID) AS target_cnt, " + + "COUNT(DISTINCT(t.name)) AS bare_type_cnt," + + "COUNT(DISTINCT(t.name || '" + NAME_CONCAT_SEPARATOR + "' || t.plugin)) AS full_type_cnt," + + "COUNT(DISTINCT(r.name)) AS l1_cnt," + + "COUNT(DISTINCT(r.name || '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p1.name") + ")) AS l2_cnt," + + "COUNT(DISTINCT(r.name || '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p1.name") + " || " + + " '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p2.name") + ")) AS l3_cnt," + + "COUNT(DISTINCT(r.name || '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p1.name") + " || " + + " '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p2.name") + " || " + + " '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p3.name") + ")) AS l4_cnt," + + "COUNT(DISTINCT(r.name || '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p1.name") + " || " + + " '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p2.name") + " || " + + " '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p3.name") + " || " + + " '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p4.name") + ")) AS l5_cnt," + + "COUNT(DISTINCT(r.name || '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p1.name") + " || " + + " '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p2.name") + " || " + + " '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p3.name") + " || " + + " '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p4.name") + " || " + + " '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p5.name") + ")) AS l6_cnt," + + "COUNT(DISTINCT(r.name || '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p1.name") + "|| " + + " '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p2.name") + " || " + + " '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p3.name") + " || " + + " '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p4.name") + " || " + + " '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p5.name") + " || " + + " '" + NAME_CONCAT_SEPARATOR + "' || " + guardNullCase("p6.name") + ")) AS l7_cnt " + + "FROM " + TABLE_NAME + " AS r " + + "JOIN " + ResourceType.TABLE_NAME + " AS t ON r.RESOURCE_TYPE_ID = t.ID " + + "LEFT OUTER JOIN " + TABLE_NAME + " AS p1 ON r.PARENT_RESOURCE_ID = p1.ID " + + "LEFT OUTER JOIN " + TABLE_NAME + " AS p2 ON p1.PARENT_RESOURCE_ID = p2.ID " + + "LEFT OUTER JOIN " + TABLE_NAME + " AS p3 ON p2.PARENT_RESOURCE_ID = p3.ID " + + "LEFT OUTER JOIN " + TABLE_NAME + " AS p4 ON p3.PARENT_RESOURCE_ID = p4.ID " + + "LEFT OUTER JOIN " + TABLE_NAME + " AS p5 ON p4.PARENT_RESOURCE_ID = p5.ID " + + "LEFT OUTER JOIN " + TABLE_NAME + " AS p6 ON p5.PARENT_RESOURCE_ID = p6.ID " + + "WHERE r.ID IN (@@RESOURCE_IDS@@)"; + private static final long serialVersionUID = 1L;
public static final Resource ROOT = null; diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/ResourceType.java b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/ResourceType.java index de6fcd1..3dcaf7d 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/ResourceType.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/ResourceType.java @@ -79,7 +79,7 @@ import org.rhq.core.domain.util.serial.ExternalizableStrategy; * @author Ian Springer */ @Entity -@Table(name = "RHQ_RESOURCE_TYPE") +@Table(name = ResourceType.TABLE_NAME) @SequenceGenerator(name = "SEQ", sequenceName = "RHQ_RESOURCE_TYPE_ID_SEQ") @NamedQueries( { @NamedQuery(name = ResourceType.QUERY_FIND_BY_NAME, // TODO: QUERY: This breaks rules, names may not be unique between plugins @@ -240,6 +240,8 @@ import org.rhq.core.domain.util.serial.ExternalizableStrategy; public class ResourceType implements Externalizable, Comparable<ResourceType> { private static final long serialVersionUID = 1L;
+ public static final String TABLE_NAME = "RHQ_RESOURCE_TYPE"; + public static final ResourceType ANY_PLATFORM_TYPE = null;
public static final String QUERY_FIND_BY_NAME = "ResourceType.findByName"; diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/DisambiguationReport.java b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/DisambiguationReport.java new file mode 100644 index 0000000..67f3276 --- /dev/null +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/DisambiguationReport.java @@ -0,0 +1,69 @@ +/* + * 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.rhq.core.domain.resource.composite; + +import java.io.Serializable; +import java.util.Collections; +import java.util.List; + +/** + * Contains information about disambiguation of a resource name. + * + * @author Lukas Krejci + */ +public class DisambiguationReport<T> implements Serializable { + private static final long serialVersionUID = 1L; + + private T original; + private List<ResourceParentFlyweight> parents; + private String resourceTypeName; + private String resourceTypePluginName; + + public DisambiguationReport(T original, List<ResourceParentFlyweight> parents, String resourceTypeName, String resourceTypePluginName) { + this.original = original; + this.parents = Collections.unmodifiableList(parents); + this.resourceTypeName = resourceTypeName; + this.resourceTypePluginName = resourceTypePluginName; + } + + public T getOriginal() { + return original; + } + + public List<ResourceParentFlyweight> getParents() { + return parents; + } + + public String getResourceTypeName() { + return resourceTypeName; + } + + public String getResourceTypePluginName() { + return resourceTypePluginName; + } + + public String toString() { + return "DisambiguationReport(type=" + resourceTypeName + ", plugin=" + resourceTypePluginName + ", parents=" + parents + ")"; + } +} \ No newline at end of file diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/ResourceNamesDisambiguationResult.java b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/ResourceNamesDisambiguationResult.java new file mode 100644 index 0000000..5d2bf2d --- /dev/null +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/ResourceNamesDisambiguationResult.java @@ -0,0 +1,90 @@ +/* + * 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.rhq.core.domain.resource.composite; + +import java.io.Serializable; +import java.util.List; + +/** + * This class is a result of resource disambiguation. + * This is used in ResourceManager. When supplied a list of results, it returns an + * instance of this class describing how the results should be disambiguated. + * + * @author Lukas Krejci + */ +public class ResourceNamesDisambiguationResult<T> implements Serializable { + + private static final long serialVersionUID = 1L; + + private List<DisambiguationReport<T>> resolution; + private boolean typeResolutionNeeded; + private boolean pluginResolutionNeeded; + private boolean parentResolutionNeeded; + + public ResourceNamesDisambiguationResult(List<DisambiguationReport<T>> resolution, boolean needsTypeResolution, + boolean needsParentResolution, boolean needsPluginResolution) { + this.resolution = resolution; + this.parentResolutionNeeded = needsParentResolution; + this.typeResolutionNeeded = needsTypeResolution; + this.pluginResolutionNeeded = needsPluginResolution; + } + + /** + * Lists the disambiguation results. + * Each record contains the original value, disambiguated parents, the resource type name and + * the type plugin name. + */ + public List<DisambiguationReport<T>> getResolution() { + return resolution; + } + + /** + * This tells the caller whether the result set contained resources with different types. + */ + public boolean isTypeResolutionNeeded() { + return typeResolutionNeeded; + } + + /** + * This is true when the resources come from different parents. + */ + public boolean isParentResolutionNeeded() { + return parentResolutionNeeded; + } + + /** + * This is true if the results contained resources of different types with the same name. + * In that case, the types need to be augmented with the plugin they come from. + */ + public boolean isPluginResolutionNeeded() { + return pluginResolutionNeeded; + } + + public String toString() { + return "ResourceNamesDisambiguationResult(typeResolutionNeeded=" + typeResolutionNeeded + + ", parentResolutionNeeded=" + parentResolutionNeeded + + ", pluginResolutionNeeded=" + pluginResolutionNeeded + + ", resolution=" + resolution + ")"; + } +} diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/ResourceParentFlyweight.java b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/ResourceParentFlyweight.java new file mode 100644 index 0000000..1298df4 --- /dev/null +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/ResourceParentFlyweight.java @@ -0,0 +1,59 @@ +/* + * 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.rhq.core.domain.resource.composite; + +import java.io.Serializable; + +/** + * A light-weight representation of a resource parent. + * + * @author Lukas Krejci + */ +public class ResourceParentFlyweight implements Serializable { + + private static final long serialVersionUID = 1L; + private int parentId; + private String parentName; + + /** + * @param parentId + * @param parentName + */ + public ResourceParentFlyweight(int parentId, String parentName) { + this.parentId = parentId; + this.parentName = parentName; + } + + public int getParentId() { + return parentId; + } + + public String getParentName() { + return parentName; + } + + public String toString() { + return "ResourceParentFlyweight(id=" + parentId + ", name=" + parentName + ")"; + } +} diff --git a/modules/core/util/src/main/java/org/rhq/core/util/IntExtractor.java b/modules/core/util/src/main/java/org/rhq/core/util/IntExtractor.java new file mode 100644 index 0000000..eb6836d --- /dev/null +++ b/modules/core/util/src/main/java/org/rhq/core/util/IntExtractor.java @@ -0,0 +1,44 @@ +/* + * 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.rhq.core.util; + +/** + * Extracts an integer value. + * + * @author Lukas Krejci + */ +public interface IntExtractor<T> { + + /** + * Extracts an integer value out of the supplied object. + * The "meaning" of the integer is dictated by the caller of this method. + * <p> + * An appropriate implementation of this interface must be used for + * appropriate purposes. + * + * @param object + * @return + */ + int extract(T object); +} 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 eb2a4fa..031d79e 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java @@ -20,6 +20,7 @@ package org.rhq.enterprise.server.resource;
import java.lang.reflect.Constructor; import java.lang.reflect.Method; +import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -88,6 +89,7 @@ import org.rhq.core.domain.resource.ResourceError; import org.rhq.core.domain.resource.ResourceErrorType; import org.rhq.core.domain.resource.ResourceSubCategory; import org.rhq.core.domain.resource.ResourceType; +import org.rhq.core.domain.resource.composite.DisambiguationReport; import org.rhq.core.domain.resource.composite.LockedResource; import org.rhq.core.domain.resource.composite.RecentlyAddedResourceComposite; import org.rhq.core.domain.resource.composite.ResourceAvailabilitySummary; @@ -95,13 +97,17 @@ 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.ResourceNamesDisambiguationResult; +import org.rhq.core.domain.resource.composite.ResourceParentFlyweight; import org.rhq.core.domain.resource.composite.ResourceWithAvailability; import org.rhq.core.domain.resource.group.ResourceGroup; import org.rhq.core.domain.resource.group.composite.AutoGroupComposite; import org.rhq.core.domain.util.PageControl; import org.rhq.core.domain.util.PageList; import org.rhq.core.domain.util.PersistenceUtility; +import org.rhq.core.util.IntExtractor; import org.rhq.core.util.collection.ArrayUtils; +import org.rhq.core.util.jdbc.JDBCUtil; import org.rhq.enterprise.server.RHQConstants; import org.rhq.enterprise.server.agentclient.AgentClient; import org.rhq.enterprise.server.auth.SubjectManagerLocal; @@ -2105,4 +2111,103 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
return (findChildResources(subject, parentResource, pageControl)); } + + public <T> ResourceNamesDisambiguationResult<T> disambiguate(List<T> results, IntExtractor<? super T> extractor) { + String query = Resource.NATIVE_QUERY_FIND_DISAMBIGUATION_LEVEL; + + query = JDBCUtil.transformQueryForMultipleInParameters(query, "@@RESOURCE_IDS@@", results.size()); + Query disambiguateQuery = entityManager.createNativeQuery(query); + int i = 1; + for(T r : results) { + disambiguateQuery.setParameter(i++, extractor.extract(r)); + } + + Object[] rs = (Object[]) disambiguateQuery.getSingleResult(); + + int disambiguationLevel = Resource.MAX_SUPPORTED_RESOURCE_HIERARCHY_DEPTH; //the max we support + + int targetCnt = ((BigInteger)rs[0]).intValue(); + int typeCnt = ((BigInteger)rs[1]).intValue(); + int typeAndPluginCnt = ((BigInteger)rs[2]).intValue(); + for (i = 1; i <= Resource.MAX_SUPPORTED_RESOURCE_HIERARCHY_DEPTH; ++i) { + int levelCnt = ((BigInteger)rs[2 + i]).intValue(); + if (levelCnt == targetCnt) { + disambiguationLevel = i - 1; + break; + } + } + + boolean typeResolutionNeeded = typeAndPluginCnt > 1; + boolean pluginResolutionNeeded = typeAndPluginCnt > typeCnt; + boolean parentResolutionNeeded = disambiguationLevel > 0; + + //we can't assume any ordering in the results, hence this map + Map<Integer, MutableDisambiguationReport<T>> reportByResourceId = new LinkedHashMap<Integer, MutableDisambiguationReport<T>>(); + for (T r : results) { + MutableDisambiguationReport<T> value = new MutableDisambiguationReport<T>(); + value.original = r; + reportByResourceId.put(extractor.extract(r), value); + } + + //k, now let's construct the JPQL query to get the parents and type infos... + StringBuilder selectBuilder = new StringBuilder( + "SELECT r0.id, r0.resourceType.name, r0.resourceType.plugin"); + StringBuilder fromBuilder = new StringBuilder("FROM Resource r0"); + + for (i = 1; i <= disambiguationLevel; ++i) { + int pi = i - 1; + selectBuilder.append(", r").append(i).append(".id"); + selectBuilder.append(", r").append(i).append(".name"); + fromBuilder.append(" left join r").append(pi).append(".parentResource r").append(i); + } + + fromBuilder.append(" WHERE r0.id IN (:resourceIds)"); + + Query parentsQuery = entityManager.createQuery(selectBuilder.append(" ").append(fromBuilder).toString()); + + parentsQuery.setParameter("resourceIds", reportByResourceId.keySet()); + + @SuppressWarnings("unchecked") + List<Object[]> parentsResults = (List<Object[]>) parentsQuery.getResultList(); + for (Object[] parentsResult : parentsResults) { + List<ResourceParentFlyweight> parents = new ArrayList<ResourceParentFlyweight>(disambiguationLevel); + Integer resourceId = (Integer) parentsResult[0]; + String typeName = (String) parentsResult[1]; + String pluginName = (String) parentsResult[2]; + + for (i = 1; i <= disambiguationLevel; ++i) { + Integer parentId = (Integer) parentsResult[2 * i + 1]; + if (parentId == null) + break; + String parentName = (String) parentsResult[2 * i + 2]; + parents.add(new ResourceParentFlyweight(parentId, parentName)); + } + MutableDisambiguationReport<T> report = reportByResourceId.get(resourceId); + report.typeName = typeName; + report.pluginName = pluginName; + report.parents = parents; + } + + //now we have all the information to create the result. + //first create the immutable reports. + List<DisambiguationReport<T>> resolution = new ArrayList<DisambiguationReport<T>>(reportByResourceId.size()); + + for (Map.Entry<Integer, MutableDisambiguationReport<T>> entry : reportByResourceId.entrySet()) { + resolution.add(entry.getValue().getReport()); + } + + return new ResourceNamesDisambiguationResult<T>(resolution, typeResolutionNeeded, parentResolutionNeeded, + pluginResolutionNeeded); + } + + private static class MutableDisambiguationReport<T> { + public T original; + public String typeName; + public String pluginName; + public List<ResourceParentFlyweight> parents; + + public DisambiguationReport<T> getReport() { + return new DisambiguationReport<T>(original, parents, typeName, pluginName); + } + } } 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 95445de..b375fd7 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 @@ -42,11 +42,14 @@ 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.ResourceNamesDisambiguationResult; +import org.rhq.core.domain.resource.composite.ResourceParentFlyweight; import org.rhq.core.domain.resource.composite.ResourceWithAvailability; import org.rhq.core.domain.resource.group.ResourceGroup; import org.rhq.core.domain.resource.group.composite.AutoGroupComposite; import org.rhq.core.domain.util.PageControl; import org.rhq.core.domain.util.PageList; +import org.rhq.core.util.IntExtractor; import org.rhq.enterprise.server.resource.group.ResourceGroupNotFoundException;
/** @@ -434,4 +437,14 @@ public interface ResourceManagerLocal { PageList<Resource> findChildResources(Subject subject, int resourceId, PageControl pageControl);
Resource getParentResource(Subject subject, int resourceId); + + /** + * Given a list of results, this method produces + * + * @param <T> the type of the result elements + * @param results the results to disambiguate + * @param resourceIdExtractor an object able to extract resource id from an instance of type parameter. + * @return the disambiguation result or null on error + */ + <T> ResourceNamesDisambiguationResult<T> disambiguate(List<T> results, IntExtractor<? super T> resourceIdExtractor); } \ No newline at end of file
rhq-commits@lists.fedorahosted.org