Descriptors

This commit is contained in:
Alexander Nozik 2019-03-18 20:34:06 +03:00
parent 47e39ae0ac
commit 9fd89a5b60
5 changed files with 245 additions and 112 deletions

View File

@ -22,7 +22,6 @@
package hep.dataforge.descriptors package hep.dataforge.descriptors
import hep.dataforge.Named import hep.dataforge.Named
import hep.dataforge.description.ValueDescriptor
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.names.Name import hep.dataforge.names.Name
import java.util.* import java.util.*

View File

@ -14,19 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
/* package hep.dataforge.descriptors
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package hep.dataforge.description
import hep.dataforge.Named
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.names.AnonymousNotAlowed import hep.dataforge.values.*
import hep.dataforge.values.BooleanValue
import hep.dataforge.values.Value
import hep.dataforge.values.ValueType
/** /**
* A descriptor for meta value * A descriptor for meta value
@ -35,54 +26,54 @@ import hep.dataforge.values.ValueType
* *
* @author Alexander Nozik * @author Alexander Nozik
*/ */
class ValueDescriptor(val meta: Meta) : MetaRepr { class ValueDescriptor(override val config: Config) : Specification {
/** /**
* The default for this value. Null if there is no default. * The default for this value. Null if there is no default.
* *
* @return * @return
*/ */
val default by meta.value() var default: Value? by value()
/** /**
* True if multiple values with this name are allowed. * True if multiple values with this name are allowed.
* *
* @return * @return
*/ */
val multiple: Boolean by meta.boolean(false) var multiple: Boolean by boolean(false)
/** /**
* True if the value is required * True if the value is required
* *
* @return * @return
*/ */
val required: Boolean by meta.boolean(default == null) var required: Boolean by boolean { default == null }
/** /**
* Value name * Value name
* *
* @return * @return
*/ */
val name: String by meta.string{ error("Anonimous descriptors are not allowed")} var name: String by string { error("Anonymous descriptors are not allowed") }
/** /**
* The value info * The value info
* *
* @return * @return
*/ */
val info: String by stringValue(def = "") var info: String? by string()
/** /**
* A list of allowed ValueTypes. Empty if any value type allowed * A list of allowed ValueTypes. Empty if any value type allowed
* *
* @return * @return
*/ */
val type: List<ValueType> by customValue(def = emptyList()) { var type: List<ValueType> by value().map {
it.list.map { v -> ValueType.valueOf(v.string) } it?.list?.map { v -> ValueType.valueOf(v.string) } ?: emptyList()
} }
val tags: List<String> by customValue(def = emptyList()) { var tags: List<String> by value().map { value ->
meta.getStringArray("tags").toList() value?.list?.map { it.string } ?: emptyList()
} }
/** /**
@ -92,7 +83,7 @@ class ValueDescriptor(val meta: Meta) : MetaRepr {
* @param value * @param value
* @return * @return
*/ */
fun isValueAllowed(value: Value): Boolean { fun isAllowedValue(value: Value): Boolean {
return (type.isEmpty() || type.contains(ValueType.STRING) || type.contains(value.type)) && (allowedValues.isEmpty() || allowedValues.contains( return (type.isEmpty() || type.contains(ValueType.STRING) || type.contains(value.type)) && (allowedValues.isEmpty() || allowedValues.contains(
value value
)) ))
@ -104,96 +95,74 @@ class ValueDescriptor(val meta: Meta) : MetaRepr {
* *
* @return * @return
*/ */
val allowedValues: List<Value> by customValue( var allowedValues: List<Value> by value().map {
def = if (type.size == 1 && type[0] === ValueType.BOOLEAN) { it?.list ?: if (type.size == 1 && type[0] === ValueType.BOOLEAN) {
listOf(BooleanValue.TRUE, BooleanValue.FALSE) listOf(True, False)
} else { } else {
emptyList() emptyList()
} }
) { it.list }
companion object {
/**
* Build a value descriptor from annotation
*/
fun build(def: ValueDef): ValueDescriptor {
val builder = MetaBuilder("value")
.setValue("name", def.key)
if (def.type.isNotEmpty()) {
builder.setValue("type", def.type)
} }
if (def.multiple) { companion object : SpecificationCompanion<ValueDescriptor> {
builder.setValue("multiple", def.multiple)
}
if (!def.info.isEmpty()) { override fun wrap(config: Config): ValueDescriptor = ValueDescriptor(config)
builder.setValue("info", def.info)
}
if (def.allowed.isNotEmpty()) { // /**
builder.setValue("allowedValues", def.allowed) // * Build a value descriptor from annotation
} else if (def.enumeration != Any::class) { // */
if (def.enumeration.java.isEnum) { // fun build(def: ValueDef): ValueDescriptor {
val values = def.enumeration.java.enumConstants // val builder = MetaBuilder("value")
builder.setValue("allowedValues", values.map { it.toString() }) // .setValue("name", def.key)
} else { //
throw RuntimeException("Only enumeration classes are allowed in 'enumeration' annotation property") // if (def.type.isNotEmpty()) {
} // builder.setValue("type", def.type)
} // }
//
if (def.def.isNotEmpty()) { // if (def.multiple) {
builder.setValue("default", def.def) // builder.setValue("multiple", def.multiple)
} else if (!def.required) { // }
builder.setValue("required", def.required) //
} // if (!def.info.isEmpty()) {
// builder.setValue("info", def.info)
if (def.tags.isNotEmpty()) { // }
builder.setValue("tags", def.tags) //
} // if (def.allowed.isNotEmpty()) {
return ValueDescriptor(builder) // builder.setValue("allowedValues", def.allowed)
} // } else if (def.enumeration != Any::class) {
// if (def.enumeration.java.isEnum) {
/** // val values = def.enumeration.java.enumConstants
* Build a value descriptor from its fields // builder.setValue("allowedValues", values.map { it.toString() })
*/ // } else {
fun build( // throw RuntimeException("Only enumeration classes are allowed in 'enumeration' annotation property")
name: String, // }
info: String = "", // }
defaultValue: Any? = null, //
required: Boolean = false, // if (def.def.isNotEmpty()) {
multiple: Boolean = false, // builder.setValue("default", def.def)
types: List<ValueType> = emptyList(), // } else if (!def.required) {
allowedValues: List<Any> = emptyList() // builder.setValue("required", def.required)
): ValueDescriptor { // }
val valueBuilder = buildMeta("value") { //
"name" to name // if (def.tags.isNotEmpty()) {
if (!types.isEmpty()) "type" to types // builder.setValue("tags", def.tags)
if (required) "required" to required // }
if (multiple) "multiple" to multiple // return ValueDescriptor(builder)
if (!info.isEmpty()) "info" to info // }
if (defaultValue != null) "default" to defaultValue //
if (!allowedValues.isEmpty()) "allowedValues" to allowedValues // /**
}.build() // * Build empty value descriptor
return ValueDescriptor(valueBuilder) // */
} // fun empty(valueName: String): ValueDescriptor {
// val builder = MetaBuilder("value")
/** // .setValue("name", valueName)
* Build empty value descriptor // return ValueDescriptor(builder)
*/ // }
fun empty(valueName: String): ValueDescriptor { //
val builder = MetaBuilder("value") // /**
.setValue("name", valueName) // * Merge two separate value descriptors
return ValueDescriptor(builder) // */
} // fun merge(primary: ValueDescriptor, secondary: ValueDescriptor): ValueDescriptor {
// return ValueDescriptor(Laminate(primary.meta, secondary.meta))
/** // }
* Merge two separate value descriptors
*/
fun merge(primary: ValueDescriptor, secondary: ValueDescriptor): ValueDescriptor {
return ValueDescriptor(Laminate(primary.meta, secondary.meta))
}
} }
} }

View File

@ -0,0 +1,149 @@
/*
* Copyright 2018 Alexander Nozik.
*
* 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 hep.dataforge.descriptors
import hep.dataforge.values.ValueType
import kotlin.reflect.KClass
@Target(AnnotationTarget.PROPERTY)
@MustBeDocumented
annotation class ValueDef(
val key: String,
val type: Array<ValueType> = [ValueType.STRING],
val multiple: Boolean = false,
val def: String = "",
val info: String = "",
val required: Boolean = true,
val allowed: Array<String> = [],
val enumeration: KClass<*> = Any::class,
val tags: Array<String> = []
)
@MustBeDocumented
annotation class NodeDef(
val key: String,
val info: String = "",
val multiple: Boolean = false,
val required: Boolean = false,
val tags: Array<String> = [],
/**
* A list of child value descriptors
*/
val values: Array<ValueDef> = [],
/**
* A target class for this node to describe
* @return
*/
val type: KClass<*> = Any::class,
/**
* The DataForge path to the resource containing the description. Following targets are supported:
*
* 1. resource
* 1. file
* 1. class
* 1. method
* 1. property
*
*
* Does not work if [type] is provided
*
* @return
*/
val descriptor: String = ""
)
/**
* Description text for meta property, node or whole object
*/
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class Description(val value: String)
/**
* Annotation for value property which states that lists are expected
*/
@Target(AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class Multiple
/**
* Descriptor target
* The DataForge path to the resource containing the description. Following targets are supported:
* 1. resource
* 1. file
* 1. class
* 1. method
* 1. property
*
*
* Does not work if [type] is provided
*/
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class Descriptor(val value: String)
/**
* Aggregator class for descriptor nodes
*/
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class DescriptorNodes(vararg val nodes: NodeDef)
/**
* Aggregator class for descriptor values
*/
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class DescriptorValues(vararg val nodes: ValueDef)
/**
* Alternative name for property descriptor declaration
*/
@Target(AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class DescriptorName(val name: String)
@Target(AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class DescriptorValue(val def: ValueDef)
//TODO enter fields directly?
@Target(AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class ValueProperty(
val name: String = "",
val type: Array<ValueType> = [ValueType.STRING],
val multiple: Boolean = false,
val def: String = "",
val enumeration: KClass<*> = Any::class,
val tags: Array<String> = []
)
@Target(AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class NodeProperty(val name: String = "")

View File

@ -10,8 +10,8 @@ import kotlin.jvm.JvmName
/** /**
* A property delegate that uses custom key * A property delegate that uses custom key
*/ */
fun Configurable.value(default: Value = Null, key: String? = null) = fun Configurable.value(default: Any = Null, key: String? = null) =
ValueConfigDelegate(config, key, default) ValueConfigDelegate(config, key, Value.of(default))
fun Configurable.string(default: String? = null, key: String? = null) = fun Configurable.string(default: String? = null, key: String? = null) =
StringConfigDelegate(config, key, default) StringConfigDelegate(config, key, default)
@ -28,15 +28,28 @@ fun Configurable.child(key: String? = null) = MetaNodeDelegate(config, key)
@JvmName("safeString") @JvmName("safeString")
fun Configurable.string(default: String, key: String? = null) = fun Configurable.string(default: String, key: String? = null) =
SafeStringConfigDelegate(config, key, default) SafeStringConfigDelegate(config, key) { default }
@JvmName("safeBoolean") @JvmName("safeBoolean")
fun Configurable.boolean(default: Boolean, key: String? = null) = fun Configurable.boolean(default: Boolean, key: String? = null) =
SafeBooleanConfigDelegate(config, key, default) SafeBooleanConfigDelegate(config, key) { default }
@JvmName("safeNumber") @JvmName("safeNumber")
fun Configurable.number(default: Number, key: String? = null) = fun Configurable.number(default: Number, key: String? = null) =
SafeNumberConfigDelegate(config, key) { default }
@JvmName("safeString")
fun Configurable.string(key: String? = null, default: () -> String) =
SafeStringConfigDelegate(config, key, default)
@JvmName("safeBoolean")
fun Configurable.boolean(key: String? = null, default: () -> Boolean) =
SafeBooleanConfigDelegate(config, key, default)
@JvmName("safeNumber")
fun Configurable.number(key: String? = null, default: () -> Number) =
SafeNumberConfigDelegate(config, key, default) SafeNumberConfigDelegate(config, key, default)
inline fun <reified E : Enum<E>> Configurable.enum(default: E, key: String? = null) = inline fun <reified E : Enum<E>> Configurable.enum(default: E, key: String? = null) =
SafeEnumvConfigDelegate(config, key, default) { enumValueOf(it) } SafeEnumvConfigDelegate(config, key, default) { enumValueOf(it) }

View File

@ -183,6 +183,9 @@ class ValueConfigDelegate<M : MutableMeta<M>>(
config.setValue(name, value) config.setValue(name, value)
} }
} }
fun <T> map(writer: (T) -> Value? = { Value.of(it) }, reader: (Value?) -> T) =
ReadWriteDelegateWrapper(this, reader, writer)
} }
class StringConfigDelegate<M : MutableMeta<M>>( class StringConfigDelegate<M : MutableMeta<M>>(