/** * The MIT License * Copyright © 2010 JmxTrans team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.googlecode.jmxtrans.model.naming; import com.googlecode.jmxtrans.model.NamingStrategy; import com.googlecode.jmxtrans.model.Result; import com.googlecode.jmxtrans.model.naming.typename.TypeNameValue; import lombok.EqualsAndHashCode; import org.apache.commons.jexl2.Expression; import org.apache.commons.jexl2.JexlContext; import org.apache.commons.jexl2.JexlEngine; import org.apache.commons.jexl2.JexlException; import org.apache.commons.jexl2.MapContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Map; /** * Naming strategy which uses an JEXL expression to format the name from the result, its class name, attribute name, * and more. Note the resulting name can be used for any of a number of purposes. For example, with OpenTSDB it could * be the metric name or a tag name. * <p/> * In the expression, all of the following may be used: * <b>Variables</b> * <dl> * <dt>alias</dt> * <dd>the classname alias of the MBean.</dd> * <dt>attribute</dt> * <dd>the name of the attribute of the MBean queried.</dd> * <dt>class</dt> * <dd>the effective classname of the MBean (uses #alias is not null, otherwise uses #realclass).</dd> * <dt>realclass</dt> * <dd>the class name of the MBean.</dd> * <dt>result</dt> * <dd>the full Result object.</dd> * </dl> */ @EqualsAndHashCode public class JexlNamingStrategy implements NamingStrategy { private static final Logger LOG = LoggerFactory.getLogger(JexlNamingStrategy.class); public static final String DEFAULT_EXPRESSION = "class + \".\" + attribute"; public static final String VAR_CLASSNAME = "realclass"; public static final String VAR_ATTRIBUTE_NAME = "attribute"; public static final String VAR_CLASSNAME_ALIAS = "alias"; public static final String VAR_EFFECTIVE_CLASSNAME = "class"; public static final String VAR_TYPENAME = "typename"; public static final String VAR_RESULT = "result"; protected JexlEngine jexl; protected Expression parsedExpr; /** * Create a new naming strategy using an JEXL expression and the default expression. */ public JexlNamingStrategy() throws JexlException { jexl = new JexlEngine(); this.parsedExpr = jexl.createExpression(DEFAULT_EXPRESSION); } /** * Create a new naming strategy using an JEXL expression and the given expression. * * @param expr - the JEXL expression to use to create names. */ public JexlNamingStrategy(String expr) throws JexlException { jexl = new JexlEngine(); this.parsedExpr = jexl.createExpression(expr); } /** * Format the name for the given result. * * @param result - the result of a JMX query. * @return String - the formatted string resulting from the expression, or null if the formatting fails. */ @Override public String formatName(Result result) { String formatted; JexlContext context = new MapContext(); this.populateContext(context, result); try { formatted = (String) this.parsedExpr.evaluate(context); } catch (JexlException jexlExc) { LOG.error("error applying JEXL expression to query results", jexlExc); formatted = null; } return formatted; } public void setExpression(String expr) throws JexlException { this.parsedExpr = this.jexl.createExpression(expr); } /** * Populate the context with values from the result. * * @param context - the expression context used when evaluating JEXL expressions. * @param result - the result of a JMX query. */ protected void populateContext(JexlContext context, Result result) { context.set(VAR_CLASSNAME, result.getClassName()); context.set(VAR_ATTRIBUTE_NAME, result.getAttributeName()); context.set(VAR_CLASSNAME_ALIAS, result.getKeyAlias()); Map<String, String> typeNameMap = TypeNameValue.extractMap(result.getTypeName()); context.set(VAR_TYPENAME, typeNameMap); String effectiveClassname = result.getKeyAlias(); if (effectiveClassname == null) { effectiveClassname = result.getClassName(); } context.set(VAR_EFFECTIVE_CLASSNAME, effectiveClassname); context.set(VAR_RESULT, result); } }