Java tutorial
/* * Copyright 2016-2018 the original author or authors. * * 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.creactiviti.piper.core.task; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.stream.Collectors; import java.util.stream.IntStream; import org.apache.commons.beanutils.ConvertUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.expression.AccessException; import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.MethodExecutor; import org.springframework.expression.MethodResolver; import org.springframework.expression.TypedValue; import org.springframework.expression.common.TemplateParserContext; import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import com.creactiviti.piper.core.context.Context; /** * a {@link TaskEvaluator} implemenation which is based on * Spring Expression Language for resolving expressions. * * @author Arik Cohen * @since Mar 31, 2017 */ public class SpelTaskEvaluator implements TaskEvaluator { private final ExpressionParser parser = new SpelExpressionParser(); private static final String PREFIX = "${"; private static final String SUFFIX = "}"; private Logger logger = LoggerFactory.getLogger(getClass()); @Override public TaskExecution evaluate(TaskExecution aJobTask, Context aContext) { Map<String, Object> map = aJobTask.asMap(); Map<String, Object> newMap = evaluateInternal(map, aContext); return SimpleTaskExecution.createFromMap(newMap); } private Map<String, Object> evaluateInternal(Map<String, Object> aMap, Context aContext) { Map<String, Object> newMap = new HashMap<String, Object>(); for (Entry<String, Object> entry : aMap.entrySet()) { newMap.put(entry.getKey(), evaluate(entry.getValue(), aContext)); } return newMap; } private Object evaluate(Object aValue, Context aContext) { StandardEvaluationContext context = createEvaluationContext(aContext); if (aValue instanceof String) { Expression expression = parser.parseExpression((String) aValue, new TemplateParserContext(PREFIX, SUFFIX)); try { return (expression.getValue(context)); } catch (SpelEvaluationException e) { logger.debug(e.getMessage()); return aValue; } } else if (aValue instanceof List) { List<Object> evaluatedlist = new ArrayList<>(); List<Object> list = (List<Object>) aValue; for (Object item : list) { evaluatedlist.add(evaluate(item, aContext)); } return evaluatedlist; } else if (aValue instanceof Map) { return evaluateInternal((Map<String, Object>) aValue, aContext); } return aValue; } private StandardEvaluationContext createEvaluationContext(Context aContext) { StandardEvaluationContext context = new StandardEvaluationContext(aContext); context.addPropertyAccessor(new MapPropertyAccessor()); context.addMethodResolver(methodResolver()); return context; } private MethodResolver methodResolver() { return (ctx, target, name, args) -> { switch (name) { case "systemProperty": return this::systemProperty; case "range": return range(); case "boolean": return cast(Boolean.class); case "byte": return cast(Byte.class); case "char": return cast(Character.class); case "short": return cast(Short.class); case "int": return cast(Integer.class); case "long": return cast(Long.class); case "float": return cast(Float.class); case "double": return cast(Double.class); case "join": return join(); case "concat": return concat(); case "flatten": return flatten(); default: return null; } }; } private TypedValue systemProperty(EvaluationContext aContext, Object aTarget, Object... aArgs) throws AccessException { return new TypedValue(System.getProperty((String) aArgs[0])); } private MethodExecutor range() { return (ctx, target, args) -> { List<Integer> value = IntStream.rangeClosed((int) args[0], (int) args[1]).boxed() .collect(Collectors.toList()); return new TypedValue(value); }; } private <T> MethodExecutor cast(Class<T> type) { return (ctx, target, args) -> { T value = type.cast(ConvertUtils.convert(args[0], type)); return new TypedValue(value); }; } private <T> MethodExecutor join() { return (ctx, target, args) -> { String separator = (String) args[0]; List<T> values = (List<T>) args[1]; String str = values.stream().map(String::valueOf).collect(Collectors.joining(separator)); return new TypedValue(str); }; } private <T> MethodExecutor concat() { return (ctx, target, args) -> { List<T> l1 = (List<T>) args[0]; List<T> l2 = (List<T>) args[1]; List<T> joined = new ArrayList<T>(l1.size() + l2.size()); joined.addAll(l1); joined.addAll(l2); return new TypedValue(joined); }; } private <T> MethodExecutor flatten() { return (ctx, target, args) -> { List<List<T>> list = (List<List<T>>) args[0]; List<T> flat = list.stream().flatMap(List::stream).collect(Collectors.toList()); return new TypedValue(flat); }; } }