Skip to content

Commit

Permalink
feature: Add Support for unit, min and max attributes of Specification
Browse files Browse the repository at this point in the history
  • Loading branch information
wba2hi committed Mar 21, 2024
1 parent 6f21d80 commit 49e1b8f
Show file tree
Hide file tree
Showing 16 changed files with 19,263 additions and 184 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class VssModelGeneratorProcessor(
}

val vssPathToVssNodeElement = simpleNodeElements
.distinctBy { it.uuid }
.distinctBy { it.vssPath }
.associateBy({ VssPath(it.vssPath) }, { it })

generateModelFiles(vssPathToVssNodeElement)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2023 - 2024 Contributors to the Eclipse Foundation
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
*
*/

package org.eclipse.kuksa.vssprocessor.parser

/**
* Will be thrown when an error occurred while parsing a File.
*/
class FileParseException(
override val message: String? = null,
override val cause: Throwable? = null,
) : Exception(message, cause)
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2023 - 2024 Contributors to the Eclipse Foundation
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
*
*/

package org.eclipse.kuksa.vssprocessor.parser

const val ROOT_KEY_VEHICLE = "Vehicle"

const val KEY_DATA_DESCRIPTION = "description"
const val KEY_DATA_TYPE = "type"
const val KEY_DATA_UUID = "uuid"
const val KEY_DATA_COMMENT = "comment"
const val KEY_DATA_DATATYPE = "datatype"
const val KEY_DATA_UNIT = "unit"
const val KEY_DATA_MIN = "min"
const val KEY_DATA_MAX = "max"
const val KEY_DATA_CHILDREN = "children"

val VSS_DATA_KEYS = listOf(
KEY_DATA_DESCRIPTION,
KEY_DATA_TYPE,
KEY_DATA_UUID,
KEY_DATA_COMMENT,
KEY_DATA_UNIT,
KEY_DATA_DATATYPE,
KEY_DATA_MIN,
KEY_DATA_MAX,
KEY_DATA_CHILDREN,
)
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,26 @@ package org.eclipse.kuksa.vssprocessor.parser.json
import com.google.gson.Gson
import com.google.gson.JsonObject
import com.google.gson.JsonParseException
import org.eclipse.kuksa.vssprocessor.parser.KEY_DATA_CHILDREN
import org.eclipse.kuksa.vssprocessor.parser.KEY_DATA_COMMENT
import org.eclipse.kuksa.vssprocessor.parser.KEY_DATA_DATATYPE
import org.eclipse.kuksa.vssprocessor.parser.KEY_DATA_DESCRIPTION
import org.eclipse.kuksa.vssprocessor.parser.KEY_DATA_MAX
import org.eclipse.kuksa.vssprocessor.parser.KEY_DATA_MIN
import org.eclipse.kuksa.vssprocessor.parser.KEY_DATA_TYPE
import org.eclipse.kuksa.vssprocessor.parser.KEY_DATA_UNIT
import org.eclipse.kuksa.vssprocessor.parser.KEY_DATA_UUID
import org.eclipse.kuksa.vssprocessor.parser.ROOT_KEY_VEHICLE
import org.eclipse.kuksa.vssprocessor.parser.VSS_DATA_KEYS
import org.eclipse.kuksa.vssprocessor.parser.VssParser
import org.eclipse.kuksa.vssprocessor.spec.VssDataType
import org.eclipse.kuksa.vssprocessor.spec.VssNodeProperty
import org.eclipse.kuksa.vssprocessor.spec.VssNodeSpecModel
import org.eclipse.kuksa.vssprocessor.spec.VssSignalProperty
import java.io.File
import java.io.IOException

private const val ROOT_KEY_VEHICLE = "Vehicle"

private const val KEY_DATA_DESCRIPTION = "description"
private const val KEY_DATA_TYPE = "type"
private const val KEY_DATA_UUID = "uuid"
private const val KEY_DATA_COMMENT = "comment"
private const val KEY_DATA_DATATYPE = "datatype"
private const val KEY_DATA_CHILDREN = "children"

