From 66366ce3700ff91ad515238b94757492fef8baef Mon Sep 17 00:00:00 2001
From: olabusayoT <50379531+olabusayoT@users.noreply.github.com>
Date: Thu, 26 Sep 2024 16:56:49 -0400
Subject: [PATCH] Add support for escalating SDWs to Errors
- add tunable 'escalateWarningsToErrors' to control escalation
- add new SchemaDefinitionErrorFromWarning class that extends SDW so any changes to SDW in the future will be automatically inherited
- make RSDW and RSDE extend SDW and SDEs respectively
- add test to demonstrate tunable
- add test to demonstrate tunable ignored when warning is suppressed
- add test to demonstrate runtime SDW can be escalated as well
DAFFODIL-2810
---
.../org/apache/daffodil/xsd/dafext.xsd | 7 +++
.../daffodil/runtime1/dpath/DPath.scala | 1 -
.../apache/daffodil/runtime1/dsom/SDE.scala | 63 +++++++++----------
.../runtime1/processors/DataProcessor.scala | 8 +--
.../processors/ProcessorStateBases.scala | 14 +++--
.../processors/SuspensionTracker.scala | 11 +++-
.../processors/parsers/ParseErrors.scala | 7 +--
.../runtime1/processors/parsers/Parser.scala | 1 -
.../processors/unparsers/Unparser.scala | 1 -
.../SchemaDefinitionErrors.tdml | 63 +++++++++++++++++++
.../section07/variables/variables.tdml | 21 +++++++
.../schema_definition_errors/TestSDE.scala | 8 +++
.../section07/variables/TestVariables.scala | 3 +
13 files changed, 157 insertions(+), 51 deletions(-)
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 3d89c56617..fffa275bb6 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
@@ -185,6 +185,13 @@
+
+
+
+ This tunable allows the escalation of Schema Definition Warnings to Errors.
+
+
+
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/DPath.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/DPath.scala
index 3e6ffca545..3e5a8f6e63 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/DPath.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/DPath.scala
@@ -394,7 +394,6 @@ final class RuntimeExpressionDPath[T <: AnyRef](
if (value.asInstanceOf[String].length == 0) {
val e = new RuntimeSchemaDefinitionError(
ci.schemaFileLocation,
- state,
"Non-empty string required."
)
doSDE(e, state)
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dsom/SDE.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dsom/SDE.scala
index 0108e5f8af..16ca935563 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dsom/SDE.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dsom/SDE.scala
@@ -24,7 +24,6 @@ import org.apache.daffodil.lib.exceptions.SchemaFileLocation
import org.apache.daffodil.lib.exceptions._
import org.apache.daffodil.lib.util.Maybe
import org.apache.daffodil.lib.util.Maybe._
-import org.apache.daffodil.runtime1.processors.CompileState
import org.apache.daffodil.runtime1.processors.ParseOrUnparseState
class SchemaDefinitionError(
@@ -49,6 +48,20 @@ class SchemaDefinitionError(
}
+class SchemaDefinitionErrorFromWarning(sdw: SchemaDefinitionWarning)
+ extends SchemaDefinitionWarning(
+ sdw.warnID,
+ sdw.schemaContext,
+ sdw.annotationContext,
+ sdw.kind,
+ sdw.args: _*
+ ) {
+
+ override def isError = true
+ override def modeName = super.modeName + " Warning Escalated"
+
+}
+
/**
* Specific class used for this specific error, because we need to pick this off
* in the debugger for special handling.
@@ -58,60 +71,41 @@ class RelativePathPastRootError(schemaContext: SchemaFileLocation, kind: String,
class RuntimeSchemaDefinitionError(
schemaContext: SchemaFileLocation,
- runtimeContext: ParseOrUnparseState,
- causedBy: Throwable,
fmtString: String,
args: Any*
-) extends SchemaDefinitionDiagnosticBase(
- Maybe(schemaContext),
- (runtimeContext match { // TODO: this is ugly.
- case cs: CompileState => Nope
- case _ => Maybe(runtimeContext)
- }),
+) extends SchemaDefinitionError(
+ Option(schemaContext),
None,
- Maybe(causedBy),
- Maybe(fmtString),
+ fmtString,
args: _*
) {
- override def isError = true
override def modeName = "Runtime Schema Definition"
-
- def this(
- schemaContext: SchemaFileLocation,
- runtimeContext: ParseOrUnparseState,
- fmtString: String,
- args: Any*
- ) =
- this(schemaContext, runtimeContext, null, fmtString, args: _*)
}
class RuntimeSchemaDefinitionWarning(
warnID: WarnID,
schemaContext: SchemaFileLocation,
- runtimeContext: ParseOrUnparseState,
kind: String,
args: Any*
-) extends SchemaDefinitionDiagnosticBase(
+) extends SchemaDefinitionWarning(
+ warnID,
Some(schemaContext),
- Some(runtimeContext),
None,
- Nope,
- Maybe(kind + s" (id: ${warnID})"),
+ kind,
args: _*
) {
- override def isError = false
override def modeName = "Runtime Schema Definition"
}
class SchemaDefinitionWarning(
- warnID: WarnID,
- schemaContext: Option[SchemaFileLocation],
- annotationContext: Option[SchemaFileLocation],
- kind: String,
- args: Any*
+ val warnID: WarnID,
+ val schemaContext: Option[SchemaFileLocation],
+ val annotationContext: Option[SchemaFileLocation],
+ val kind: String,
+ val args: Any*
) extends SchemaDefinitionDiagnosticBase(
schemaContext,
None,
@@ -269,7 +263,12 @@ trait ImplementsThrowsOrSavesSDE extends ImplementsThrowsSDE with SavesErrorsAnd
fmt,
args: _*
)
- warn(sdw)
+ if (tunable.escalateWarningsToErrors) {
+ val sde = new SchemaDefinitionErrorFromWarning(sdw)
+ toss(sde)
+ } else {
+ warn(sdw)
+ }
}
}
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/DataProcessor.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/DataProcessor.scala
index 2d325b5641..752f59cc95 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/DataProcessor.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/DataProcessor.scala
@@ -513,9 +513,9 @@ class DataProcessor(
state.dataInputStream.inputSource.setInvalid
state.setFailed(sde)
}
- case rsde: RuntimeSchemaDefinitionError => {
+ case sdefw: SchemaDefinitionErrorFromWarning => {
state.dataInputStream.inputSource.setInvalid
- state.setFailed(rsde)
+ state.setFailed(sdefw)
}
case e: ErrorAlreadyHandled => {
state.setFailed(e.th)
@@ -574,8 +574,8 @@ class DataProcessor(
unparserState.setFailed(sde)
unparserState.unparseResult
}
- case rsde: RuntimeSchemaDefinitionError => {
- unparserState.setFailed(rsde)
+ case sdefw: SchemaDefinitionErrorFromWarning => {
+ unparserState.setFailed(sdefw)
unparserState.unparseResult
}
case e: ErrorAlreadyHandled => {
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/ProcessorStateBases.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/ProcessorStateBases.scala
index 8789b11e2f..62550b54ae 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/ProcessorStateBases.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/ProcessorStateBases.scala
@@ -53,6 +53,7 @@ import org.apache.daffodil.runtime1.dpath.DState
import org.apache.daffodil.runtime1.dsom.DPathCompileInfo
import org.apache.daffodil.runtime1.dsom.RuntimeSchemaDefinitionError
import org.apache.daffodil.runtime1.dsom.RuntimeSchemaDefinitionWarning
+import org.apache.daffodil.runtime1.dsom.SchemaDefinitionErrorFromWarning
import org.apache.daffodil.runtime1.dsom.ValidationError
import org.apache.daffodil.runtime1.infoset.DataValue.DataValuePrimitive
import org.apache.daffodil.runtime1.infoset._
@@ -555,13 +556,13 @@ abstract class ParseOrUnparseState protected (
final def SDE(str: String, args: Any*) = {
val ctxt = getContext()
- val rsde = new RuntimeSchemaDefinitionError(ctxt.schemaFileLocation, this, str, args: _*)
+ val rsde = new RuntimeSchemaDefinitionError(ctxt.schemaFileLocation, str, args: _*)
ctxt.toss(rsde)
}
final def SDEButContinue(str: String, args: Any*) = {
val ctxt = getContext()
- val rsde = new RuntimeSchemaDefinitionError(ctxt.schemaFileLocation, this, str, args: _*)
+ val rsde = new RuntimeSchemaDefinitionError(ctxt.schemaFileLocation, str, args: _*)
diagnostics = rsde :: diagnostics
}
@@ -573,8 +574,13 @@ abstract class ParseOrUnparseState protected (
tssdw.contains(warnID) || tssdw.contains(WarnID.All)
if (!suppress) {
val rsdw =
- new RuntimeSchemaDefinitionWarning(warnID, ctxt.schemaFileLocation, this, str, args: _*)
- diagnostics = rsdw :: diagnostics
+ new RuntimeSchemaDefinitionWarning(warnID, ctxt.schemaFileLocation, str, args: _*)
+ if (tunable.escalateWarningsToErrors) {
+ val sde = new SchemaDefinitionErrorFromWarning(rsdw)
+ ctxt.toss(sde)
+ } else {
+ diagnostics = rsdw :: diagnostics
+ }
}
}
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/SuspensionTracker.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/SuspensionTracker.scala
index 64d579f587..58c25c781c 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/SuspensionTracker.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/SuspensionTracker.scala
@@ -120,7 +120,14 @@ class SuspensionTracker(suspensionWaitYoung: Int, suspensionWaitOld: Int) {
class SuspensionDeadlockException(suspExprs: Seq[Suspension])
extends RuntimeSchemaDefinitionError(
suspExprs(0).rd.schemaFileLocation,
- suspExprs(0).savedUstate,
"Expressions/Unparsers are circularly deadlocked (mutually defined):\n%s",
- suspExprs.groupBy { _.rd }.mapValues { _(0) }.values.mkString(" - ", "\n - ", "")
+ suspExprs
+ .groupBy {
+ _.rd
+ }
+ .mapValues {
+ _(0)
+ }
+ .values
+ .mkString(" - ", "\n - ", "")
)
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/ParseErrors.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/ParseErrors.scala
index b82077f096..83b257615d 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/ParseErrors.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/ParseErrors.scala
@@ -140,12 +140,7 @@ trait DoSDEMixin {
throw sde
}
case other => {
- val sde = new RuntimeSchemaDefinitionError(
- state.getContext().schemaFileLocation,
- state,
- e,
- null
- )
+ val sde = new RuntimeSchemaDefinitionError(state.getContext().schemaFileLocation, e.getMessage)
state.setFailed(sde)
state.toss(sde)
}
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/Parser.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/Parser.scala
index 033f6214af..50ddd5026a 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/Parser.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/Parser.scala
@@ -342,7 +342,6 @@ case class NotParsableParser(context: ElementRuntimeData) extends PrimParserNoDa
// create an SDE and toss it
val rsde = new RuntimeSchemaDefinitionError(
context.schemaFileLocation,
- state,
"This schema was compiled without parse support. Check the parseUnparsePolicy tunable or dfdlx:parseUnparsePolicy property."
)
context.toss(rsde)
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/unparsers/Unparser.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/unparsers/Unparser.scala
index d7ce1581fe..a982ba91dd 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/unparsers/Unparser.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/unparsers/Unparser.scala
@@ -201,7 +201,6 @@ case class NotUnparsableUnparser(override val context: ElementRuntimeData)
// create an SDE and toss it
val rsde = new RuntimeSchemaDefinitionError(
context.schemaFileLocation,
- state,
"This schema was compiled without unparse support. Check the parseUnparsePolicy tunable or dfdlx:parseUnparsePolicy property."
)
context.toss(rsde)
diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section02/schema_definition_errors/SchemaDefinitionErrors.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/section02/schema_definition_errors/SchemaDefinitionErrors.tdml
index f8c0fedb1e..d9f2214b5f 100644
--- a/daffodil-test/src/test/resources/org/apache/daffodil/section02/schema_definition_errors/SchemaDefinitionErrors.tdml
+++ b/daffodil-test/src/test/resources/org/apache/daffodil/section02/schema_definition_errors/SchemaDefinitionErrors.tdml
@@ -308,4 +308,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+ Schema Definition Warning Escalated Error
+ appinfoDFDLSourceWrong
+ xs:appinfo source attribute
+
+
+
+
+
+
+
+
+
+ test
+
+
+
+
diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section07/variables/variables.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/section07/variables/variables.tdml
index 60506dbfa2..b97374ad18 100644
--- a/daffodil-test/src/test/resources/org/apache/daffodil/section07/variables/variables.tdml
+++ b/daffodil-test/src/test/resources/org/apache/daffodil/section07/variables/variables.tdml
@@ -23,6 +23,7 @@
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ct="http://w3.ibm.com/xmlns/dfdl/ctInfoset"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:ex="http://example.com"
+ xmlns:daf="urn:ogf:dfdl:2013:imp:daffodil.apache.org:2018:ext"
defaultRoundTrip="true">
@@ -2221,6 +2222,26 @@
+
+
+ true
+
+
+
+
+
+
+ Schema Definition Warning Escalated Error
+ variableSet
+ Cannot set variable
+ after reading the default value
+ State was: VariableRead
+
+
+
+