package com.googlecode.jmxtrans.model.naming;

import com.googlecode.jmxtrans.model.NamingStrategy;
import com.googlecode.jmxtrans.model.Result;

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;

/**
 * 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.
 *
 * In the expression, all of the following may be used:
 *      Variables
 *      alias - the classname alias of the MBean.
 *      attribute - the name of the attribute of the MBean queried.
 *      class - the effective classname of the MBean (uses #alias is not null, otherwise uses #realclass).
 *      realclass - the class name of the MBean.
 *      result - the full Result object.
 */
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.getClassNameAlias());
        context.set(VAR__TYPENAME, result.getTypeName());

        String effectiveClassname = result.getClassNameAlias();
        if ( effectiveClassname == null ) {
            effectiveClassname = result.getClassName();
        }
        context.set(VAR__EFFECTIVE_CLASSNAME, effectiveClassname);

        context.set(VAR__RESULT, result);
    }
}

@@ -137,16 +137,85 @@
 .Result;
+%0Aimport com.googlecode.jmxtrans.util.JmxUtils;%0A%0Aimport java.util.Map;
 %0A%0Aimport
@@ -1713,24 +1713,90 @@
 %22typename%22;%0A
+    public static final String  VAR__TYPENAMEMAP = %22typenamemap%22;%0A
     public s
@@ -3903,24 +3903,171 @@
 peName());%0A%0A
+        Map%3CString, String%3E typeNameMap = JmxUtils.getTypeNameValueMap(result.getTypeName());%0A        context.set(VAR__TYPENAMEMAP, typeNameMap);%0A%0A
         Stri

Make typeName available as a map to jexl