/* * 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.server.resource.disambiguation; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.List; import org.rhq.enterprise.server.resource.disambiguation.MutableDisambiguationReport.Resource; /** * This enumerates different strategies that can be used to update the results to produce disambiguated list. * * @author Lukas Krejci */ public enum DefaultDisambiguationUpdateStrategies implements DisambiguationUpdateStrategy { /** * The disambiguation policy is followed precisely. */ EXACT { public <T> void update(DisambiguationPolicy policy, MutableDisambiguationReport<T> report) { updateResources(policy, report, true, true); int nofParents = policy.size() - 1; if (nofParents < 0) nofParents = 0; if (nofParents == 0) { report.parents.clear(); } else { while (report.parents.size() > nofParents) { report.parents.remove(report.parents.size() - 1); } } } public <T> boolean partitionFurther(ReportPartitions<T> partitions) { return true; } }, /** * Even if the disambiguation policy determined that parents are not needed to disambiguate the * results, at least one of them is kept in the report. */ KEEP_AT_LEAST_ONE_PARENT { public <T> void update(DisambiguationPolicy policy, MutableDisambiguationReport<T> report) { updateResources(policy, report, true, true); int nofParents = policy.size() - 1; if (nofParents < 1) nofParents = 1; while (report.parents.size() > nofParents) { report.parents.remove(report.parents.size() - 1); } } @Override public EnumSet<ResourceResolution> resourceLevelRepartitionableResolutions() { return EnumSet.allOf(ResourceResolution.class); } public <T> boolean partitionFurther(ReportPartitions<T> partitions) { return true; } }, /** * The parentage of the report is retained at least up to the server/service directly under platform. * If the policy needs the platform to stay, it is of course preserved. */ KEEP_PARENTS_TO_TOPMOST_SERVERS { public <T> void update(DisambiguationPolicy policy, MutableDisambiguationReport<T> report) { updateResources(policy, report, true, true); //only remove the platform, if the policy doesn't dictate its presence... if (policy.size() > 1 && report.parents.size() > policy.size() - 1) { report.parents.remove(report.parents.size() - 1); } } @Override public EnumSet<ResourceResolution> resourceLevelRepartitionableResolutions() { return EnumSet.allOf(ResourceResolution.class); } public <T> boolean partitionFurther(ReportPartitions<T> partitions) { return partitions.getDisambiguationPolicy().size() < Disambiguator.MAXIMUM_DISAMBIGUATED_TREE_DEPTH - 1; } }, /** * All parents are preserved no matter what the policy says. */ KEEP_ALL_PARENTS { public <T> void update(DisambiguationPolicy policy, MutableDisambiguationReport<T> report) { updateResources(policy, report, true, true); //do nothing to the parents, keep them as they are... } public EnumSet<ResourceResolution> resourceLevelRepartitionableResolutions() { return EnumSet.of(ResourceResolution.NAME); } public EnumSet<ResourceResolution> alwaysRepartitionableResolutions() { return EnumSet.of(ResourceResolution.NAME); } public <T> boolean partitionFurther(ReportPartitions<T> partitions) { //we always keep all the info about the resources in this strategy //so there's no real need to disambiguate anything. return false; } }; private static final DisambiguationPolicy.Level OVERRIDING_RESOLUTION = new DisambiguationPolicy.Level(ResourceResolution.TYPE); /** * This updates the resources in the report according to the resolutions contained in the policy. * This method is called as part of the {@link DisambiguationUpdateStrategy#update(DisambiguationPolicy, MutableDisambiguationReport)} * implementations in this enum before the individual enums modify the parent list as they see fit. * This method is left public because it is generic enough to be reused by other potential implementations of the * {@link DisambiguationUpdateStrategy} interface. * * @param <T> * @param policy * @param report * @param honorAmbiguousTypeNamesList whether to honor the list of ambiguous type names as listed in the policy when updating the resources. * @param pushDownPluginInfo if true, the plugin information is pushed down as low in the resource hierarchy as possible. This means that if * some parent needs plugin disambiguation or is of an ambiguous type and the resource comes from the same plugin, the plugin info is preserved * on the resource rather than on the parent. This is mainly useful for the display purposes, because it just * looks nicer to have that info at a resource than somewhere in the location string. */ public static <T> void updateResources(DisambiguationPolicy policy, MutableDisambiguationReport<T> report, boolean honorAmbiguousTypeNamesList, boolean pushDownPluginInfo) { List<String> ambiguousTypeNames = honorAmbiguousTypeNamesList ? policy.getAmbiguousTypeNames() : Collections.<String>emptyList(); String resourcePlugin = report.resource.resourceType.plugin; List<String> parentPlugins = new ArrayList<String>(report.parents.size()); updateResource(policy.get(0), report.resource, ambiguousTypeNames); int disambiguationPolicyIndex = 1; while (disambiguationPolicyIndex < policy.size() && disambiguationPolicyIndex - 1 < report.parents.size()) { DisambiguationPolicy.Level resolutionLevel = policy.get(disambiguationPolicyIndex); MutableDisambiguationReport.Resource parent = report.parents.get(disambiguationPolicyIndex - 1); if (pushDownPluginInfo) { parentPlugins.add(parent.resourceType.plugin); } updateResource(resolutionLevel, parent, ambiguousTypeNames); disambiguationPolicyIndex++; } disambiguationPolicyIndex--; //because the parents update strategy might leave more parents than this policy requires for disambiguation //we need to treat those parents as well. Because they are not needed for disambiguation, treat them as //if only the name and type was needed for them. for (; disambiguationPolicyIndex < report.parents.size(); ++disambiguationPolicyIndex) { if (pushDownPluginInfo) { parentPlugins.add(report.parents.get(disambiguationPolicyIndex).resourceType.plugin); } updateResource(OVERRIDING_RESOLUTION, report.parents.get(disambiguationPolicyIndex), ambiguousTypeNames); } if (pushDownPluginInfo) { for (int i = report.parents.size() - 1; i >= 0; --i) { String plugin = report.parents.get(i).resourceType.plugin; if (plugin != null && i > 0 && plugin.equals(parentPlugins.get(i - 1))) { report.parents.get(i - 1).resourceType.plugin = plugin; report.parents.get(i).resourceType.plugin = null; } } if (report.parents.size() > 0) { String plugin = report.parents.get(0).resourceType.plugin; if (plugin != null && plugin.equals(resourcePlugin)) { report.resource.resourceType.plugin = resourcePlugin; report.parents.get(0).resourceType.plugin = null; } } } } /** * @return a set of resolutions for which the unique reports need to be repartitioned at the resource level. * In another words this forces the disambiguation to continue on up the disambiguation chain even if the * it disambiguates the resuts successfully at the resource level. */ public EnumSet<ResourceResolution> resourceLevelRepartitionableResolutions() { return EnumSet.noneOf(ResourceResolution.class); } /** * @return a set of resolutions for which uniquely disambiguated reports are to be repartitioned further. * The resolutions from this set apply on the parents (on any level), unlike the resolutions from {@link #resourceLevelRepartitionableResolutions()}. */ public EnumSet<ResourceResolution> alwaysRepartitionableResolutions() { return EnumSet.noneOf(ResourceResolution.class); } private static void updateResource(DisambiguationPolicy.Level resolutionLevel, Resource resource, List<String> ambiguousTypeNames) { switch (resolutionLevel.getResourceResolution()) { case NAME: case TYPE: if (!ambiguousTypeNames.contains(resource.resourceType.name)) { resource.resourceType.plugin = null; } break; case PLUGIN: if (!(resolutionLevel.isDeciding() || ambiguousTypeNames.contains(resource.resourceType.name))) { resource.resourceType.plugin = null; } } } public static DefaultDisambiguationUpdateStrategies getDefault() { return DefaultDisambiguationUpdateStrategies.KEEP_ALL_PARENTS; } }