All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bazaarvoice.jolt.modifier.spec.ModifierLeafSpec Maven / Gradle / Ivy

There is a newer version: 0.1.8
Show newest version
/*
 * Copyright 2013 Bazaarvoice, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.bazaarvoice.jolt.modifier.spec;

import com.bazaarvoice.jolt.common.Optional;
import com.bazaarvoice.jolt.common.SpecStringParser;
import com.bazaarvoice.jolt.common.tree.MatchedElement;
import com.bazaarvoice.jolt.common.tree.WalkedPath;
import com.bazaarvoice.jolt.modifier.OpMode;
import com.bazaarvoice.jolt.modifier.TemplatrSpecBuilder;
import com.bazaarvoice.jolt.modifier.function.Function;
import com.bazaarvoice.jolt.modifier.function.FunctionArg;
import com.bazaarvoice.jolt.modifier.function.FunctionEvaluator;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;

@SuppressWarnings( "deprecated" )
public class ModifierLeafSpec extends ModifierSpec {

    private final List functionEvaluatorList;

    @SuppressWarnings( "unchecked" )
    public ModifierLeafSpec( final String rawJsonKey, Object rhsObj, final OpMode opMode, final Map functionsMap ) {
        super(rawJsonKey, opMode);
        functionEvaluatorList = new LinkedList<>(  );

        FunctionEvaluator functionEvaluator;

        // "key": "expression1"
        if ( (rhsObj instanceof String) ) {
            functionEvaluator = buildFunctionEvaluator( (String) rhsObj, functionsMap );
            functionEvaluatorList.add( functionEvaluator );
        }
        // "key": ["expression1", "expression2", "expression3"]
        else if(rhsObj instanceof List && ((List)rhsObj).size() > 0) {
            List rhsList = (List) rhsObj;
            for(Object rhs: rhsList) {
                if(rhs instanceof String) {
                    functionEvaluator = buildFunctionEvaluator( rhs.toString(), functionsMap );
                    functionEvaluatorList.add( functionEvaluator );
                }
                else {
                    functionEvaluator = FunctionEvaluator.forArgEvaluation( FunctionArg.forLiteral( rhs, false ) );
                    functionEvaluatorList.add( functionEvaluator );
                }
            }
        }
        // "key": anyObjectOrLiteral --- just set as-is
        else {
            functionEvaluator = FunctionEvaluator.forArgEvaluation( FunctionArg.forLiteral( rhsObj, false ) );
            functionEvaluatorList.add( functionEvaluator );
        }
    }

    @Override
    public void applyElement( final String inputKey, final Optional inputOptional, final MatchedElement thisLevel, final WalkedPath walkedPath, final Map context ) {

        Object parent = walkedPath.lastElement().getTreeRef();

        walkedPath.add( inputOptional.get(), thisLevel );

        Optional valueOptional = getFirstAvailable( functionEvaluatorList, inputOptional, walkedPath, context );

        if(valueOptional.isPresent()) {
            setData( parent, thisLevel, valueOptional.get(), opMode );
        }

        walkedPath.removeLast();
    }

    private static FunctionEvaluator buildFunctionEvaluator( final String rhs, final Map functionsMap ) {
        final FunctionEvaluator functionEvaluator;
        // "key": "@0" --- evaluate expression then set
        if(!rhs.startsWith( TemplatrSpecBuilder.FUNCTION )) {
            return FunctionEvaluator.forArgEvaluation( constructSingleArg( rhs, false ) );
        }
        else {
            String functionName;
            // "key": "=abs" --- call function with current value then set output if present
            if ( !rhs.contains( "(" ) && !rhs.endsWith( ")" ) ) {
                functionName = rhs.substring( TemplatrSpecBuilder.FUNCTION.length() );
                return FunctionEvaluator.forFunctionEvaluation( functionsMap.get( functionName ) );
            }
            // "key": "=abs(@(1,&0))" --- evaluate expression then call function with
            //                            expression-output, then set output if present
            else {
                String fnString = rhs.substring( TemplatrSpecBuilder.FUNCTION.length() );
                List fnArgs = SpecStringParser.parseFunctionArgs( fnString );
                functionName = fnArgs.remove( 0 );
                functionEvaluator = FunctionEvaluator.forFunctionEvaluation( functionsMap.get( functionName ), constructArgs( fnArgs ) );
            }
        }
        return functionEvaluator;
    }

    private static Optional getFirstAvailable(List functionEvaluatorList, Optional inputOptional, WalkedPath walkedPath, Map context) {
        Optional valueOptional = Optional.empty();
        for(FunctionEvaluator functionEvaluator: functionEvaluatorList) {
            try {
                valueOptional = functionEvaluator.evaluate( inputOptional, walkedPath, context );
                if(valueOptional.isPresent()) {
                    return valueOptional;
                }
            }
            catch(Exception ignored) {}
        }
        return valueOptional;
    }

    private static FunctionArg[] constructArgs( List argsList ) {
        FunctionArg[] argsArray = new FunctionArg[argsList.size()];
        for(int i=0; i