From afcd99e9dc0d765758be1d91ab862afa54d244dd Mon Sep 17 00:00:00 2001 From: Brinda Santh Date: Mon, 5 Aug 2019 12:24:33 -0400 Subject: Add class model for workflow and resource data type. Change-Id: Ia42f56541bef0418dddb797c019ecda3afa6983b Issue-ID: CCSDK-1380 Signed-off-by: Brinda Santh --- .../core/BluePrintExtensionFunctions.kt | 126 +++++++++++++++++++++ .../controllerblueprints/core/CustomFunctions.kt | 22 ++++ .../core/annotations/BluePrintsAnnotations.kt | 97 ++++++++++++++++ .../controllerblueprints/core/dsl/BluePrintDSL.kt | 51 +++++---- .../core/dsl/BluePrintServiceDSLBuilder.kt | 12 +- .../core/dsl/BluePrintWorkflowDSLBuilder.kt | 10 ++ 6 files changed, 296 insertions(+), 22 deletions(-) create mode 100644 ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BluePrintExtensionFunctions.kt create mode 100644 ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/annotations/BluePrintsAnnotations.kt (limited to 'ms/controllerblueprints/modules/blueprint-core/src/main') diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BluePrintExtensionFunctions.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BluePrintExtensionFunctions.kt new file mode 100644 index 000000000..dafd076fb --- /dev/null +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BluePrintExtensionFunctions.kt @@ -0,0 +1,126 @@ +/* + * Copyright © 2019 IBM. + * + * 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.onap.ccsdk.cds.controllerblueprints.core + +import org.onap.ccsdk.cds.controllerblueprints.core.annotations.* +import org.onap.ccsdk.cds.controllerblueprints.core.data.ConstraintClause +import org.onap.ccsdk.cds.controllerblueprints.core.data.DataType +import org.onap.ccsdk.cds.controllerblueprints.core.data.EntrySchema +import org.onap.ccsdk.cds.controllerblueprints.core.data.PropertyDefinition +import org.onap.ccsdk.cds.controllerblueprints.core.dsl.* +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 +import kotlin.reflect.KType +import kotlin.reflect.full.declaredMemberProperties + +fun > T.asBluePrintsDataTypes(): DataType { + val annotation = this.annotations.filter { it is BluePrintsDataType }.single() as BluePrintsDataType + checkNotNull(annotation) { "BluePrintsDataType annotation definition not found" } + val dataType = DataType().apply { + id = annotation.name + version = annotation.version + derivedFrom = annotation.derivedFrom + description = annotation.description + } + dataType.properties = this.asPropertyDefinitionMap() + return dataType +} + +fun > T.asPropertyDefinitionMap(): MutableMap { + val properties: MutableMap = hashMapOf() + this.declaredMemberProperties.forEach { member -> + properties[member.name] = member.asPropertyDefinition() + } + return properties +} + +fun KProperty1.asPropertyDefinition(): PropertyDefinition { + val property = PropertyDefinition() + property.id = this.name + val getter = this.getter + property.required = !this.returnType.isMarkedNullable + property.type = this.returnType.asBluePrintsDataType(this.name) + if (this.returnType.arguments.isNotEmpty()) { + property.entrySchema = this.returnType.entitySchema() + } + this.annotations.forEach { fieldAnnotation -> + //println("Field : ${this.name} : Annotation : $fieldAnnotation") + when (fieldAnnotation) { + is BluePrintsProperty -> + property.description = fieldAnnotation.description + is PropertyDefaultValue -> + property.value = fieldAnnotation.value.asJsonType(property.type) + is BluePrintsConstrain -> { + if (property.constraints == null) property.constraints = arrayListOf() + property.constraints!!.add(fieldAnnotation.asBluePrintConstraintClause()) + } + is InputExpression -> { + property.value = getInput(fieldAnnotation.propertyName) + } + is PropertyExpression -> { + property.value = getNodeTemplateProperty(fieldAnnotation.modelableEntityName, + fieldAnnotation.propertyName, fieldAnnotation.subPropertyName) + } + is AttributeExpression -> { + property.value = getNodeTemplateAttribute(fieldAnnotation.modelableEntityName, + fieldAnnotation.attributeName, fieldAnnotation.subAttributeName) + } + is ArtifactExpression -> { + property.value = getNodeTemplateArtifact(fieldAnnotation.modelableEntityName, + fieldAnnotation.artifactName) + } + is OperationOutputExpression -> { + property.value = getNodeTemplateOperationOutput(fieldAnnotation.modelableEntityName, + fieldAnnotation.interfaceName, fieldAnnotation.propertyName, fieldAnnotation.subPropertyName) + } + is DSLExpression -> { + property.value = dslExpression(fieldAnnotation.propertyName) + } + } + } + return property +} + +internal fun BluePrintsConstrain.asBluePrintConstraintClause(): ConstraintClause { + TODO() +} + +internal fun T.entitySchema(): EntrySchema { + val entrySchema = EntrySchema() + if (this.arguments.size == 1) { + entrySchema.type = this.arguments[0].type!!.asBluePrintsDataType("") + } else if (this.arguments.size == 2) { + entrySchema.type = this.arguments[1].type!!.asBluePrintsDataType("") + } + return entrySchema +} + +internal fun T.asBluePrintsDataType(propertyName: String): String { + val simpleName = (this.classifier as? KClass<*>)?.java?.simpleName + ?: throw BluePrintException("filed to get simple name.") + return when (simpleName) { + "String", "Date" -> BluePrintConstants.DATA_TYPE_STRING + "int" -> BluePrintConstants.DATA_TYPE_INTEGER + "Boolean" -> BluePrintConstants.DATA_TYPE_BOOLEAN + "Float" -> BluePrintConstants.DATA_TYPE_FLOAT + "Double" -> BluePrintConstants.DATA_TYPE_DOUBLE + "List" -> BluePrintConstants.DATA_TYPE_LIST + "Map" -> BluePrintConstants.DATA_TYPE_MAP + "Object", "JsonNode", "ObjectNode", "ArrayNode" -> BluePrintConstants.DATA_TYPE_JSON + else -> simpleName + } +} \ No newline at end of file diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt index d148745df..c77427b01 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt @@ -24,6 +24,7 @@ import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils import org.onap.ccsdk.cds.controllerblueprints.core.utils.JsonParserUtils import org.slf4j.LoggerFactory import org.slf4j.helpers.MessageFormatter +import java.lang.Float import kotlin.reflect.KClass /** @@ -93,6 +94,19 @@ fun T.asJsonPrimitive(): JsonNode { } } +/** Based on Blueprint DataType Convert string value to JsonNode Type **/ +fun String.asJsonType(bpDataType: String): JsonNode { + return when (bpDataType.toLowerCase()) { + BluePrintConstants.DATA_TYPE_STRING -> this.asJsonPrimitive() + BluePrintConstants.DATA_TYPE_BOOLEAN -> java.lang.Boolean.valueOf(this).asJsonPrimitive() + BluePrintConstants.DATA_TYPE_INTEGER -> Integer.valueOf(this).asJsonPrimitive() + BluePrintConstants.DATA_TYPE_FLOAT -> Float.valueOf(this).asJsonPrimitive() + BluePrintConstants.DATA_TYPE_DOUBLE -> java.lang.Double.valueOf(this).asJsonPrimitive() + // For List, Map and Complex Types. + else -> this.jsonAsJsonType() + } +} + /** * Utility to convert Complex or Primitive object to Json Type. */ @@ -156,6 +170,11 @@ fun ArrayNode.asListOfString(): List { return JacksonUtils.getListFromJsonNode(this, String::class.java) } +fun JsonNode.asType(clazzType: Class): T { + return JacksonUtils.readValue(this, clazzType) + ?: throw BluePrintException("couldn't convert JsonNode of type $clazzType") +} + fun JsonNode.asListOfString(): List { check(this is ArrayNode) { "JsonNode is not of type ArrayNode" } return this.asListOfString() @@ -260,6 +279,9 @@ fun isNotBlank(value: String?): Boolean { return value != null && value.isNotBlank() } +fun T?.emptyTONull(): String? { + return if (this == null || this.isEmpty()) null else this +} fun nullToEmpty(value: String?): String { return if (isNotEmpty(value)) value!! else "" diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/annotations/BluePrintsAnnotations.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/annotations/BluePrintsAnnotations.kt new file mode 100644 index 000000000..94392b992 --- /dev/null +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/annotations/BluePrintsAnnotations.kt @@ -0,0 +1,97 @@ +/* + * Copyright © 2019 IBM. + * + * 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.onap.ccsdk.cds.controllerblueprints.core.annotations + + +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants +import kotlin.reflect.KClass + +@Target(AnnotationTarget.CLASS) +annotation class BluePrintsDataType( + val name: String, + val version: String = BluePrintConstants.DEFAULT_VERSION_NUMBER, + val description: String, + val derivedFrom: String = "tosca.datatypes.root" +) + +@Target(AnnotationTarget.CLASS) +annotation class BluePrintsWorkflowInput + +@Target(AnnotationTarget.CLASS) +annotation class BluePrintsWorkflowOutput + +@Target(AnnotationTarget.CLASS) +annotation class BluePrintsNodeType(val propertiesType: KClass<*>, val attributesType: KClass<*>, + val inputsType: KClass<*>, val outputsType: KClass<*>) + +@Target(AnnotationTarget.FIELD, AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.PROPERTY) +annotation class BluePrintsProperty( + val name: String = "", + val description: String = "" +) + +@Target(AnnotationTarget.FIELD, AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.PROPERTY) +@Repeatable +annotation class BluePrintsConstrain() + +@Target(AnnotationTarget.FIELD, AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.PROPERTY) +annotation class PropertyDefaultValue(val value: String) + +annotation class PropertyValidValue(val value: String) + +@Target(AnnotationTarget.FIELD, AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.PROPERTY) +annotation class InputExpression( + val propertyName: String +) + +@Target(AnnotationTarget.FIELD, AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.PROPERTY) +annotation class PropertyExpression( + val modelableEntityName: String = "SELF", + val reqOrCapEntityName: String = "", + val propertyName: String, + val subPropertyName: String = "" +) + +@Target(AnnotationTarget.FIELD, AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.PROPERTY) +annotation class AttributeExpression( + val modelableEntityName: String = "SELF", + val reqOrCapEntityName: String = "", + val attributeName: String, + val subAttributeName: String = "" +) + +@Target(AnnotationTarget.FIELD, AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.PROPERTY) +annotation class ArtifactExpression( + val modelableEntityName: String = "SELF", + val artifactName: String, + val location: String = "LOCAL_FILE", + val remove: Boolean = false +) + +@Target(AnnotationTarget.FIELD, AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.PROPERTY) +annotation class OperationOutputExpression( + val modelableEntityName: String = "SELF", + val interfaceName: String, + val operationName: String, + val propertyName: String, + val subPropertyName: String = "" +) + +@Target(AnnotationTarget.FIELD, AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.PROPERTY) +annotation class DSLExpression( + val propertyName: String +) \ No newline at end of file diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BluePrintDSL.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BluePrintDSL.kt index c88408f19..01c6a13be 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BluePrintDSL.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BluePrintDSL.kt @@ -19,6 +19,7 @@ package org.onap.ccsdk.cds.controllerblueprints.core.dsl import com.fasterxml.jackson.databind.JsonNode import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintTypes +import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive import org.onap.ccsdk.cds.controllerblueprints.core.data.* import org.onap.ccsdk.cds.controllerblueprints.core.jsonAsJsonType @@ -63,56 +64,66 @@ fun relationshipType(id: String, version: String, derivedFrom: String, descripti return RelationshipTypeBuilder(id, version, derivedFrom, description).apply(block).build() } +// DSL Function +fun dslExpression(key: String): JsonNode { + return ("*$key").asJsonPrimitive() +} // Input Function -fun getInput(inputKey: String): JsonNode { +fun getInput(inputKey: String, jsonPath: String? = null): JsonNode { return """{"get_input": "$inputKey"}""".jsonAsJsonType() } -fun getAttribute(attributeId: String): JsonNode { - return """{"get_attribute": ["SELF", "$attributeId"]}""".jsonAsJsonType() -} - -fun getAttribute(attributeId: String, jsonPath: String): JsonNode { - return """{"get_attribute": ["SELF", "$attributeId", "$jsonPath"]}""".jsonAsJsonType() +fun getAttribute(attributeId: String, jsonPath: String? = null): JsonNode { + return getNodeTemplateAttribute("SELF", attributeId, jsonPath) } fun getNodeTemplateAttribute(nodeTemplateId: String, attributeId: String): JsonNode { - return """{"get_attribute": ["$nodeTemplateId", "$attributeId"]}""".jsonAsJsonType() + return getNodeTemplateAttribute(nodeTemplateId, attributeId, null) } -fun getNodeTemplateAttribute(nodeTemplateId: String, attributeId: String, jsonPath: String): JsonNode { - return """{"get_attribute": ["$nodeTemplateId", "$attributeId", "$jsonPath]}""".jsonAsJsonType() +fun getNodeTemplateAttribute(nodeTemplateId: String, attributeId: String, jsonPath: String?): JsonNode { + return if (jsonPath.isNullOrEmpty() || jsonPath.isNullOrBlank()) { + """{"get_attribute": ["$nodeTemplateId", "$attributeId"]}""".jsonAsJsonType() + } else { + """{"get_attribute": ["$nodeTemplateId", "$attributeId", "$jsonPath"]}""".jsonAsJsonType() + } } // Property Function -fun getProperty(propertyId: String): JsonNode { - return """{"get_property": ["SELF", "$propertyId"]}""".jsonAsJsonType() -} - -fun getProperty(propertyId: String, jsonPath: String): JsonNode { - return """{"get_property": ["SELF", "$propertyId", "$jsonPath"]}""".jsonAsJsonType() +fun getProperty(propertyId: String, jsonPath: String? = null): JsonNode { + return getNodeTemplateProperty("SELF", propertyId, jsonPath) } fun getNodeTemplateProperty(nodeTemplateName: String, propertyId: String): JsonNode { - return """{"get_property": ["$nodeTemplateName", "$propertyId"]}""".jsonAsJsonType() + return getNodeTemplateProperty(nodeTemplateName, propertyId, null) } -fun getNodeTemplateProperty(nodeTemplateName: String, propertyId: String, jsonPath: String): JsonNode { - return """{"get_property": ["$nodeTemplateName", "$propertyId", "$jsonPath]}""".jsonAsJsonType() +fun getNodeTemplateProperty(nodeTemplateName: String, propertyId: String, jsonPath: String?): JsonNode { + return if (jsonPath.isNullOrEmpty() || jsonPath.isNullOrBlank()) { + """{"get_property": ["$nodeTemplateName", "$propertyId"]}""".jsonAsJsonType() + } else { + """{"get_property": ["$nodeTemplateName", "$propertyId", "$jsonPath"]}""".jsonAsJsonType() + } } // Artifact Function fun getArtifact(artifactId: String): JsonNode { - return """{"get_artifact": ["SELF", "$artifactId"]}""".jsonAsJsonType() + return getNodeTemplateArtifact("SELF", artifactId) } fun getNodeTemplateArtifact(nodeTemplateName: String, artifactId: String): JsonNode { return """{"get_artifact": ["$nodeTemplateName", "$artifactId"]}""".jsonAsJsonType() } +// Operation Function + +fun getNodeTemplateOperationOutput(nodeTemplateName: String, interfaceName: String, propertyId: String, + jsonPath: String? = null): JsonNode { + return """{"get_operation_output": ["$nodeTemplateName", "$interfaceName", "process","$propertyId","$jsonPath" ]}""".trimMargin().jsonAsJsonType() +} /** Blueprint Type Extensions */ diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BluePrintServiceDSLBuilder.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BluePrintServiceDSLBuilder.kt index c9f7d507c..06d3421c0 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BluePrintServiceDSLBuilder.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BluePrintServiceDSLBuilder.kt @@ -17,9 +17,9 @@ package org.onap.ccsdk.cds.controllerblueprints.core.dsl import com.fasterxml.jackson.databind.JsonNode -import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants -import org.onap.ccsdk.cds.controllerblueprints.core.asJsonType +import org.onap.ccsdk.cds.controllerblueprints.core.* import org.onap.ccsdk.cds.controllerblueprints.core.data.* +import kotlin.reflect.KClass class ServiceTemplateBuilder(private val name: String, private val version: String, @@ -54,6 +54,14 @@ class ServiceTemplateBuilder(private val name: String, imports.add(importDefinition) } + fun dsl(id: String, kclass: KClass<*>) { + dsl(id, kclass.asPropertyDefinitionMap().asJsonNode()) + } + + fun dataType(dataType: KClass<*>) { + dataType(dataType.asBluePrintsDataTypes()) + } + fun dsl(id: String, content: Any) { dsl(id, content.asJsonType()) } diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BluePrintWorkflowDSLBuilder.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BluePrintWorkflowDSLBuilder.kt index f98cf58d3..6d46ac7ad 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BluePrintWorkflowDSLBuilder.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BluePrintWorkflowDSLBuilder.kt @@ -17,10 +17,12 @@ package org.onap.ccsdk.cds.controllerblueprints.core.dsl import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants +import org.onap.ccsdk.cds.controllerblueprints.core.asPropertyDefinitionMap import org.onap.ccsdk.cds.controllerblueprints.core.data.Activity import org.onap.ccsdk.cds.controllerblueprints.core.data.PropertyDefinition import org.onap.ccsdk.cds.controllerblueprints.core.data.Step import org.onap.ccsdk.cds.controllerblueprints.core.data.Workflow +import kotlin.reflect.KClass class WorkflowBuilder(private val id: String, private val description: String) { @@ -46,6 +48,10 @@ class WorkflowBuilder(private val id: String, private val description: String) { steps!![id] = StepBuilder(id, target, description).apply(block).build() } + fun inputs(kClazz: KClass<*>) { + inputs = kClazz.asPropertyDefinitionMap() + } + fun inputs(block: PropertiesDefinitionBuilder.() -> Unit) { inputs = PropertiesDefinitionBuilder().apply(block).build() } @@ -54,6 +60,10 @@ class WorkflowBuilder(private val id: String, private val description: String) { outputs = PropertiesDefinitionBuilder().apply(block).build() } + fun outputs(kClazz: KClass<*>) { + outputs = kClazz.asPropertyDefinitionMap() + } + fun build(): Workflow { workflow.id = id workflow.description = description -- cgit 1.2.3-korg