org.flockdata.transform.ExpressionHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.flockdata.transform.ExpressionHelper.java

Source

/*
 *
 *  Copyright (c) 2012-2016 "FlockData LLC"
 *
 *  This file is part of FlockData.
 *
 *  FlockData is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  FlockData 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 for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with FlockData.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.flockdata.transform;

import org.apache.commons.lang3.math.NumberUtils;
import org.flockdata.profile.model.ContentModel;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.expression.ExpressionException;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

/**
 * Encapsulate methods to evaluate transformational expressions
 * <p>
 * @author mholdsworth
 * @since 30/07/2015
 */
public class ExpressionHelper {

    private static final ExpressionParser parser = new SpelExpressionParser();

    private static final Logger logger = LoggerFactory.getLogger(ExpressionHelper.class);

    public static Object getValue(Object value, ColumnDefinition colDef) {

        //        context.setVariable("colDef",colDef);
        if (value == null || value.equals("null"))
            return null;
        else if (NumberUtils.isNumber(value.toString())) {
            if (colDef != null && colDef.getDataType() != null && colDef.getDataType().equalsIgnoreCase("string"))
                return String.valueOf(value);
            else
                return NumberUtils.createNumber(value.toString());
        } else {
            return value.toString().trim();
        }
    }

    public static String getValue(Map<String, Object> row, ColumnDefinition.ExpressionType expCol,
            ColumnDefinition colDef, Object defaultValue) {
        if (colDef == null)
            return getNullSafeDefault(defaultValue, null);

        String expression = colDef.getExpression(expCol);
        if (expression == null) {
            return getNullSafeDefault(defaultValue, colDef);
        }
        Object result = getValue(row, expression);
        if (result == null)
            return getNullSafeDefault(defaultValue, colDef);
        return result.toString().trim();

    }

    public static String getValue(Map<String, Object> row, String expression, ColumnDefinition colDef,
            Object defaultValue) {
        return getValue(row, expression, colDef, defaultValue, null);
    }

    /**
     * Returns a value based on the expression. To evaluate a column, use #data['col'] syntax
     *
     * @param row          Existing transformed data
     * @param expression   to evaluate
     * @param colDef       options about the transformation
     * @param defaultValue what to return if expression results in null
     * @return calculated value or defaultValue
     */
    public static String getValue(Map<String, Object> row, String expression, ColumnDefinition colDef,
            Object defaultValue, ContentModel contentModel) {
        if (colDef == null)
            return getNullSafeDefault(defaultValue, null);

        Object result = (expression == null || expression.length() == 0 ? null
                : evaluateExpression(contentModel, row, expression));
        if (result == null)
            return getNullSafeDefault(defaultValue, colDef);
        return result.toString().trim();

    }

    public static Object getValue(Map<String, Object> row, String expression) {
        Object result;
        try {
            if (row.containsKey(expression))
                result = row.get(expression); // Pull value straight from the row
            else
                result = evaluateExpression(row, expression);
        } catch (ExpressionException | StringIndexOutOfBoundsException e) {
            logger.trace("Expression error parsing [" + expression + "]. Returning null");
            result = null;
        }
        return result;
    }

    static Object evaluateExpression(Map<String, Object> row, String expression) {
        return evaluateExpression(null, row, expression);
    }

    private static Object evaluateExpression(ContentModel contentModel, Map<String, Object> row,
            String expression) {
        if (expression == null)
            return null;

        StandardEvaluationContext context = new StandardEvaluationContext(row);
        setContextVariables(contentModel, row, context);

        try {
            return parser.parseExpression(expression).getValue(context);
        } catch (Exception e) {
            logger.debug(
                    String.format("Error evaluating expression [%s], message was %s ", expression, e.getMessage()));
            throw (e);
        }
    }

    private static void setContextVariables(ContentModel contentModel, Map<String, Object> row,
            StandardEvaluationContext context) {
        if (contentModel != null)
            context.setVariable("model", contentModel);
        //        for (String s : row.keySet()) {
        //            context.setVariable(s, row.get(s));
        //        }
    }

    private static String getNullSafeDefault(Object defaultValue, ColumnDefinition colDef) {
        if (defaultValue == null || defaultValue.equals("")) {
            // May be a literal value to set the property to
            if (colDef == null)
                return null;
            return colDef.getNullOrEmpty();
        }
        return defaultValue.toString().trim();
    }

    public static Long parseDate(ColumnDefinition colDef, String value) {
        if (value == null || value.equals(""))
            return null;
        if (colDef.isDateEpoc()) {
            return Long.parseLong(value) * 1000;
        }

        if (colDef.getDateFormat() == null || colDef.getDateFormat().equalsIgnoreCase("automatic")) {
            try {
                return Date.parse(value);
            } catch (IllegalArgumentException e) {
                // Try other formats
            }
        }
        if (colDef.getDateFormat() != null && colDef.getDateFormat().equalsIgnoreCase("timestamp")) {
            try {
                return Timestamp.valueOf(value).getTime();
            } catch (IllegalArgumentException e) {
                // attempt other conversions
            }
        }

        if (NumberUtils.isDigits(value)) // plain old java millis
            return Long.parseLong(value);

        // Custom Date formats
        String tz = colDef.getTimeZone();
        if (tz == null)
            tz = TimeZone.getDefault().getID();

        try {

            // Try first as DateTime
            return new SimpleDateFormat(colDef.getDateFormat()).parse(value).getTime();
        } catch (DateTimeParseException | IllegalArgumentException | ParseException e) {
            // Just a plain date
            DateTimeFormatter pattern = DateTimeFormatter.ofPattern(colDef.getDateFormat(), Locale.ENGLISH);
            LocalDate date = LocalDate.parse(value, pattern);
            return new DateTime(date.toString(), DateTimeZone.forID(tz)).getMillis();
        }
    }
}