Skip to content

Commit

Permalink
Merge pull request #142 from powerflows/Add-support-for-providing-cus…
Browse files Browse the repository at this point in the history
…tom-functions-in-Expressions

Added support for providing custom functions in Expressions.
  • Loading branch information
stlhrt authored Jan 27, 2019
2 parents 8695bba + 45c4818 commit 60a8dcc
Show file tree
Hide file tree
Showing 33 changed files with 910 additions and 207 deletions.
13 changes: 7 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@
<scope>provided</scope>
</dependency>

<!-- Groovy -->
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>${groovy.version}</version>
</dependency>

<!-- Tests -->
<dependency>
<groupId>org.spockframework</groupId>
Expand All @@ -121,12 +128,6 @@
<version>${cglib.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>${groovy.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,40 @@
package org.powerflows.dmn.engine.configuration;


import lombok.Setter;
import lombok.experimental.Accessors;
import org.powerflows.dmn.engine.DecisionEngine;
import org.powerflows.dmn.engine.DefaultDecisionEngine;
import org.powerflows.dmn.engine.evaluator.decision.DecisionEvaluator;
import org.powerflows.dmn.engine.evaluator.entry.InputEntryEvaluator;
import org.powerflows.dmn.engine.evaluator.entry.OutputEntryEvaluator;
import org.powerflows.dmn.engine.evaluator.entry.mode.provider.EvaluationModeProviderFactory;
import org.powerflows.dmn.engine.evaluator.expression.provider.ExpressionEvaluationProviderFactory;
import org.powerflows.dmn.engine.evaluator.expression.script.DefaultScriptEngineProvider;
import org.powerflows.dmn.engine.evaluator.expression.script.ScriptEngineProvider;
import org.powerflows.dmn.engine.evaluator.expression.provider.DefaultExpressionEvaluationProviderFactory;
import org.powerflows.dmn.engine.evaluator.expression.provider.ExpressionEvaluationConfiguration;
import org.powerflows.dmn.engine.evaluator.expression.provider.binding.MethodBinding;
import org.powerflows.dmn.engine.evaluator.rule.RuleEvaluator;
import org.powerflows.dmn.engine.evaluator.type.converter.TypeConverterFactory;

import javax.script.ScriptEngineManager;
import java.util.Collections;
import java.util.List;

@Accessors(chain = true, fluent = true)
public class DefaultDecisionEngineConfiguration implements DecisionEngineConfiguration {

@Setter
private List<MethodBinding> methodBindings = Collections.emptyList();
private ExpressionEvaluationConfiguration configuration;
private DecisionEvaluator decisionEvaluator;
private RuleEvaluator ruleEvaluator;
private EvaluationModeProviderFactory evaluationModeProviderFactory;
private InputEntryEvaluator inputEntryEvaluator;
private OutputEntryEvaluator outputEntryEvaluator;
private ScriptEngineProvider scriptEngineProvider;
private ExpressionEvaluationProviderFactory expressionEvaluationProviderFactory;
private DefaultExpressionEvaluationProviderFactory expressionEvaluationProviderFactory;
private TypeConverterFactory typeConverterFactory;

@Override
public DecisionEngine configure() {
initScriptEngineProvider();
initExpressionEvaluation();
initEvaluationProviderFactory();
initTypeConverterFactory();
initEvaluationModeProviderFactory();
Expand All @@ -56,18 +62,20 @@ public DecisionEngine configure() {
return new DefaultDecisionEngine(decisionEvaluator);
}

private void initExpressionEvaluation() {
configuration = ExpressionEvaluationConfiguration.builder()
.methodBinding(methodBindings)
.build();
}

private void initEvaluationProviderFactory() {
expressionEvaluationProviderFactory = new ExpressionEvaluationProviderFactory(scriptEngineProvider);
expressionEvaluationProviderFactory = new DefaultExpressionEvaluationProviderFactory(configuration);
}

private void initTypeConverterFactory() {
typeConverterFactory = new TypeConverterFactory();
}

private void initScriptEngineProvider() {
scriptEngineProvider = new DefaultScriptEngineProvider(new ScriptEngineManager());
}

private void initEvaluationModeProviderFactory() {
evaluationModeProviderFactory = new EvaluationModeProviderFactory();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import org.powerflows.dmn.engine.evaluator.entry.mode.provider.EvaluationModeProvider;
import org.powerflows.dmn.engine.evaluator.entry.mode.provider.EvaluationModeProviderFactory;
import org.powerflows.dmn.engine.evaluator.expression.provider.ExpressionEvaluationProvider;
import org.powerflows.dmn.engine.evaluator.expression.provider.ExpressionEvaluationProviderFactory;
import org.powerflows.dmn.engine.evaluator.expression.provider.DefaultExpressionEvaluationProviderFactory;
import org.powerflows.dmn.engine.evaluator.type.converter.TypeConverter;
import org.powerflows.dmn.engine.evaluator.type.converter.TypeConverterFactory;
import org.powerflows.dmn.engine.evaluator.type.value.SpecifiedTypeValue;
Expand All @@ -36,12 +36,12 @@
@Slf4j
public class InputEntryEvaluator {

private final ExpressionEvaluationProviderFactory expressionEvaluationProviderFactory;
private final DefaultExpressionEvaluationProviderFactory expressionEvaluationProviderFactory;
private final TypeConverterFactory typeConverterFactory;
private final EvaluationModeProviderFactory evaluationModeProviderFactory;


public InputEntryEvaluator(final ExpressionEvaluationProviderFactory expressionEvaluationProviderFactory,
public InputEntryEvaluator(final DefaultExpressionEvaluationProviderFactory expressionEvaluationProviderFactory,
final TypeConverterFactory typeConverterFactory,
final EvaluationModeProviderFactory evaluationModeProviderFactory) {
this.expressionEvaluationProviderFactory = expressionEvaluationProviderFactory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import lombok.extern.slf4j.Slf4j;
import org.powerflows.dmn.engine.evaluator.context.EvaluationContext;
import org.powerflows.dmn.engine.evaluator.expression.provider.ExpressionEvaluationProvider;
import org.powerflows.dmn.engine.evaluator.expression.provider.ExpressionEvaluationProviderFactory;
import org.powerflows.dmn.engine.evaluator.expression.provider.DefaultExpressionEvaluationProviderFactory;
import org.powerflows.dmn.engine.evaluator.type.converter.TypeConverter;
import org.powerflows.dmn.engine.evaluator.type.converter.TypeConverterFactory;
import org.powerflows.dmn.engine.model.decision.field.Output;
Expand All @@ -32,10 +32,10 @@
@Slf4j
public class OutputEntryEvaluator {

private final ExpressionEvaluationProviderFactory expressionEvaluationProviderFactory;
private final DefaultExpressionEvaluationProviderFactory expressionEvaluationProviderFactory;
private final TypeConverterFactory typeConverterFactory;

public OutputEntryEvaluator(ExpressionEvaluationProviderFactory expressionEvaluationProviderFactory,
public OutputEntryEvaluator(DefaultExpressionEvaluationProviderFactory expressionEvaluationProviderFactory,
final TypeConverterFactory typeConverterFactory) {
this.expressionEvaluationProviderFactory = expressionEvaluationProviderFactory;
this.typeConverterFactory = typeConverterFactory;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2018-present PowerFlows.org - all rights reserved.
*
* 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 org.powerflows.dmn.engine.evaluator.expression.provider;

import lombok.extern.slf4j.Slf4j;
import org.powerflows.dmn.engine.model.decision.expression.ExpressionType;

import java.util.EnumMap;
import java.util.Optional;
import java.util.ServiceLoader;

@Slf4j
public class DefaultExpressionEvaluationProviderFactory {

private static final ServiceLoader<ExpressionEvaluationProviderFactory> serviceLoader = ServiceLoader.load(ExpressionEvaluationProviderFactory.class);

private final EnumMap<ExpressionType, ExpressionEvaluationProviderFactory> factories = new EnumMap<>(ExpressionType.class);

private final EnumMap<ExpressionType, ExpressionEvaluationProvider> providers = new EnumMap<>(ExpressionType.class);
private final ExpressionEvaluationConfiguration configuration;


public DefaultExpressionEvaluationProviderFactory() {
this(ExpressionEvaluationConfiguration.simpleConfiguration());
}

public DefaultExpressionEvaluationProviderFactory(final ExpressionEvaluationConfiguration configuration) {
this.configuration = configuration;
serviceLoader.forEach(provider ->
provider.supportedExpressionTypes()
.forEach(type -> {
log.debug("Found ExpressionEvaluationProvider for type {} - {}", type, provider);
factories.put(type, provider);
}
)
);
}

public ExpressionEvaluationProvider getInstance(final ExpressionType expressionType) {
final ExpressionEvaluationProvider expressionEvaluationProvider = providers.computeIfAbsent(expressionType, key -> Optional
.ofNullable(factories.get(key))
.map(factory -> factory.createProvider(configuration))
.orElse(null)
);

if (expressionEvaluationProvider == null) {
throw new IllegalArgumentException("Unknown expression type " + expressionType);
}

return expressionEvaluationProvider;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2018-present PowerFlows.org - all rights reserved.
*
* 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 org.powerflows.dmn.engine.evaluator.expression.provider;

import lombok.Builder;
import lombok.Getter;
import org.powerflows.dmn.engine.evaluator.expression.provider.binding.MethodBinding;

import javax.script.ScriptEngineManager;
import java.util.Collections;
import java.util.List;

@Getter
@Builder
public class ExpressionEvaluationConfiguration {

private final List<MethodBinding> methodBinding;
private final ScriptEngineManager scriptEngineManager;

private ExpressionEvaluationConfiguration(final List<MethodBinding> methodBinding, final ScriptEngineManager scriptEngineManager) {
this.methodBinding = methodBinding == null ? Collections.emptyList() : methodBinding;
this.scriptEngineManager = scriptEngineManager == null ? new ScriptEngineManager() : scriptEngineManager;
}

public static ExpressionEvaluationConfiguration simpleConfiguration() {
return ExpressionEvaluationConfiguration.builder().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.powerflows.dmn.engine.evaluator.expression.provider;

import org.powerflows.dmn.engine.evaluator.expression.script.ScriptEngineProvider;
import org.powerflows.dmn.engine.model.decision.expression.ExpressionType;

import java.util.EnumMap;

public class ExpressionEvaluationProviderFactory {

private final EnumMap<ExpressionType, ExpressionEvaluationProvider> factories = new EnumMap<>(ExpressionType.class);

public ExpressionEvaluationProviderFactory(final ScriptEngineProvider scriptEngineProvider) {
final ExpressionEvaluationProvider scriptExpressionEvaluationProvider = new ScriptExpressionEvaluationProvider(scriptEngineProvider);

factories.put(ExpressionType.LITERAL, new LiteralExpressionEvaluationProvider());
factories.put(ExpressionType.FEEL, new FeelExpressionEvaluationProvider());
factories.put(ExpressionType.JUEL, new JuelExpressionEvaluationProvider());
factories.put(ExpressionType.GROOVY, scriptExpressionEvaluationProvider);
factories.put(ExpressionType.JAVASCRIPT, scriptExpressionEvaluationProvider);
}

public ExpressionEvaluationProvider getInstance(final ExpressionType expressionType) {
final ExpressionEvaluationProvider expressionEvaluationProvider = factories.get(expressionType);
import java.util.List;

if (expressionEvaluationProvider == null) {
throw new IllegalArgumentException("Unknown expression type " + expressionType);
}
public interface ExpressionEvaluationProviderFactory {
ExpressionEvaluationProvider createProvider(ExpressionEvaluationConfiguration configuration);

return expressionEvaluationProvider;
}
List<ExpressionType> supportedExpressionTypes();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2018-present PowerFlows.org - all rights reserved.
*
* 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 org.powerflows.dmn.engine.evaluator.expression.provider;

import org.powerflows.dmn.engine.model.decision.expression.ExpressionType;

import java.util.Collections;
import java.util.List;

public class FeelExpressionEvaluationProviderFactory implements ExpressionEvaluationProviderFactory {
private static final List<ExpressionType> SUPPORTED = Collections.singletonList(ExpressionType.FEEL);

@Override
public ExpressionEvaluationProvider createProvider(final ExpressionEvaluationConfiguration configuration) {
return new FeelExpressionEvaluationProvider();
}

@Override
public List<ExpressionType> supportedExpressionTypes() {
return SUPPORTED;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2018-present PowerFlows.org - all rights reserved.
*
* 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 org.powerflows.dmn.engine.evaluator.expression.provider;

import lombok.extern.slf4j.Slf4j;
import org.codehaus.groovy.runtime.MethodClosure;
import org.powerflows.dmn.engine.evaluator.expression.provider.binding.MethodBinding;

@Slf4j
class GroovyExpressionEvaluationProvider extends ScriptEngineExpressionEvaluationProvider {

public GroovyExpressionEvaluationProvider(final ExpressionEvaluationConfiguration configuration) {
super(configuration);
}

@Override
protected Object createMethodBinding(final MethodBinding methodBinding) {
return new MethodClosure(methodBinding, "execute");
}

@Override
protected String getEngineName() {
return "groovy";
}
}
Loading

0 comments on commit 60a8dcc

Please sign in to comment.