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 + + + +