Skip to content

Commit

Permalink
feat(#3208): Add math expression evaluator, UI fixes (#3209)
Browse files Browse the repository at this point in the history
* feat(#3208): Add math expression evaluator, UI fixes

* Fix dependency convergence

* Add test, improve docs
  • Loading branch information
dominikriemer authored Sep 4, 2024
1 parent 755ca49 commit 970ccf4
Show file tree
Hide file tree
Showing 23 changed files with 658 additions and 29 deletions.
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
<commons-compress.version>1.26.0</commons-compress.version>
<commons-io.version>2.16.1</commons-io.version>
<commons-lang3.version>3.14.0</commons-lang3.version>
<commons-logging.version>1.3.2</commons-logging.version>
<commons-pool2.version>2.12.0</commons-pool2.version>
<commons-text.version>1.12.0</commons-text.version>
<ditto-client.version>1.0.0</ditto-client.version>
Expand Down Expand Up @@ -171,6 +172,11 @@
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>${commons-logging.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
Expand Down
5 changes: 5 additions & 0 deletions streampipes-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@
<groupId>org.apache.httpcomponents</groupId>
<artifactId>fluent-hc</artifactId>
</dependency>

<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@
<artifactId>js-scriptengine</artifactId>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-jexl3</artifactId>
<version>3.4.0</version>
</dependency>

<!-- Test dependencies -->
<dependency>
<groupId>org.apache.streampipes</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.apache.streampipes.extensions.api.declarer.IExtensionModuleExport;
import org.apache.streampipes.extensions.api.migration.IModelMigrator;
import org.apache.streampipes.extensions.api.pe.IStreamPipesPipelineElement;
import org.apache.streampipes.processors.enricher.jvm.processor.expression.MathExpressionProcessor;
import org.apache.streampipes.processors.enricher.jvm.processor.jseval.JSEvalProcessor;
import org.apache.streampipes.processors.enricher.jvm.processor.limitsalert.SensorLimitAlertProcessor;
import org.apache.streampipes.processors.enricher.jvm.processor.limitsenrichment.QualityControlLimitsEnrichmentProcessor;
Expand All @@ -48,7 +49,8 @@ public List<IStreamPipesPipelineElement<?>> pipelineElements() {
new MathOpProcessor(),
new StaticMathOpProcessor(),
new TrigonometryProcessor(),
new ValueChangeProcessor()
new ValueChangeProcessor(),
new MathExpressionProcessor()
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.streampipes.processors.enricher.jvm.processor.expression;

import org.apache.streampipes.model.runtime.Event;

import org.apache.commons.jexl3.MapContext;

public class JexlContextGenerator {

private final MathExpressionFieldExtractor extractor;
private final MapContext mapContext;

public JexlContextGenerator(MathExpressionFieldExtractor extractor) {
this.extractor = extractor;
this.mapContext = makeInitialContext();
}

private MapContext makeInitialContext() {
var ctx = new MapContext();
ctx.set("Math", Math.class);
extractor.getInputProperties().forEach(ep ->
ctx.set(ep.getRuntimeName(), 0)
);
return ctx;
}

public MapContext makeContext(Event event) {
event.getRaw().forEach(mapContext::set);
return mapContext;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.streampipes.processors.enricher.jvm.processor.expression;

import org.apache.streampipes.model.schema.EventPropertyPrimitive;

public record JexlDescription(EventPropertyPrimitive ep,
String script) {

public String getFieldName() {
return ep.getRuntimeName();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.streampipes.processors.enricher.jvm.processor.expression;

import org.apache.commons.jexl3.JexlBuilder;
import org.apache.commons.jexl3.JexlEngine;
import org.apache.commons.jexl3.JexlFeatures;
import org.apache.commons.jexl3.introspection.JexlPermissions;

public class JexlEngineProvider {

public JexlEngine getEngine() {
var features = new JexlFeatures()
.loops(false)
.sideEffect(false)
.sideEffectGlobal(false);

var permissions = new JexlPermissions.ClassPermissions(java.lang.Math.class);

return new JexlBuilder().features(features).permissions(permissions).create();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.streampipes.processors.enricher.jvm.processor.expression;

import org.apache.streampipes.model.runtime.Event;

import org.apache.commons.jexl3.JexlEngine;
import org.apache.commons.jexl3.JexlScript;
import org.apache.commons.jexl3.MapContext;

public class JexlEvaluator {

private final JexlDescription jexlDescription;
private final JexlScript script;

public JexlEvaluator(JexlDescription jexlDescription,
JexlEngine engine) {
this.jexlDescription = jexlDescription;
this.script = engine.createScript(jexlDescription.script());
}

public void evaluate(MapContext context,
Event event) {
event.addField(jexlDescription.getFieldName(), script.execute(context));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.streampipes.processors.enricher.jvm.processor.expression;

import org.apache.streampipes.extensions.api.extractor.IDataProcessorParameterExtractor;
import org.apache.streampipes.model.graph.DataProcessorInvocation;
import org.apache.streampipes.model.schema.EventProperty;
import org.apache.streampipes.model.staticproperty.CodeInputStaticProperty;
import org.apache.streampipes.model.staticproperty.FreeTextStaticProperty;
import org.apache.streampipes.sdk.extractor.ProcessingElementParameterExtractor;
import org.apache.streampipes.sdk.helpers.EpProperties;
import org.apache.streampipes.sdk.helpers.Labels;
import org.apache.streampipes.vocabulary.SO;

import java.util.List;

import static org.apache.streampipes.processors.enricher.jvm.processor.expression.MathExpressionProcessor.ENRICHED_FIELDS;
import static org.apache.streampipes.processors.enricher.jvm.processor.expression.MathExpressionProcessor.EXPRESSION;
import static org.apache.streampipes.processors.enricher.jvm.processor.expression.MathExpressionProcessor.FIELD_NAME;

public class MathExpressionFieldExtractor {

private final DataProcessorInvocation processingElement;
private final IDataProcessorParameterExtractor extractor;

public MathExpressionFieldExtractor(DataProcessorInvocation processingElement) {
this.processingElement = processingElement;
this.extractor = ProcessingElementParameterExtractor.from(processingElement);
}

public MathExpressionFieldExtractor(DataProcessorInvocation processingElement,
IDataProcessorParameterExtractor extractor) {
this.processingElement = processingElement;
this.extractor = extractor;
}

public List<JexlDescription> getAdditionalFields() {
return extractor
.collectionMembersAsGroup(ENRICHED_FIELDS)
.stream().map(group -> {
var runtimeName = extractor.extractGroupMember(FIELD_NAME, group).as(FreeTextStaticProperty.class).getValue();
var expression = extractor.extractGroupMember(EXPRESSION, group).as(CodeInputStaticProperty.class).getValue();
return new JexlDescription(EpProperties.doubleEp(Labels.empty(), runtimeName, SO.NUMBER), expression);
}).toList();
}

public List<EventProperty> getInputProperties() {
var inputStreams = processingElement.getInputStreams();
if (!inputStreams.isEmpty()) {
return inputStreams.get(0).getEventSchema().getEventProperties();
} else {
return List.of();
}
}
}

Loading

0 comments on commit 970ccf4

Please sign in to comment.