/* * RHQ Management Platform * Copyright (C) 2005-2008 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, as * published by the Free Software Foundation, and/or the GNU Lesser * General Public License, version 2.1, also as published by the Free * Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License and the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.rhq.plugins.jmx.util; import org.rhq.core.domain.configuration.Configuration; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.HashSet; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * A utility class to help in querying object names and utilizing parts of the object name for setting configuration * values and changing string messages. A template that you'd build this utility with could look like * "foo:name=%myName%,type=myType". This will be "translated" into a valid JMX objectName Query of the form * "foo:type=myType,*". It will also detect that we've got a variable defined as "myName" that we'd like to later match * to. * * <p/>We can then find beans with the query and apply their objectName properties to the object and use those found * values to rewrite strings or setup configuration properties. For example, we've got a detected object name for the * above template "foo:name=bar,type=myType". We set its detected keys against this utility and we now have a variable * defined as the key "myName" and the value of "bar". Then I can call formatMessage with "A foo called {myName}" which * will be translated into "A foo called bar". This can be useful for naming resources and descriptions using parts of a * mapped ObjectName. * * @author Greg Hinkle */ public class ObjectNameQueryUtility { private String queryTemplate; private Map<String, String> variableProperties = new HashMap<String, String>(); private Map<String, String> variableValues = new HashMap<String, String>(); private Set<String> nonVariableProperties = new HashSet<String>(); private String translatedQuery; /** * Builds a mapped query utility object and finds the variables in the supplied object name query template. * * @param objectNameQueryTemplate string of form "a:b=%c%,d=e,f=%g%" */ public ObjectNameQueryUtility(String objectNameQueryTemplate) { this.queryTemplate = objectNameQueryTemplate; buildMatchMap(queryTemplate); } /** * Builds a mapped query utility object and finds the variables in the supplied object name query template. * This version first translates the objectName template for defined values in provided configuration. This * is explicitly built for hierarchical objectName models to find the children of parents. * * @param objectNameQueryTemplate string of form "a:b=%c%,d=e,f=%g%,h={myParentsH}" * @param parentConfiguration the config holding the matched values for the object name key property variables */ public ObjectNameQueryUtility(String objectNameQueryTemplate, Configuration parentConfiguration) { Pattern p = Pattern.compile("\\{([^\\{\\}]*)\\}"); Matcher m = p.matcher(objectNameQueryTemplate); while (m.find()) { String objectNameKeyPropVariableName = m.group(1); String value = parentConfiguration.getSimple(objectNameKeyPropVariableName).getStringValue(); objectNameQueryTemplate = objectNameQueryTemplate.replaceAll("\\{" + objectNameKeyPropVariableName + "\\}", value); } this.queryTemplate = objectNameQueryTemplate; buildMatchMap(this.queryTemplate); } /** * Set values for properties from an objectName. These are first translated into the "real" keys. e.g. foo:bar=%baz% * In this case, the property of the bar objectName property will be set into the properties keyed against "baz" * which is the real key. * * @param keyProperties properties from the found objectName to apply * * @return true if the objectName properties contained all variable properties or false if some where missing (e.g. * foo:A=%a%,B=%b% is the queryTemplate but objectName found is foo:A=alpha) */ public boolean setMatchedKeyValues(Map<String, String> keyProperties) { for (String key : keyProperties.keySet()) { if (this.variableProperties.containsKey(key)) { String realKey = this.variableProperties.get(key); String value = keyProperties.get(key); this.variableValues.put(realKey, value); } } // Return true if there are key properties for every variable in the template and false otherwise return (keyProperties.keySet().containsAll(this.variableProperties.keySet())); } /** * Format a message with {<key>} formatted replacement keys. * * @param message the message to format * * @return the formatted text with variables replaced */ public String formatMessage(String message) { for (String key : variableValues.keySet()) { message = message.replaceAll("\\{" + key + "\\}", this.variableValues.get(key)); } return message; } /** * Clears out variables so that a new found bean can be used against the same utility object again. */ public void resetVariables() { this.variableValues.clear(); } public String getQueryTemplate() { return queryTemplate; } public Map<String, String> getVariableProperties() { return variableProperties; } public Map<String, String> getVariableValues() { return variableValues; } public String getTranslatedQuery() { return translatedQuery; } /** * Detects the mapped variable object name properties and the resulting object name query that can find matching * beans. * * @param objectNameQueryTemplate a template of the form foo:bar=%baz% */ private void buildMatchMap(String objectNameQueryTemplate) { StringBuilder queryBuilder = new StringBuilder(); Pattern p = Pattern.compile("^([^:]*\\:)(.*)$"); Matcher m = p.matcher(objectNameQueryTemplate); if (!m.find()) { assert false : "ObjectName did not match expected regular expression: " + objectNameQueryTemplate; } queryBuilder.append(m.group(1)); String keyProps = m.group(2); String[] keys = keyProps.split(","); boolean firstVar = true; boolean onlyVar = true; for (String key : keys) { Pattern p2 = Pattern.compile("^([^=]*)=\\%(.*)\\%$"); Matcher m2 = p2.matcher(key); if (m2.find()) { variableProperties.put(m2.group(1), m2.group(2)); } else { Pattern p3 = Pattern.compile("^([^=]*)=(.*)$"); Matcher m3 = p3.matcher(key); if (m3.find()) { nonVariableProperties.add(m3.group(1)); } onlyVar = false; if (firstVar) { firstVar = false; } else { queryBuilder.append(","); } queryBuilder.append(key); } } if (variableProperties.size() > 0) { if (!onlyVar) { queryBuilder.append(","); } queryBuilder.append("*"); } this.translatedQuery = queryBuilder.toString(); } public boolean isContainsExtraKeyProperties(Set<String> strings) { for (String key : strings) { if (!nonVariableProperties.contains(key) && !variableProperties.containsKey(key)) { return true; } } return false; } }