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
import hep.dataforge.Named
import hep.dataforge.description.ValueDescriptor
import hep.dataforge.meta.*
import hep.dataforge.names.Name
import java.util.*

View File

@ -14,19 +14,10 @@
* limitations under the License.
*/
/*
* 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
package hep.dataforge.descriptors
import hep.dataforge.Named
import hep.dataforge.meta.*
import hep.dataforge.names.AnonymousNotAlowed
import hep.dataforge.values.BooleanValue
import hep.dataforge.values.Value
import hep.dataforge.values.ValueType
import hep.dataforge.values.*
/**
* A descriptor for meta value
@ -35,54 +26,54 @@ import hep.dataforge.values.ValueType
*
* @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.
*
* @return
*/
val default by meta.value()
var default: Value? by value()
/**
* True if multiple values with this name are allowed.
*
* @return
*/
val multiple: Boolean by meta.boolean(false)
var multiple: Boolean by boolean(false)
/**
* True if the value is required
*
* @return
*/
val required: Boolean by meta.boolean(default == null)
var required: Boolean by boolean { default == null }
/**
* Value name
*
* @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
*
* @return
*/
val info: String by stringValue(def = "")
var info: String? by string()
/**
* A list of allowed ValueTypes. Empty if any value type allowed
*
* @return
*/
val type: List<ValueType> by customValue(def = emptyList()) {
it.list.map { v -> ValueType.valueOf(v.string) }
var type: List<ValueType> by value().map {
it?.list?.map { v -> ValueType.valueOf(v.string) } ?: emptyList()
}
val tags: List<String> by customValue(def = emptyList()) {
meta.getStringArray("tags").toList()
var tags: List<String> by value().map { value ->
value?.list?.map { it.string } ?: emptyList()
}
/**
@ -92,7 +83,7 @@ class ValueDescriptor(val meta: Meta) : MetaRepr {
* @param value
* @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(
value
))
@ -104,96 +95,74 @@ class ValueDescriptor(val meta: Meta) : MetaRepr {
*
* @return
*/
val allowedValues: List<Value> by customValue(
def = if (type.size == 1 && type[0] === ValueType.BOOLEAN) {
listOf(BooleanValue.TRUE, BooleanValue.FALSE)
var allowedValues: List<Value> by value().map {
it?.list ?: if (type.size == 1 && type[0] === ValueType.BOOLEAN) {
listOf(True, False)
} else {
emptyList()
}
) { it.list }
}
companion object {
companion object : SpecificationCompanion<ValueDescriptor> {
/**
* Build a value descriptor from annotation
*/
fun build(def: ValueDef): ValueDescriptor {
val builder = MetaBuilder("value")
.setValue("name", def.key)
override fun wrap(config: Config): ValueDescriptor = ValueDescriptor(config)
if (def.type.isNotEmpty()) {
builder.setValue("type", def.type)
}
if (def.multiple) {
builder.setValue("multiple", def.multiple)
}
if (!def.info.isEmpty()) {
builder.setValue("info", def.info)
}
if (def.allowed.isNotEmpty()) {
builder.setValue("allowedValues", def.allowed)
} else if (def.enumeration != Any::class) {
if (def.enumeration.java.isEnum) {
val values = def.enumeration.java.enumConstants
builder.setValue("allowedValues", values.map { it.toString() })
} else {
throw RuntimeException("Only enumeration classes are allowed in 'enumeration' annotation property")
}
}
if (def.def.isNotEmpty()) {
builder.setValue("default", def.def)
} else if (!def.required) {
builder.setValue("required", def.required)
}
if (def.tags.isNotEmpty()) {
builder.setValue("tags", def.tags)
}
return ValueDescriptor(builder)
}
/**
* Build a value descriptor from its fields
*/
fun build(
name: String,
info: String = "",
defaultValue: Any? = null,
required: Boolean = false,
multiple: Boolean = false,
types: List<ValueType> = emptyList(),
allowedValues: List<Any> = emptyList()
): ValueDescriptor {
val valueBuilder = buildMeta("value") {
"name" to name
if (!types.isEmpty()) "type" to types
if (required) "required" to required
if (multiple) "multiple" to multiple
if (!info.isEmpty()) "info" to info
if (defaultValue != null) "default" to defaultValue
if (!allowedValues.isEmpty()) "allowedValues" to allowedValues
}.build()
return ValueDescriptor(valueBuilder)
}
/**
* Build empty value descriptor
*/
fun empty(valueName: String): ValueDescriptor {
val builder = MetaBuilder("value")
.setValue("name", valueName)
return ValueDescriptor(builder)
}
/**
* Merge two separate value descriptors
*/
fun merge(primary: ValueDescriptor, secondary: ValueDescriptor): ValueDescriptor {
return ValueDescriptor(Laminate(primary.meta, secondary.meta))
}
// /**
// * 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) {
// builder.setValue("multiple", def.multiple)
// }
//
// if (!def.info.isEmpty()) {
// builder.setValue("info", def.info)
// }
//
// if (def.allowed.isNotEmpty()) {
// builder.setValue("allowedValues", def.allowed)
// } else if (def.enumeration != Any::class) {
// if (def.enumeration.java.isEnum) {
// val values = def.enumeration.java.enumConstants
// builder.setValue("allowedValues", values.map { it.toString() })
// } else {
// throw RuntimeException("Only enumeration classes are allowed in 'enumeration' annotation property")
// }
// }
//
// if (def.def.isNotEmpty()) {
// builder.setValue("default", def.def)
// } else if (!def.required) {
// builder.setValue("required", def.required)
// }
//
// if (def.tags.isNotEmpty()) {
// builder.setValue("tags", def.tags)
// }
// return ValueDescriptor(builder)
// }
//
// /**
// * Build empty value descriptor
// */
// fun empty(valueName: String): ValueDescriptor {
// val builder = MetaBuilder("value")
// .setValue("name", valueName)
// return ValueDescriptor(builder)
// }
//
// /**
// * 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
*/
fun Configurable.value(default: Value = Null, key: String? = null) =
ValueConfigDelegate(config, key, default)
fun Configurable.value(default: Any = Null, key: String? = null) =
ValueConfigDelegate(config, key, Value.of(default))
fun Configurable.string(default: String? = null, key: String? = null) =
StringConfigDelegate(config, key, default)
@ -28,15 +28,28 @@ fun Configurable.child(key: String? = null) = MetaNodeDelegate(config, key)
@JvmName("safeString")
fun Configurable.string(default: String, key: String? = null) =
SafeStringConfigDelegate(config, key, default)
SafeStringConfigDelegate(config, key) { default }
@JvmName("safeBoolean")
fun Configurable.boolean(default: Boolean, key: String? = null) =
SafeBooleanConfigDelegate(config, key, default)
SafeBooleanConfigDelegate(config, key) { default }
@JvmName("safeNumber")
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)
inline fun <reified E : Enum<E>> Configurable.enum(default: E, key: String? = null) =
SafeEnumvConfigDelegate(config, key, default) { enumValueOf(it) }

View File

@ -183,6 +183,9 @@ class ValueConfigDelegate<M : MutableMeta<M>>(
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>>(