Skip to content

Commit

Permalink
Merge pull request #148 from powerflows/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
mariuszkumor authored Feb 3, 2019
2 parents c4d1309 + 3bbd681 commit bf9ec55
Show file tree
Hide file tree
Showing 106 changed files with 5,657 additions and 577 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@
# Others
target/
.settings/
bin/
bin/
/.attach_pid*
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,8 @@ Decision decision = Decision.builder()

# IO
Thanks to IO module there is a possibility to:
* Read decisions from *.yml files;
* Read decisions from _powerflows_ *.yml files;
* Read decisions from DMN 1.1 *.xml files;
* Write decisions to *.yml files.

## Reading
Expand All @@ -354,8 +355,15 @@ First of all input stream is needed. Then, using YamlDecisionReader class a deve

```java
InputStream inputStream = this.class.getResourceAsStream("sample-decision.yml");
Decision result = new YamlDecisionReader().read(inputStream);
Optional<Decision> result = new YamlDecisionReader().read(inputStream);
```
Another source of Decision may be OMG defined DMN 1.1 compatible XML file.

```java
InputStream inputStream = this.class.getResourceAsStream("sample-decision.xml");
List<Decision> result = new XMLDecisionReader.readAll(inputStream);
```
Currently only reading of decision tables from _decision_ tags is supported.

## Writing
The IO module can be used to conversion between different formats. For now the only one supported is *.yml.
Expand Down
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 @@ -32,14 +32,18 @@
import org.powerflows.dmn.engine.model.evaluation.variable.DecisionVariables;

import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
public class DecisionEvaluator {

private static final Set<HitPolicy> UNSUPPORTED_HIT_POLICIES = Collections.unmodifiableSet(EnumSet.of(HitPolicy.OUTPUT_ORDER, HitPolicy.RULE_ORDER, HitPolicy.PRIORITY));
private final RuleEvaluator ruleEvaluator;

public DecisionEvaluator(RuleEvaluator ruleEvaluator) {
Expand All @@ -55,6 +59,10 @@ public DecisionResult evaluate(final Decision decision, final DecisionVariables
throw new NullPointerException("Decision variables can not be null");
}

if (isUnsupportedSupportedHitPolicy(decision.getHitPolicy())) {
throw new UnsupportedOperationException("HitPolicy " + decision.getHitPolicy() + " is not supported");
}

log.info("Starting evaluation of decision: {} with decision variables: {}", decision, decisionVariables);

validateDecisionVariables(decision.getInputs(), decisionVariables);
Expand Down Expand Up @@ -97,6 +105,10 @@ public DecisionResult evaluate(final Decision decision, final DecisionVariables
return decisionResult;
}

private boolean isUnsupportedSupportedHitPolicy(HitPolicy hitPolicy) {
return UNSUPPORTED_HIT_POLICIES.contains(hitPolicy);
}

private void validateDecisionVariables(final List<Input> inputs, final DecisionVariables decisionVariables) {
final String invalidInputNames = inputs
.stream()
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 All @@ -66,7 +66,7 @@ public boolean evaluate(final InputEntry inputEntry,

final Object inputValue = evaluationContext.get(inputEntry.getName());
final SpecifiedTypeValue<?> typedInputValue = typeConverter.convert(inputValue);
final Object inputEntryValue = inputEntryExpressionEvaluator.evaluateEntry(inputEntry.getExpression(), evaluationContext);
final Object inputEntryValue = inputEntryExpressionEvaluator.evaluateInputEntry(inputEntry, evaluationContext);

final SpecifiedTypeValue<?> typedInputEntryValue;
if (isBoolean(inputEntryValue)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@

import lombok.extern.slf4j.Slf4j;
import org.powerflows.dmn.engine.evaluator.context.EvaluationContext;
import org.powerflows.dmn.engine.evaluator.expression.provider.ExpressionEvaluationProviderFactory;
import org.powerflows.dmn.engine.evaluator.expression.provider.ExpressionEvaluationProvider;
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 All @@ -45,7 +45,7 @@ public EntryResult evaluate(final OutputEntry outputEntry, final Output output,
final ExpressionEvaluationProvider expressionEvaluator = expressionEvaluationProviderFactory.getInstance(outputEntry.getExpression().getType());
final TypeConverter typeConverter = typeConverterFactory.getInstance(output.getType());

final Serializable outputEntryValue = expressionEvaluator.evaluateEntry(outputEntry.getExpression(), evaluationContext);
final Serializable outputEntryValue = expressionEvaluator.evaluateOutputEntry(outputEntry, evaluationContext);

//Needed for the output entry value validation.
//Correct build means the output entry value has a type compatible with the output definition.
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 @@ -17,14 +17,17 @@
package org.powerflows.dmn.engine.evaluator.expression.provider;

import org.powerflows.dmn.engine.evaluator.context.EvaluationContext;
import org.powerflows.dmn.engine.model.decision.expression.Expression;
import org.powerflows.dmn.engine.model.decision.field.Input;
import org.powerflows.dmn.engine.model.decision.rule.entry.InputEntry;
import org.powerflows.dmn.engine.model.decision.rule.entry.OutputEntry;

import java.io.Serializable;

public interface ExpressionEvaluationProvider {

Serializable evaluateInput(Input input, EvaluationContext evaluationContext);

Serializable evaluateEntry(Expression entryExpression, EvaluationContext evaluationContext);
Serializable evaluateInputEntry(InputEntry inputEntry, EvaluationContext evaluationContext);

Serializable evaluateOutputEntry(OutputEntry outputEntry, EvaluationContext evaluationContext);
}
Loading

0 comments on commit bf9ec55

Please sign in to comment.