internal class JsonVssParser : VssParser {
private val dataKeys = listOf(
KEY_DATA_DESCRIPTION,
KEY_DATA_TYPE,
KEY_DATA_UUID,
KEY_DATA_COMMENT,
KEY_DATA_DATATYPE,
KEY_DATA_CHILDREN,
)

override fun parseNodes(vssFile: File): List<VssNodeSpecModel> {
val vssNodeSpecModels = mutableListOf<VssNodeSpecModel>()
Expand Down Expand Up @@ -81,7 +78,7 @@ internal class JsonVssParser : VssParser {
val childrenJsonElement = jsonObject.getAsJsonObject(KEY_DATA_CHILDREN)

val filteredKeys = childrenJsonElement.asMap().keys
.filter { key -> !dataKeys.contains(key) }
.filter { key -> !VSS_DATA_KEYS.contains(key) }

filteredKeys.forEach { key ->
val childJsonElement = childrenJsonElement.getAsJsonObject(key)
Expand All @@ -98,16 +95,33 @@ internal class JsonVssParser : VssParser {
vssPath: String,
jsonObject: JsonObject,
): VssNodeSpecModel {
val uuid = jsonObject.get(KEY_DATA_UUID).asString
val uuid = jsonObject.get(KEY_DATA_UUID)?.asString
?: throw JsonParseException("Could not parse '$KEY_DATA_UUID' for '$vssPath'")

val type = jsonObject.get(KEY_DATA_TYPE).asString
val type = jsonObject.get(KEY_DATA_TYPE)?.asString
?: throw JsonParseException("Could not parse '$KEY_DATA_TYPE' for '$vssPath'")

val description = jsonObject.get(KEY_DATA_DESCRIPTION).asString ?: ""
val description = jsonObject.get(KEY_DATA_DESCRIPTION)?.asString ?: ""
val datatype = jsonObject.get(KEY_DATA_DATATYPE)?.asString ?: ""
val comment = jsonObject.get(KEY_DATA_COMMENT)?.asString ?: ""

return VssNodeSpecModel(uuid, vssPath, description, type, comment, datatype)
val unit = jsonObject.get(KEY_DATA_UNIT)?.asString ?: ""
val min = jsonObject.get(KEY_DATA_MIN)?.asString ?: ""
val max = jsonObject.get(KEY_DATA_MAX)?.asString ?: ""

val vssDataType = VssDataType.find(datatype)
val valueDataType = vssDataType.valueDataType

val vssNodeProperties = mutableSetOf(
VssNodeProperty(vssPath, KEY_DATA_UUID, uuid, String::class),
VssNodeProperty(vssPath, KEY_DATA_TYPE, type, String::class),
VssNodeProperty(vssPath, KEY_DATA_DESCRIPTION, description, String::class),
VssNodeProperty(vssPath, KEY_DATA_COMMENT, comment, String::class),
VssSignalProperty(vssPath, KEY_DATA_DATATYPE, datatype, valueDataType),
VssSignalProperty(vssPath, KEY_DATA_UNIT, unit, String::class),
VssSignalProperty(vssPath, KEY_DATA_MIN, min, valueDataType),
VssSignalProperty(vssPath, KEY_DATA_MAX, max, valueDataType),
)

return VssNodeSpecModel(vssPath, vssNodeProperties)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,37 +20,54 @@
package org.eclipse.kuksa.vssprocessor.parser.yaml

import org.eclipse.kuksa.vsscore.model.VssNode
import org.eclipse.kuksa.vssprocessor.parser.FileParseException
import org.eclipse.kuksa.vssprocessor.parser.KEY_DATA_COMMENT
import org.eclipse.kuksa.vssprocessor.parser.KEY_DATA_DATATYPE
import org.eclipse.kuksa.vssprocessor.parser.KEY_DATA_DESCRIPTION
import org.eclipse.kuksa.vssprocessor.parser.KEY_DATA_MAX
import org.eclipse.kuksa.vssprocessor.parser.KEY_DATA_MIN
import org.eclipse.kuksa.vssprocessor.parser.KEY_DATA_TYPE
import org.eclipse.kuksa.vssprocessor.parser.KEY_DATA_UNIT
import org.eclipse.kuksa.vssprocessor.parser.KEY_DATA_UUID
import org.eclipse.kuksa.vssprocessor.parser.VssParser
import org.eclipse.kuksa.vssprocessor.spec.VssDataType
import org.eclipse.kuksa.vssprocessor.spec.VssNodeProperty
import org.eclipse.kuksa.vssprocessor.spec.VssNodeSpecModel
import org.eclipse.kuksa.vssprocessor.spec.VssSignalProperty
import java.io.File
import java.io.IOException
import kotlin.reflect.KMutableProperty
import kotlin.reflect.KProperty
import kotlin.reflect.full.memberProperties

internal class YamlVssParser(private val elementDelimiter: String = "") : VssParser {
override fun parseNodes(vssFile: File): List<VssNodeSpecModel> {
val vssNodeElements = mutableListOf<VssNodeSpecModel>()
vssFile.useLines { lines ->
val yamlAttributes = mutableListOf<String>()
for (line in lines.toList()) {
val trimmedLine = line.trim()
if (trimmedLine == elementDelimiter) { // A new element will follow after the delimiter
parseYamlElement(yamlAttributes)?.let { element ->
vssNodeElements.add(element)
try {
vssFile.useLines { lines ->
val yamlAttributes = mutableListOf<String>()
for (line in lines.toList()) {
val trimmedLine = line.trim()
if (trimmedLine == elementDelimiter) { // A new element will follow after the delimiter
parseYamlElement(yamlAttributes).let { element ->
vssNodeElements.add(element)
}

yamlAttributes.clear()

continue
}

yamlAttributes.clear()

continue
yamlAttributes.add(trimmedLine)
}

yamlAttributes.add(trimmedLine)
}

// Add the last element because no empty line will follow
parseYamlElement(yamlAttributes)?.let { element ->
vssNodeElements.add(element)
// Add the last element because no empty line will follow
parseYamlElement(yamlAttributes).let { element ->
vssNodeElements.add(element)
}
}
} catch (e: FileParseException) {
throw IOException("Invalid VSS File: '${vssFile.path}'", e)
}

return vssNodeElements
Expand All @@ -62,40 +79,45 @@ internal class YamlVssParser(private val elementDelimiter: String = "") : VssPar
// description: Antilock Braking System signals.
// type: branch
// uuid: 219270ef27c4531f874bbda63743b330
private fun parseYamlElement(yamlElement: List<String>, delimiter: Char = ';'): VssNodeSpecModel? {
val elementVssPath = yamlElement.first().substringBefore(":")
private fun parseYamlElement(yamlElement: List<String>, delimiter: Char = ';'): VssNodeSpecModel {
val vssPath = yamlElement.first().substringBefore(":")

val yamlElementJoined = yamlElement
.joinToString(separator = delimiter.toString())
.substringAfter(delimiter) // Remove vssPath (already parsed)
.prependIndent(delimiter.toString()) // So the parsing is consistent for the first element
val members = VssNodeSpecModel::class.memberProperties
val fieldsToSet = mutableListOf<Pair<String, Any?>>()

// The VSSPath is an exception because it is parsed from the top level name.
val vssPathFieldInfo = Pair("vssPath", elementVssPath)
fieldsToSet.add(vssPathFieldInfo)

// Parse (example: "description: Antilock Braking System signals.") into name + value for all .yaml lines
for (member in members) {
val memberName = member.name
if (!yamlElementJoined.contains(memberName)) continue

// Also parse the delimiter to not confuse type != datatype
val memberValue = yamlElementJoined
.substringAfter("$delimiter$memberName: ")
.substringBefore(delimiter)

val fieldInfo = Pair(memberName, memberValue)
fieldsToSet.add(fieldInfo)
}

val vssNodeSpec = VssNodeSpecModel()
vssNodeSpec.setFields(fieldsToSet)

if (vssNodeSpec.uuid.isEmpty()) return null

return vssNodeSpec
val uuid = fetchValue(KEY_DATA_UUID, yamlElementJoined, delimiter)
?: throw FileParseException("Could not parse '$KEY_DATA_UUID' for '$vssPath'")

val type = fetchValue(KEY_DATA_TYPE, yamlElementJoined, delimiter)
?: throw FileParseException("Could not parse '$KEY_DATA_TYPE' for '$vssPath'")

val description = fetchValue(KEY_DATA_DESCRIPTION, yamlElementJoined, delimiter) ?: ""
val datatype = fetchValue(KEY_DATA_DATATYPE, yamlElementJoined, delimiter) ?: ""
val comment = fetchValue(KEY_DATA_COMMENT, yamlElementJoined, delimiter) ?: ""
val unit = fetchValue(KEY_DATA_UNIT, yamlElementJoined, delimiter) ?: ""
val min = fetchValue(KEY_DATA_MIN, yamlElementJoined, delimiter) ?: ""
val max = fetchValue(KEY_DATA_MAX, yamlElementJoined, delimiter) ?: ""

val vssDataType = VssDataType.find(datatype)
val valueDataType = vssDataType.valueDataType

val vssNodeProperties = mutableSetOf(
VssNodeProperty(vssPath, KEY_DATA_UUID, uuid, String::class),
VssNodeProperty(vssPath, KEY_DATA_TYPE, type, String::class),
VssNodeProperty(vssPath, KEY_DATA_DESCRIPTION, description, String::class),
VssNodeProperty(vssPath, KEY_DATA_COMMENT, comment, String::class),
VssSignalProperty(vssPath, KEY_DATA_DATATYPE, datatype, valueDataType),
VssSignalProperty(vssPath, KEY_DATA_UNIT, unit, String::class),
VssSignalProperty(vssPath, KEY_DATA_MIN, min, valueDataType),
VssSignalProperty(vssPath, KEY_DATA_MAX, max, valueDataType),
)

return VssNodeSpecModel(vssPath, vssNodeProperties)
}
}

Expand Down Expand Up @@ -123,3 +145,16 @@ private fun VssNode.setFields(
?.setter?.call(this, propertyValue)
}
}

private fun fetchValue(
nodeName: String,
yamlElementJoined: String,
delimiter: Char,
): String? {
// Also parse the delimiter to not confuse type != datatype
val value = yamlElementJoined
.substringAfter("$delimiter$nodeName: ")
.substringBefore(delimiter)

return value.ifEmpty { return null }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2023 - 2024 Contributors to the Eclipse Foundation
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
*
*/

package org.eclipse.kuksa.vssprocessor.spec

import kotlin.reflect.KClass

open class VssNodeProperty(
val vssPath: String,
val nodePropertyName: String,
val nodePropertyValue: String,
val dataType: KClass<*>,
) {
open val isCommon: Boolean = true

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

other as VssNodeProperty

return nodePropertyName == other.nodePropertyName
}

override fun hashCode(): Int {
return nodePropertyName.hashCode()
}
}

class VssSignalProperty(
vssPath: String,
nodePropertyName: String,
nodePropertyValue: String,
dataType: KClass<*>,
) : VssNodeProperty(vssPath, nodePropertyName, nodePropertyValue, dataType) {
override val isCommon: Boolean = false
}
Loading

0 comments on commit 49e1b8f

Please sign in to comment.