it.geosolutions.opensdi2.workflow.transform.spel.SpelTransformer.java Source code

Java tutorial

Introduction

Here is the source code for it.geosolutions.opensdi2.workflow.transform.spel.SpelTransformer.java

Source

/*
 *  OpenSDI Manager 2
 *  Copyright (C) 2014 GeoSolutions S.A.S.
 *  http://www.geo-solutions.it
 *
 *  GPLv3 + Classpath exception
 *
 *  This program 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.
 *
 *  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 for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package it.geosolutions.opensdi2.workflow.transform.spel;

import it.geosolutions.opensdi2.workflow.transform.PreBuilder;
import it.geosolutions.opensdi2.workflow.transform.Transformer;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.expression.Expression;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

/**
 * The <SpelTransformer> is a <Transformer> that converts objects into
 * other using a map of rules and the Spel Expressions.
 * See {@linktourl http://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/expressions.html}
 * 
 * The "rules" object (a <Map> of <String>,<String> that represents the
 * **outputExpression** and the **inputExpression**) to 
 * produce the result.
 * In both **outputExpression** and **inputExpression** you can use 
 * spEL language to create the input value from input object and 
 * output attribute to write to.
 * Basically the output object properties (identified by the outputExpression)
 * will be populated, using the transform method, with values generated
 * from the outputExpressions, using the argument of the tranform object as 
 * context. You can Set <PropertyAccessor> objects for input and output objects
 * Example: 
 * input object :
 * {
 *    att1:1,
 *  att2:"attribute2"
 * }
 * rules:
 * {
 *    "b1.nestedobj" : "'hello'",
 *  "b2": "att1 +5",
 *  "b3": "att2 + ' other stuff'"
 * }
 * result:
 * {
 *    b1:{
 *    nestedobj : "hello",
 *  }
 *  b2: 6,
 *  b3: "attribute2 other stuff"
 * }
 * or something like that, depending of the output object
 * @author Lorenzo Natali
 *
 */
public class SpelTransformer<SOURCETYPE, DESTTYPE> implements Transformer<SOURCETYPE, DESTTYPE> {
    public static SpelExpressionParser expressionParser = new SpelExpressionParser();

    private Map<String, String> rules;
    private List<PropertyAccessor> inputaccessors = new ArrayList<PropertyAccessor>();
    private List<PropertyAccessor> outputaccessors = new ArrayList<PropertyAccessor>();
    private PreBuilder<DESTTYPE> outputPreBuilder;

    private DESTTYPE outputObject;

    /**
     * get the output object
     * @return
     */
    public DESTTYPE getOutputObject() {
        return outputObject;
    }

    /**
     * Set the output object
     * @param outputObject
     */
    public void setOutputObject(DESTTYPE outputObject) {
        this.outputObject = outputObject;
    }

    /**
     * Get a builder to initialize the output object
     * @return
     */
    public PreBuilder<DESTTYPE> getOutputPreBuilder() {
        return outputPreBuilder;
    }

    /**
     * Set a builder to initialize the output object
     * @param outputPreBuilder
     */
    public void setOutputPreBuilder(PreBuilder<DESTTYPE> outputPreBuilder) {
        this.outputPreBuilder = outputPreBuilder;
    }

    /**
     * Set the rules map
     * @param map a map of "outExpression","inputExpression"
     */
    public void setRules(Map<String, String> map) {
        this.rules = map;
    }

    /**
     * get rules map
     * @return the map of rules
     */
    public Map<String, String> getRules() {
        return rules;
    }

    /**
     * Get the rules map
     * @return
     */
    public List<PropertyAccessor> getInputaccessors() {
        return inputaccessors;
    }

    /**
     * Set <PropertyAccessors> for input object
     * @param inputaccessors
     */
    public void setInputaccessors(List<PropertyAccessor> inputaccessors) {
        this.inputaccessors = inputaccessors;
    }

    /**
     * Get <PropertyAccessors> for output object
     * @return
     */
    public List<PropertyAccessor> getOutputaccessors() {
        return outputaccessors;
    }

    /**
     * Set <PropertyAccessors> for output object
     * @param inputaccessors
     */
    public void setOutputaccessors(List<PropertyAccessor> outputaccessors) {
        this.outputaccessors = outputaccessors;
    }

    @Override
    public DESTTYPE transform(SOURCETYPE source) throws IllegalArgumentException {

        //create the output object
        DESTTYPE output = null;
        if (outputObject == null && outputPreBuilder != null) {
            output = outputPreBuilder.build(rules);
        } else if (outputPreBuilder != null) {
            output = outputPreBuilder.build(outputObject, rules);
        } else if (outputObject != null) {
            output = outputObject;
        } else {
            throw new IllegalArgumentException("no outputObject or outPrebuilder provided");
        }

        //create evaluation Context
        StandardEvaluationContext inputEvaluationContext = new StandardEvaluationContext(source);
        StandardEvaluationContext outputevaluationContext = new StandardEvaluationContext(output);
        //set property accessors for input and output
        inputEvaluationContext.setPropertyAccessors(inputaccessors);
        outputevaluationContext.setPropertyAccessors(outputaccessors);
        if (rules != null) {
            Set<String> attributes = rules.keySet();

            //parse rules to create output
            for (String attribute : attributes) {
                String expression = rules.get(attribute);
                //create expressions for in and out
                Expression conversionExpression = expressionParser.parseExpression(expression);
                Expression outputAttribute = expressionParser.parseExpression(attribute);
                //evaluate input value
                Object value = conversionExpression.getValue(inputEvaluationContext); //TODO create a second evaulationContext for output
                //set the attribute value using the output context
                outputAttribute.setValue(outputevaluationContext, value);
            }
        }
        return output;

    }

}