You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@daffodil.apache.org by sl...@apache.org on 2020/12/02 18:20:15 UTC
[incubator-daffodil] branch master updated: Add validation support
for tunables
This is an automated email from the ASF dual-hosted git repository.
slawrence pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-daffodil.git
The following commit(s) were added to refs/heads/master by this push:
new 7867d8e Add validation support for tunables
7867d8e is described below
commit 7867d8e0cb99ec6b09f0e1ce0791ce850642f7f2
Author: Steve Lawrence <sl...@apache.org>
AuthorDate: Fri Nov 20 13:22:02 2020 -0500
Add validation support for tunables
- Adds xs:restrictions to tunables for which there is only a valid range
within the range of the primitive type. Modifies the tunable generator
to convert these restrictions to code checks and throw an
IllegalArgumentException if outside the valid range.
- Also sorts the tunable by name so they are organized.
DAFFODIL-2432
---
.../daffodil/processor/TestSAXUnparseAPI.scala | 26 +--
.../resources/org/apache/daffodil/xsd/dafext.xsd | 211 ++++++++++++++++-----
.../apache/daffodil/propGen/TunableGenerator.scala | 103 ++++++++--
3 files changed, 258 insertions(+), 82 deletions(-)
diff --git a/daffodil-core/src/test/scala/org/apache/daffodil/processor/TestSAXUnparseAPI.scala b/daffodil-core/src/test/scala/org/apache/daffodil/processor/TestSAXUnparseAPI.scala
index de6f263..afd3937 100644
--- a/daffodil-core/src/test/scala/org/apache/daffodil/processor/TestSAXUnparseAPI.scala
+++ b/daffodil-core/src/test/scala/org/apache/daffodil/processor/TestSAXUnparseAPI.scala
@@ -20,8 +20,6 @@ package org.apache.daffodil.processor
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
-import scala.xml.SAXException
-
import javax.xml.parsers.SAXParserFactory
import org.apache.daffodil.Implicits.intercept
import org.apache.daffodil.xml.XMLUtils
@@ -50,24 +48,16 @@ class TestSAXUnparseAPI {
}
/**
- * Test the case when a user supplies 0 as the batch size. Minimum batchsize must be 1
+ * Test the case when a user supplies 0 as the batch size as soon as an
+ * invalid tunable is set. Minimum batchsize must be 1.
*/
@Test def testUnparseContentHandler_unparse_saxUnparseEventBatchSize_0(): Unit = {
- val dpT = testDataProcessor(testSchema, Map("saxUnparseEventBatchSize" -> "0"))
- val xmlReader: XMLReader = SAXParserFactory.newInstance.newSAXParser.getXMLReader
- val bao = new ByteArrayOutputStream()
- val wbc = java.nio.channels.Channels.newChannel(bao)
- val unparseContentHandler = dpT.newContentHandlerInstance(wbc)
- xmlReader.setContentHandler(unparseContentHandler)
- xmlReader.setFeature(XMLUtils.SAX_NAMESPACES_FEATURE, true)
- xmlReader.setFeature(XMLUtils.SAX_NAMESPACE_PREFIXES_FEATURE, true)
- val bai = new ByteArrayInputStream(testInfosetString.getBytes)
- val e = intercept[SAXException] {
- xmlReader.parse(new InputSource(bai))
- }
- val eMsg = e.getMessage
- assertTrue(eMsg.contains("invalid saxUnparseEventBatchSize"))
- assertTrue(eMsg.contains("minimum value is 1"))
+ val e = intercept[java.lang.IllegalArgumentException] {
+ testDataProcessor(testSchema, Map("saxUnparseEventBatchSize" -> "0"))
+ }
+ val eMsg = e.getMessage
+ assertTrue(eMsg.contains("saxUnparseEventBatchSize"))
+ assertTrue(eMsg.contains("0"))
}
@Test def testUnparseContentHandler_unparse_namespace_feature(): Unit = {
diff --git a/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/dafext.xsd b/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/dafext.xsd
index 6a7548c..fcdb128 100644
--- a/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/dafext.xsd
+++ b/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/dafext.xsd
@@ -79,6 +79,25 @@
</xs:simpleContent>
</xs:complexType>
+ <!--
+ This file is used by TunableGenerator.scala to generate code that parses and
+ validates tunable values. The following schema elements define these tunables
+ to be generated. Although this schema is verbose and repetitive, it makes it
+ relatively straightforward to parse and ensure we generate correct code. As
+ such, one must follow a strict pattern to ensure correct code is generated.
+
+ Each element representing a tunable must have an schema primitive as its type,
+ as determined by the tunables allowed value space. Each tunable must also have
+ a default value that is valid for the type. If an element needs additional
+ limitations beyond the value space of the type, then an xs:simpleType with
+ xs:restriction must be used. The base attribute of the restriction must be a
+ schema primitive type. Only the following restrictions are currently supported:
+
+ - minInclusive
+ - maxInclusive
+ - minExclusive
+ - maxExclusive
+ -->
<xs:element name="tunables">
<xs:complexType>
<xs:all>
@@ -110,55 +129,39 @@
</xs:documentation>
</xs:annotation>
</xs:element>
- <xs:element name="blobChunkSizeInBytes" type="xs:int" default="4096" minOccurs="0">
+ <xs:element name="blobChunkSizeInBytes" default="4096" minOccurs="0">
<xs:annotation>
<xs:documentation>
When reading/writing blob data, the maximum number of bytes to read/write at a time.
</xs:documentation>
</xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:int">
+ <xs:minInclusive value="1" />
+ </xs:restriction>
+ </xs:simpleType>
</xs:element>
- <xs:element name="outputStreamChunkSizeInBytes" type="xs:int" default="65536" minOccurs="0">
- <xs:annotation>
- <xs:documentation>
- When writing file data to the output stream during unparse, this
- is the maximum number of bytes to write at a time.
- </xs:documentation>
- </xs:annotation>
- </xs:element>
- <xs:element name="maxByteArrayOutputStreamBufferSizeInBytes" type="xs:long" default="2097152000" minOccurs="0">
- <xs:annotation>
- <xs:documentation>
- When unparsing, this is the maximum size of the buffer that the
- ByteArrayOutputStream can grow to before switching to a file based
- output stream.
- </xs:documentation>
- </xs:annotation>
- </xs:element>
- <xs:element name="tempFilePath" type="xs:string" default="" minOccurs="0">
+ <xs:element name="defaultEmptyElementParsePolicy" type="daf:TunableEmptyElementParsePolicy" default="treatAsEmpty" minOccurs="0">
<xs:annotation>
<xs:documentation>
- When unparsing, use this path to store temporary files that may be genrated.
- The default value (empty string) will result in the use of the java.io.tmpdir
- property being used as the path.
+ Defines the default empty element parse policy to use if it is not defined
+ in a schema. This is only used if requireEmptyElementParsePolicyProperty is
+ false.
</xs:documentation>
</xs:annotation>
</xs:element>
- <xs:element name="defaultInitialRegexMatchLimitInChars" type="xs:int" default="32" minOccurs="0">
+ <xs:element name="defaultInitialRegexMatchLimitInChars" default="32" minOccurs="0">
<xs:annotation>
<xs:documentation>
Deprecated. This tunable no longer has any affect and is only kept for
backwards compatability.
</xs:documentation>
</xs:annotation>
- </xs:element>
- <xs:element name="defaultEmptyElementParsePolicy" type="daf:TunableEmptyElementParsePolicy" default="treatAsEmpty" minOccurs="0">
- <xs:annotation>
- <xs:documentation>
- Defines the default empty element parse policy to use if it is not defined
- in a schema. This is only used if requireEmptyElementParsePolicyProperty is
- false.
- </xs:documentation>
- </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:int">
+ <xs:minInclusive value="1" />
+ </xs:restriction>
+ </xs:simpleType>
</xs:element>
<xs:element name="errorOnUnsupportedJavaVersion" type="xs:boolean" default="true" minOccurs="0">
<xs:annotation>
@@ -176,14 +179,19 @@
</xs:documentation>
</xs:annotation>
</xs:element>
- <xs:element name="initialElementOccurrencesHint" type="xs:int" default="10" minOccurs="0">
+ <xs:element name="initialElementOccurrencesHint" default="10" minOccurs="0">
<xs:annotation>
<xs:documentation>
Initial array buffer size allocated for recurring elements/arrays.
</xs:documentation>
</xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:int">
+ <xs:minInclusive value="1" />
+ </xs:restriction>
+ </xs:simpleType>
</xs:element>
- <xs:element name="initialRegexMatchLimitInCharacters" type="xs:int" default="64" minOccurs="0">
+ <xs:element name="initialRegexMatchLimitInCharacters" default="64" minOccurs="0">
<xs:annotation>
<xs:documentation>
Initial number of characters to match when performing regular expression
@@ -191,6 +199,11 @@
consumed up to the maximumRegexMatchLengthInCharacters tunable.
</xs:documentation>
</xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:int">
+ <xs:minInclusive value="1" />
+ </xs:restriction>
+ </xs:simpleType>
</xs:element>
<xs:element name="inputFileMemoryMapLowThreshold" type="xs:int" default="33554432" minOccurs="0">
<xs:annotation>
@@ -200,20 +213,44 @@
</xs:documentation>
</xs:annotation>
</xs:element>
- <xs:element name="maxBinaryDecimalVirtualPoint" type="xs:int" default="200" minOccurs="0">
+ <xs:element name="maxBinaryDecimalVirtualPoint" default="200" minOccurs="0">
<xs:annotation>
<xs:documentation>
The largest allowed value of the dfdl:binaryDecimalVirtualPoint property.
</xs:documentation>
</xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:int">
+ <xs:minInclusive value="1" />
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="maxByteArrayOutputStreamBufferSizeInBytes" default="2097152000" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>
+ When unparsing, this is the maximum size of the buffer that the
+ ByteArrayOutputStream can grow to before switching to a file based
+ output stream.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:int">
+ <xs:minInclusive value="0" />
+ </xs:restriction>
+ </xs:simpleType>
</xs:element>
- <xs:element name="maxDataDumpSizeInBytes" type="xs:int" default="256" minOccurs="0">
+ <xs:element name="maxDataDumpSizeInBytes" default="256" minOccurs="0">
<xs:annotation>
<xs:documentation>
- The maximum size of data to retrive when When getting data to display
+ The maximum size of data to retrive when when getting data to display
for debugging.
</xs:documentation>
</xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:int">
+ <xs:minInclusive value="1" />
+ </xs:restriction>
+ </xs:simpleType>
</xs:element>
<xs:element name="maxFieldContentLengthInBytes" type="xs:int" default="1048576" minOccurs="0">
<xs:annotation>
@@ -223,7 +260,7 @@
</xs:documentation>
</xs:annotation>
</xs:element>
- <xs:element name="maxLengthForVariableLengthDelimiterDisplay" type="xs:int" default="10" minOccurs="0">
+ <xs:element name="maxLengthForVariableLengthDelimiterDisplay" default="10" minOccurs="0">
<xs:annotation>
<xs:documentation>
When unexpected text is found where a delimiter is expected, this is the maximum
@@ -231,8 +268,13 @@
length delimiter.
</xs:documentation>
</xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:int">
+ <xs:minInclusive value="1" />
+ </xs:restriction>
+ </xs:simpleType>
</xs:element>
- <xs:element name="maxLookaheadFunctionBits" type="xs:long" default="512" minOccurs="0">
+ <xs:element name="maxLookaheadFunctionBits" default="512" minOccurs="0">
<xs:annotation>
<xs:documentation>
Max distance that the DPath lookahead function is permitted to look.
@@ -240,23 +282,37 @@
so it is offset+bitsize.
</xs:documentation>
</xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:long">
+ <xs:minInclusive value="1" />
+ </xs:restriction>
+ </xs:simpleType>
</xs:element>
- <xs:element name="maxOccursBounds" type="xs:int" default="2147483647" minOccurs="0">
+ <xs:element name="maxOccursBounds" default="2147483647" minOccurs="0">
<xs:annotation>
<xs:documentation>
Maximum number of occurances of an array element.
</xs:documentation>
</xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:long">
+ <xs:minInclusive value="1" />
+ </xs:restriction>
+ </xs:simpleType>
</xs:element>
- <xs:element name="maxSkipLengthInBytes" type="xs:int" default="1024" minOccurs="0">
+ <xs:element name="maxSkipLengthInBytes" default="1024" minOccurs="0">
<xs:annotation>
<xs:documentation>
Maximum number of bytes allowed to skip in a skip region.
</xs:documentation>
</xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:int">
+ <xs:minInclusive value="1" />
+ </xs:restriction>
+ </xs:simpleType>
</xs:element>
-
- <xs:element name="maxValidYear" type="xs:int" default="9999" minOccurs="0">
+ <xs:element name="maxValidYear" default="9999" minOccurs="0">
<xs:annotation>
<xs:documentation>
Due to differences in the DFDL spec and ICU4J SimpleDateFormat, we must
@@ -265,28 +321,48 @@
tunable tunable sets an upper limit for values to prevent overflow.
</xs:documentation>
</xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:int">
+ <xs:minInclusive value="1" />
+ </xs:restriction>
+ </xs:simpleType>
</xs:element>
- <xs:element name="maximumRegexMatchLengthInCharacters" type="xs:int" default="1048576" minOccurs="0">
+ <xs:element name="maximumRegexMatchLengthInCharacters" default="1048576" minOccurs="0">
<xs:annotation>
<xs:documentation>
Maximum number of characters to match when performing regular expression
matches on input data.
</xs:documentation>
</xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:int">
+ <xs:minInclusive value="1" />
+ </xs:restriction>
+ </xs:simpleType>
</xs:element>
- <xs:element name="maximumSimpleElementSizeInCharacters" type="xs:int" default="1048576" minOccurs="0">
+ <xs:element name="maximumSimpleElementSizeInCharacters" default="1048576" minOccurs="0">
<xs:annotation>
<xs:documentation>
Maximum number of characters to parse when parsing string data.
</xs:documentation>
</xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:int">
+ <xs:minInclusive value="1" />
+ </xs:restriction>
+ </xs:simpleType>
</xs:element>
- <xs:element name="minBinaryDecimalVirtualPoint" type="xs:int" default="-200" minOccurs="0">
+ <xs:element name="minBinaryDecimalVirtualPoint" default="-200" minOccurs="0">
<xs:annotation>
<xs:documentation>
The smallest allowed value of the dfdl:binaryDecimalVirtualPoint property.
</xs:documentation>
</xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:int">
+ <xs:maxInclusive value="-1" />
+ </xs:restriction>
+ </xs:simpleType>
</xs:element>
<xs:element name="minValidYear" type="xs:int" default="0" minOccurs="0">
<xs:annotation>
@@ -298,6 +374,19 @@
</xs:documentation>
</xs:annotation>
</xs:element>
+ <xs:element name="outputStreamChunkSizeInBytes" default="65536" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>
+ When writing file data to the output stream during unparse, this
+ is the maximum number of bytes to write at a time.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:int">
+ <xs:minInclusive value="1" />
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
<xs:element name="parseUnparsePolicy" type="daf:TunableParseUnparsePolicyTunable" default="fromRoot" minOccurs="0">
<xs:annotation>
<xs:documentation>
@@ -390,7 +479,7 @@
</xs:documentation>
</xs:annotation>
</xs:element>
- <xs:element name="saxUnparseEventBatchSize" type="xs:int" default="100" minOccurs="0">
+ <xs:element name="saxUnparseEventBatchSize" default="100" minOccurs="0">
<xs:annotation>
<xs:documentation>
Daffodil's SAX Unparse API allows events to be batched in memory to minimize the
@@ -401,6 +490,11 @@
frequency of context switching, but increase the memory footprint.
</xs:documentation>
</xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:int">
+ <xs:minInclusive value="1" />
+ </xs:restriction>
+ </xs:simpleType>
</xs:element>
<xs:element name="suppressSchemaDefinitionWarnings" type="daf:TunableSuppressSchemaDefinitionWarnings" default="emptyElementParsePolicyError" minOccurs="0">
<xs:annotation>
@@ -410,6 +504,15 @@
</xs:documentation>
</xs:annotation>
</xs:element>
+ <xs:element name="tempFilePath" type="xs:string" default="This string is ignored. Default value is taken from java.io.tmpdir property" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>
+ When unparsing, use this path to store temporary files that may be genrated.
+ The default value (empty string) will result in the use of the java.io.tmpdir
+ property being used as the path.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
<xs:element name="unqualifiedPathStepPolicy" type="daf:TunableUnqualifiedPathStepPolicy" default="noNamespace" minOccurs="0">
<xs:annotation>
<xs:documentation>
@@ -422,7 +525,7 @@
</xs:documentation>
</xs:annotation>
</xs:element>
- <xs:element name="unparseSuspensionWaitOld" type="xs:int" default="100" minOccurs="0">
+ <xs:element name="unparseSuspensionWaitOld" default="100" minOccurs="0">
<xs:annotation>
<xs:documentation>
While unparsing, some unparse actions require "suspending" which
@@ -440,13 +543,23 @@
young and old suspensions, respectively.
</xs:documentation>
</xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:int">
+ <xs:minInclusive value="1" />
+ </xs:restriction>
+ </xs:simpleType>
</xs:element>
- <xs:element name="unparseSuspensionWaitYoung" type="xs:int" default="5" minOccurs="0">
+ <xs:element name="unparseSuspensionWaitYoung" default="5" minOccurs="0">
<xs:annotation>
<xs:documentation>
See unparseSuspensionWaitOld
</xs:documentation>
</xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:int">
+ <xs:minInclusive value="1" />
+ </xs:restriction>
+ </xs:simpleType>
</xs:element>
</xs:all>
</xs:complexType>
diff --git a/daffodil-propgen/src/main/scala/org/apache/daffodil/propGen/TunableGenerator.scala b/daffodil-propgen/src/main/scala/org/apache/daffodil/propGen/TunableGenerator.scala
index 821c543..b235a1e 100644
--- a/daffodil-propgen/src/main/scala/org/apache/daffodil/propGen/TunableGenerator.scala
+++ b/daffodil-propgen/src/main/scala/org/apache/daffodil/propGen/TunableGenerator.scala
@@ -117,6 +117,10 @@ class TunableGenerator(schemaRootConfig: scala.xml.Node, schemaRootExt: scala.xm
| !suppressSchemaDefinitionWarnings.contains(warnID) &&
| !suppressSchemaDefinitionWarnings.contains(WarnID.All)
|
+ | private def throwInvalidTunableValue(tunable: String, value: String) = {
+ | throw new IllegalArgumentException("Invalid value for tunable " + tunable + ": " + value)
+ | }
+ |
|}
""".trim.stripMargin
@@ -134,9 +138,15 @@ class TunableGenerator(schemaRootConfig: scala.xml.Node, schemaRootExt: scala.xm
val tunables =
tunableNodes.map { tunableNode =>
val schemaName = tunableNode \@ "name"
- val schemaType = tunableNode \@ "type"
+ val schemaType =
+ if (tunableNode \@ "type" != "") tunableNode \@ "type"
+ else tunableNode \\ "restriction" \@ "base"
val schemaDefault = tunableNode \@ "default"
+ if (schemaName == "") throw new Exception("Tunable missing mandatory name attribute: " + tunableNode)
+ if (schemaType == "") throw new Exception("Tunable missing mandatory type or restriction base attribute: " + schemaName)
+ if (schemaDefault == "") throw new Exception("Tunable missing mandatory default attribute: " + schemaName)
+
val tunable =
if (schemaName == "suppressSchemaDefinitionWarnings") {
// special case, list of enums
@@ -146,21 +156,37 @@ class TunableGenerator(schemaRootConfig: scala.xml.Node, schemaRootExt: scala.xm
new EnumTunable(schemaName, schemaType, schemaDefault)
} else if (schemaName == "tempFilePath") {
// special case, creates actual file object instead of string
- new TempFilePathTunable()
+ new FileTunable("tempFilePath", """System.getProperty("java.io.tmpdir")""")
} else {
// primitive type
- new PrimitiveTunable(schemaName, schemaType, schemaDefault)
+ new PrimitiveTunable(schemaName, schemaType, schemaDefault, tunableNode)
}
tunable
- }
+ }.sortBy(_.name)
+
+ val definitionString =
+ tunables
+ .map(_.scalaDefinition)
+ .mkString(" ", ",\n ", ")")
+
+ val conversionString =
+ tunables
+ .map { tunable =>
+ tunable
+ .scalaConversion
+ .split("\n")
+ .filter(_.trim.length > 0)
+ .mkString(" ", "\n ", "")
+ }
+ .mkString("\n")
w.write(top)
w.write("\n")
- w.write(tunables.map(_.scalaDefinition).mkString(" ", ",\n ", ")"))
+ w.write(definitionString)
w.write("\n")
w.write(middle)
w.write("\n")
- w.write(tunables.map(_.scalaConversion.split("\n").mkString(" ", "\n ", "")).mkString("\n"))
+ w.write(conversionString)
w.write("\n")
w.write(bottom)
w.write("\n")
@@ -180,9 +206,14 @@ class TunableGenerator(schemaRootConfig: scala.xml.Node, schemaRootExt: scala.xm
abstract class TunableBase {
def scalaDefinition: String
def scalaConversion: String
+ def name: String
}
-class PrimitiveTunable(name: String, schemaType: String, schemaDefault: String)
+class PrimitiveTunable(
+ override val name: String,
+ schemaType: String,
+ schemaDefault: String,
+ node: scala.xml.Node)
extends TunableBase {
private val scalaType = schemaType match {
@@ -190,6 +221,7 @@ class PrimitiveTunable(name: String, schemaType: String, schemaDefault: String)
case "xs:int" => "Int"
case "xs:long" => "Long"
case "xs:string" => "String"
+ case _ => throw new Exception("Type not supported for tunable: " + schemaType)
}
private val scalaDefault = schemaType match {
@@ -197,16 +229,53 @@ class PrimitiveTunable(name: String, schemaType: String, schemaDefault: String)
case _ => schemaDefault
}
+ private def restrictionCheck(rCheck: String, rValue: String): Option[String] = {
+ if (rValue != "") {
+ Some(s""" if (!(v ${rCheck} ${rValue})) throwInvalidTunableValue(tunable, value)""")
+ } else {
+ None
+ }
+ }
+
+ private val minInclusive = node \\ "minInclusive" \@ "value"
+ private val maxInclusive = node \\ "maxInclusive" \@ "value"
+ private val minExclusive = node \\ "minExclusive" \@ "value"
+ private val maxExclusive = node \\ "maxExclusive" \@ "value"
+
+ private val restrictionChecks = Seq(
+ restrictionCheck(">=", minInclusive),
+ restrictionCheck("<=", maxInclusive),
+ restrictionCheck(">", minExclusive),
+ restrictionCheck("<", maxExclusive),
+ ).flatten.mkString("\n")
+
override val scalaDefinition = s"""val ${name}: ${scalaType} = ${scalaDefault}"""
- override val scalaConversion = s"""case "${name}" => this.copy(${name} = value.to${scalaType})"""
+ override val scalaConversion = s"""
+ |case "${name}" => {
+ | val v = scala.util.Try(value.to${scalaType}).getOrElse { throwInvalidTunableValue(tunable, value) }
+ |${restrictionChecks}
+ | this.copy(${name} = v)
+ |}
+ """.trim.stripMargin
}
-class TempFilePathTunable() extends TunableBase {
- override val scalaDefinition = s"""val tempFilePath: java.io.File = new java.io.File(System.getProperty(\"java.io.tmpdir\"))"""
- override val scalaConversion = s"""case "tempFilePath" => this.copy(tempFilePath = new java.io.File(value))"""
+class FileTunable(
+ override val name: String,
+ default: String)
+ extends TunableBase {
+
+ override val scalaDefinition = s"""val ${name}: java.io.File = new java.io.File(${default})"""
+ override val scalaConversion = s"""
+ |case "${name}" => {
+ | this.copy(${name} = new java.io.File(value))
+ |}
+ """.trim.stripMargin
}
-class EnumTunable(name: String, schemaType: String, schemaDefault: String)
+class EnumTunable(
+ override val name: String,
+ schemaType: String,
+ schemaDefault: String)
extends TunableBase {
private val scalaType = schemaType.stripPrefix("daf:Tunable")
@@ -216,13 +285,17 @@ class EnumTunable(name: String, schemaType: String, schemaDefault: String)
override val scalaConversion = s"""
|case "${name}" => {
| val vOpt = ${scalaType}.optionStringToEnum("${scalaType}", value)
- | val v = vOpt.getOrElse(throw new IllegalArgumentException("For input string: \\"" + value + "\\""))
+ | val v = vOpt.getOrElse { throwInvalidTunableValue(tunable, value) }
| this.copy(${name} = v)
|}
""".trim.stripMargin
}
-class EnumListTunable(name: String, schemaType: String, schemaDefault: String, listType: String)
+class EnumListTunable(
+ override val name: String,
+ schemaType: String,
+ schemaDefault: String,
+ listType: String)
extends TunableBase {
val scalaDefault = {
@@ -241,7 +314,7 @@ class EnumListTunable(name: String, schemaType: String, schemaDefault: String, l
|case "${name}" => {
| val values = value.split("\\\\s+").toSeq.map { v =>
| val vOpt = ${listType}.optionStringToEnum("${listType}", v)
- | vOpt.getOrElse(throw new IllegalArgumentException("For input string: \\"" + v + "\\""))
+ | vOpt.getOrElse { throwInvalidTunableValue(tunable, value) }
| }
| this.copy(${name} = values)
|}