Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possibility to add allowed classes in the model #1908

Merged
merged 8 commits into from
Jul 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public class ExpressionConfig implements Serializable {

private final List<WithCategories<String>> globalImports;

private final List<Class<?>> additionalClasses;

private final LanguageConfiguration languages;

private final boolean optimizeCompilation;
Expand All @@ -27,15 +29,16 @@ public class ExpressionConfig implements Serializable {

private final boolean hideMetaVariable;

public ExpressionConfig(Map<String, WithCategories<Object>> globalProcessVariables, List<WithCategories<String>> globalImports) {
this(globalProcessVariables, globalImports, new LanguageConfiguration(List$.MODULE$.empty()), true, true, Collections.emptyMap(), false);
public ExpressionConfig(Map<String, WithCategories<Object>> globalProcessVariables, List<WithCategories<String>> globalImports, List<Class<?>> additionalClasses) {
this(globalProcessVariables, globalImports, additionalClasses, new LanguageConfiguration(List$.MODULE$.empty()), true, true, Collections.emptyMap(), false);
}

public ExpressionConfig(Map<String, WithCategories<Object>> globalProcessVariables, List<WithCategories<String>> globalImports,
LanguageConfiguration languages, boolean optimizeCompilation, boolean strictTypeChecking,
List<Class<?>> additionalClasses, LanguageConfiguration languages, boolean optimizeCompilation, boolean strictTypeChecking,
Map<String, WithCategories<DictDefinition>> dictionaries, boolean hideMetaVariable) {
this.globalProcessVariables = globalProcessVariables;
this.globalImports = globalImports;
this.additionalClasses = additionalClasses;
this.languages = languages;
this.optimizeCompilation = optimizeCompilation;
this.strictTypeChecking = strictTypeChecking;
Expand All @@ -51,6 +54,10 @@ public List<WithCategories<String>> getGlobalImports() {
return globalImports;
}

public List<Class<?>> getAdditionalClasses() {
return additionalClasses;
}

public LanguageConfiguration getLanguages() {
return languages;
}
Expand Down Expand Up @@ -80,14 +87,15 @@ public boolean equals(Object o) {
strictTypeChecking == that.strictTypeChecking &&
Objects.equals(globalProcessVariables, that.globalProcessVariables) &&
Objects.equals(globalImports, that.globalImports) &&
Objects.equals(additionalClasses, that.additionalClasses) &&
Objects.equals(languages, that.languages) &&
Objects.equals(dictionaries, that.dictionaries) &&
Objects.equals(hideMetaVariable, that.hideMetaVariable);
}

@Override
public int hashCode() {
return Objects.hash(globalProcessVariables, globalImports, languages, optimizeCompilation, strictTypeChecking, dictionaries, hideMetaVariable);
return Objects.hash(globalProcessVariables, globalImports, additionalClasses, languages, optimizeCompilation, strictTypeChecking, dictionaries, hideMetaVariable);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ object ProcessConfigCreatorMapping {
ExpressionConfig(
globalProcessVariables = jec.getGlobalProcessVariables.asScala.toMap,
globalImports = jec.getGlobalImports.asScala.toList,
additionalClasses = jec.getAdditionalClasses.asScala.toList,
languages = jec.getLanguages,
optimizeCompilation = jec.isOptimizeCompilation,
strictTypeChecking = jec.isStrictTypeChecking,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import pl.touk.nussknacker.engine.api.expression.ExpressionParser
//TODO: how to make this config less spel-centric?, move globalImports and optimizeCompilation to spel configuration
case class ExpressionConfig(globalProcessVariables: Map[String, WithCategories[AnyRef]],
globalImports: List[WithCategories[String]],
additionalClasses: List[Class[_]] = List.empty,
languages: LanguageConfiguration = LanguageConfiguration.default,
optimizeCompilation: Boolean = true,
strictTypeChecking: Boolean = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import pl.touk.nussknacker.engine.graph.expression.Expression
/* This is helper class for testing SpEL expressions, see SampleSpelBenchmark for usage */
class SpelBenchmarkSetup(expression: String, vars: Map[String, AnyRef]) {

private val expressionDefinition = ExpressionDefinition(globalVariables = Map(), globalImports = Nil,
private val expressionDefinition = ExpressionDefinition(globalVariables = Map(), globalImports = Nil, additionalClasses = List(),
languages = LanguageConfiguration.default, optimizeCompilation = true,
strictTypeChecking = true, dictionaries = Map.empty, hideMetaVariable = false, strictMethodsChecking = true)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public ExceptionHandlerFactory exceptionHandlerFactory(ProcessObjectDependencies

@Override
public ExpressionConfig expressionConfig(ProcessObjectDependencies processObjectDependencies) {
return new ExpressionConfig(Collections.emptyMap(), Collections.emptyList());
return new ExpressionConfig(Collections.emptyMap(), Collections.emptyList(), Collections.emptyList());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import pl.touk.nussknacker.engine.avro.source.KafkaAvroSourceFactory
import pl.touk.nussknacker.engine.flink.api.process._
import pl.touk.nussknacker.engine.flink.util.exception.ConfigurableExceptionHandlerFactory
import pl.touk.nussknacker.engine.flink.util.sink.EmptySink
import pl.touk.nussknacker.engine.flink.util.source.EspDeserializationSchema
import pl.touk.nussknacker.engine.flink.util.source.{EspDeserializationSchema, ReturningClassInstanceSource, ReturningTestCaseClass}
import pl.touk.nussknacker.engine.flink.util.transformer.aggregate.AggregateHelper
import pl.touk.nussknacker.engine.flink.util.transformer.aggregate.sampleTransformers.SlidingAggregateTransformerV2
import pl.touk.nussknacker.engine.flink.util.transformer.outer.OuterJoinTransformer
Expand Down Expand Up @@ -96,7 +96,8 @@ class DevProcessConfigCreator extends ProcessConfigCreator {
"communicationSource" -> categories(DynamicParametersSource),
"csv-source" -> categories(FlinkSourceFactory.noParam(new CsvSource)),
"genericSourceWithCustomVariables" -> categories(GenericSourceWithCustomVariablesSample),
"sql-source" -> categories(SqlSource)
"sql-source" -> categories(SqlSource),
"classInstanceSource" -> all(new ReturningClassInstanceSource)
)
}

Expand Down Expand Up @@ -193,9 +194,14 @@ class DevProcessConfigCreator extends ProcessConfigCreator {
"TypedConfig" -> all(ConfigTypedGlobalVariable)
)

val additionalClasses = List(
classOf[ReturningTestCaseClass]
)

ExpressionConfig(
globalProcessVariables,
List.empty,
additionalClasses,
LanguageConfiguration(List()),
dictionaries = Map(
TestDictionary.id -> categories(TestDictionary.definition),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ object ProcessTestHelpers {
"processHelper" -> WithCategories(ProcessHelper),
"enum" -> WithCategories(DictInstance(dictId, dictDef)),
"typedMap" -> WithCategories(TypedMap(Map("aField" -> "123"))))
ExpressionConfig(globalProcessVariables, List.empty, dictionaries = Map(dictId -> WithCategories(dictDef)))
ExpressionConfig(globalProcessVariables, List.empty, List.empty, dictionaries = Map(dictId -> WithCategories(dictDef)))
}

override def signals(processObjectDependencies: ProcessObjectDependencies): Map[String, WithCategories[ProcessSignalSender]] = Map.empty
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package pl.touk.nussknacker.engine.flink.util.source

import org.apache.flink.streaming.api.scala.{StreamExecutionEnvironment, _}
import pl.touk.nussknacker.engine.api.editor.{DualEditor, DualEditorMode, SimpleEditor, SimpleEditorType}
import pl.touk.nussknacker.engine.api.typed.typing.Typed
import pl.touk.nussknacker.engine.api.{MethodToInvoke, ParamName}
import pl.touk.nussknacker.engine.flink.api.process.FlinkSourceFactory

class ReturningClassInstanceSource extends FlinkSourceFactory[Any] {

@MethodToInvoke
def source(@ParamName("Additional class")
@DualEditor(
simpleEditor = new SimpleEditor(`type` = SimpleEditorType.STRING_EDITOR),
defaultMode = DualEditorMode.SIMPLE
) additionalClass: String) =
new CollectionSource[Any](StreamExecutionEnvironment.getExecutionEnvironment.getConfig, List.empty, None, Typed.typedClass(Class.forName(additionalClass)))

}
case class ReturningTestCaseClass(someMethod: String)
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,12 @@ object DefinitionExtractor {
TypesInformationExtractor.clazzAndItsChildrenDefinition(classesToExtractDefinitions)
}

def extractFromClassList(objectToExtractClassesFromCollection: Iterable[Class[_]])
(implicit settings: ClassExtractionSettings): Set[TypeInfos.ClazzDefinition] = {
val ref = objectToExtractClassesFromCollection.map(Typed.apply)
TypesInformationExtractor.clazzAndItsChildrenDefinition(ref)
}

private def extractTypesFromObjectDefinition(obj: ObjectWithMethodDef): List[TypingResult] = {
def typesFromParameter(parameter: Parameter): List[TypingResult] = {
val fromAdditionalVars = parameter.additionalVariables.values
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ object ProcessDefinitionExtractor {
definition.customStreamTransformers.values.map(_._1) ++
definition.signalsWithTransformers.values.map(_._1) ++
definition.expressionConfig.globalVariables.values
)(definition.settings)
) (definition.settings) ++
TypesInformation.extractFromClassList(definition.expressionConfig.additionalClasses)(definition.settings)
}

import pl.touk.nussknacker.engine.util.Implicits._
Expand Down Expand Up @@ -77,6 +78,7 @@ object ProcessDefinitionExtractor {
customStreamTransformersDefs.mapValuesNow(k => (k, extractCustomTransformerData(k))),
signalsDefs, exceptionHandlerFactoryDefs, ExpressionDefinition(globalVariablesDefs,
globalImportsDefs,
expressionConfig.additionalClasses,
expressionConfig.languages,
expressionConfig.optimizeCompilation,
expressionConfig.strictTypeChecking,
Expand Down Expand Up @@ -141,6 +143,7 @@ object ProcessDefinitionExtractor {
val expressionDefinition = ExpressionDefinition(
definition.expressionConfig.globalVariables.mapValuesNow(_.objectDefinition),
definition.expressionConfig.globalImports,
definition.expressionConfig.additionalClasses,
definition.expressionConfig.languages,
definition.expressionConfig.optimizeCompilation,
definition.expressionConfig.strictTypeChecking,
Expand All @@ -160,8 +163,8 @@ object ProcessDefinitionExtractor {
)
}

case class ExpressionDefinition[+T <: ObjectMetadata](globalVariables: Map[String, T], globalImports: List[String], languages: LanguageConfiguration,
optimizeCompilation: Boolean, strictTypeChecking: Boolean, dictionaries: Map[String, DictDefinition],
hideMetaVariable: Boolean, strictMethodsChecking: Boolean)
case class ExpressionDefinition[+T <: ObjectMetadata](globalVariables: Map[String, T], globalImports: List[String], additionalClasses: List[Class[_]],
languages: LanguageConfiguration, optimizeCompilation: Boolean, strictTypeChecking: Boolean,
dictionaries: Map[String, DictDefinition], hideMetaVariable: Boolean, strictMethodsChecking: Boolean)

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ object ProcessDefinitionBuilder {

def empty: ProcessDefinition[ObjectDefinition] =
ProcessDefinition(Map.empty, Map.empty, Map.empty, Map.empty, Map.empty, ObjectDefinition.noParam,
ExpressionDefinition(Map.empty, List.empty, languages = LanguageConfiguration(List.empty),
ExpressionDefinition(Map.empty, List.empty, List.empty, languages = LanguageConfiguration(List.empty),
optimizeCompilation = true, strictTypeChecking = true, dictionaries = Map.empty, hideMetaVariable = false, strictMethodsChecking = true), ClassExtractionSettings.Default)

def withEmptyObjects(definition: ProcessDefinition[ObjectDefinition]): ProcessDefinition[ObjectWithMethodDef] = {
Expand All @@ -27,6 +27,7 @@ object ProcessDefinitionBuilder {
val expressionDefinition = ExpressionDefinition(
definition.expressionConfig.globalVariables.mapValuesNow(makeDummyDefinition(_)),
definition.expressionConfig.globalImports,
definition.expressionConfig.additionalClasses,
definition.expressionConfig.languages,
definition.expressionConfig.optimizeCompilation,
definition.expressionConfig.strictTypeChecking,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class ProcessValidatorSpec extends FunSuite with Matchers with Inside {
ObjectDefinition.noParam,
ExpressionDefinition(
Map("processHelper" -> ObjectDefinition(List(), Typed(ProcessHelper.getClass), List("cat1"), SingleNodeConfig.zero)),
List.empty, LanguageConfiguration.default, optimizeCompilation = false, strictTypeChecking = true, dictionaries = Map.empty, hideMetaVariable = false, strictMethodsChecking = true
List.empty, List.empty, LanguageConfiguration.default, optimizeCompilation = false, strictTypeChecking = true, dictionaries = Map.empty, hideMetaVariable = false, strictMethodsChecking = true
),
ClassExtractionSettings.Default
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class LazyParameterSpec extends FunSuite with Matchers {
}

private def prepareInterpreter = {
val exprDef = ExpressionDefinition(Map.empty, List.empty, LanguageConfiguration.default, optimizeCompilation = false, strictTypeChecking = true, Map.empty,
val exprDef = ExpressionDefinition(Map.empty, List.empty, List.empty, LanguageConfiguration.default, optimizeCompilation = false, strictTypeChecking = true, Map.empty,
hideMetaVariable = false, strictMethodsChecking = true)
val processDef = ProcessDefinition(Map.empty, Map.empty, Map.empty, Map.empty, Map.empty,
ObjectWithMethodDef.withEmptyConfig(new NoParamExceptionHandlerFactory(_ => null), ProcessObjectDefinitionExtractor.exceptionHandler), exprDef, ClassExtractionSettings.Default)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ class ProcessDefinitionExtractorSpec extends FunSuite with Matchers {
classDefinition.map(_.methods.keys) shouldBe Some(Set("someField", "toString"))
}

test("extract type info from additional classes") {
val types = ProcessDefinitionExtractor.extractTypes(processDefinition)
val classDefinition = types.find(_.clazzName == Typed[AdditionalClass])
classDefinition.map(_.methods.keys) shouldBe Some(Set("someField", "toString"))
}

test("extract definition from WithExplicitMethodToInvoke") {
val definition = processDefinition.services("configurable1")

Expand Down Expand Up @@ -126,7 +132,9 @@ class ProcessDefinitionExtractorSpec extends FunSuite with Matchers {
"helper" -> WithCategories(SampleHelper, "category"),
"typedGlobal" -> WithCategories(SampleTypedVariable, "category")
),
globalImports = Nil
globalImports = Nil, additionalClasses = List(
classOf[AdditionalClass]
)
)

override def buildInfo(): Map[String, String] = Map()
Expand Down Expand Up @@ -170,6 +178,8 @@ class ProcessDefinitionExtractorSpec extends FunSuite with Matchers {

case class OnlyUsedInAdditionalVariable(someField: String)

case class AdditionalClass(someField: String)

case class EmptyExplicitMethodToInvoke(parameterDefinition: List[Parameter], returnType: TypingResult) extends Service with WithExplicitMethodToInvoke {

override def runtimeClass: Class[_] = classOf[Future[_]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class EmptyProcessConfigCreator
override def exceptionHandlerFactory(processObjectDependencies: ProcessObjectDependencies): ExceptionHandlerFactory =
ExceptionHandlerFactory.noParams(_ => EspExceptionHandler.empty)

override def expressionConfig(processObjectDependencies: ProcessObjectDependencies) = ExpressionConfig(Map.empty, List.empty, LanguageConfiguration.default)
override def expressionConfig(processObjectDependencies: ProcessObjectDependencies) = ExpressionConfig(Map.empty, List.empty, List.empty, LanguageConfiguration.default)

override def buildInfo(): Map[String, String] =
Map.empty
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ class DefinitionResourcesSpec extends FunSpec with ScalatestRouteTest with FailF

private implicit final val string: FromEntityUnmarshaller[String] = Unmarshaller.stringUnmarshaller.forContentTypes(ContentTypeRange.*)

it("should handle missing processing type") {
it("should handle missing scenario type") {
getProcessDefinitionData("foo", Map.empty[String, Long].asJson) ~> check {
status shouldBe StatusCodes.NotFound
}
}

it("should return definition data for existing processing type") {
it("should return definition data for existing scenario type") {
getProcessDefinitionData(existingProcessingType, Map.empty[String, Long].asJson) ~> check {
status shouldBe StatusCodes.OK

Expand All @@ -37,6 +37,22 @@ class DefinitionResourcesSpec extends FunSpec with ScalatestRouteTest with FailF
}
}

it("should return definition data for allowed classes") {
getProcessDefinitionData(existingProcessingType, Map.empty[String, Long].asJson) ~> check {
status shouldBe StatusCodes.OK

val typesInformation = responseAs[Json].hcursor
.downField("processDefinition")
.downField("typesInformation")
.downAt(_.hcursor.downField("clazzName").get[String]("display").right.value == "ReturningTestCaseClass")
.downField("clazzName")
.downField("display")

typesInformation.focus.get shouldBe Json.fromString("ReturningTestCaseClass")
}
}


it("should return all definition services") {
getProcessDefinitionServices ~> check {
status shouldBe StatusCodes.OK
Expand Down Expand Up @@ -88,7 +104,7 @@ class DefinitionResourcesSpec extends FunSpec with ScalatestRouteTest with FailF
}
}

it("should return info about editor based on subprocess node configuration") {
it("should return info about editor based on fragment node configuration") {
val processName = ProcessName(SampleProcess.process.id)
val processWithSubProcess = ProcessTestData.validProcessWithSubprocess(processName)
val displayableSubProcess = ProcessConverter.toDisplayable(processWithSubProcess.subprocess, TestProcessingTypes.Streaming)
Expand Down Expand Up @@ -306,7 +322,7 @@ class DefinitionResourcesSpec extends FunSpec with ScalatestRouteTest with FailF
)
),
"type" -> Json.fromString("FixedValuesValidator")
))
))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class ProcessConverterSpec extends FunSuite with Matchers with TableDrivenProper
lazy val validation: ProcessValidation = {
val processDefinition = ProcessDefinition[ObjectDefinition](Map("ref" -> ObjectDefinition.noParam),
Map("sourceRef" -> ObjectDefinition.noParam), Map(), Map(), Map(), ObjectDefinition.noParam,
ExpressionDefinition(Map.empty, List.empty, LanguageConfiguration.default, optimizeCompilation = false, strictTypeChecking = true, Map.empty,
ExpressionDefinition(Map.empty, List.empty, List.empty, LanguageConfiguration.default, optimizeCompilation = false, strictTypeChecking = true, Map.empty,
hideMetaVariable = false, strictMethodsChecking = true), ClassExtractionSettings.Default)
val validator = ProcessValidator.default(ProcessDefinitionBuilder.withEmptyObjects(processDefinition), new SimpleDictRegistry(Map.empty))
new ProcessValidation(mapProcessingTypeDataProvider(TestProcessingTypes.Streaming -> validator), mapProcessingTypeDataProvider(TestProcessingTypes.Streaming -> Map()), sampleResolver, emptyProcessingTypeDataProvider)
Expand Down