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 2019/06/04 11:38:38 UTC

[incubator-daffodil] branch master updated: Generate DaffodilTunables and WarnID from dafext.xsd

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 db7b1ea  Generate DaffodilTunables and WarnID from dafext.xsd
db7b1ea is described below

commit db7b1eac516c3de16fe58d87804ec799fac382a5
Author: Steve Lawrence <sl...@apache.org>
AuthorDate: Wed May 15 08:09:29 2019 -0400

    Generate DaffodilTunables and WarnID from dafext.xsd
    
    - Add Tuanble and WarnID generators to generate code based on
      dafext.xsd. This makes adding new warnings or tunables much easier,
      and the schema acts as documentation.
    - Modifies the parseUnparsePolicy tunable to add a "fromRoot" value,
      which is the new default. The old default of empty string is no longer
      supported.
    - Generates ParseUnparsePolicy and UnqualifyPathStepPolicy tunable
      enums, which are also now props.Enums to gets improved enum
      functionality and allows for consistent logic in the generator
    - Cleaned up the dafext.xsd schema, added tunable documentation and
      default values
    
    DAFFODIL-2117
---
 .../org/apache/daffodil/compiler/Compiler.scala    |  46 +-
 .../org/apache/daffodil/general/TestTunables.scala |   4 +-
 .../org/apache/daffodil/api/DaffodilTunables.scala | 310 ------------
 .../daffodil/api/UnqualifiedPathStepPolicy.scala   |  44 --
 .../scala/org/apache/daffodil/api/WarnID.scala     |  98 ----
 .../resources/org/apache/daffodil/xsd/dafext.xsd   | 548 +++++++++++++++------
 .../daffodil/propGen/PropertyGenerator.scala       |  34 +-
 .../apache/daffodil/propGen/TunableGenerator.scala | 292 +++++++++++
 .../apache/daffodil/propGen/WarnIDGenerator.scala  |  85 ++++
 9 files changed, 849 insertions(+), 612 deletions(-)

diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/compiler/Compiler.scala b/daffodil-core/src/main/scala/org/apache/daffodil/compiler/Compiler.scala
index 18f236f..521e7a7 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/compiler/Compiler.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/compiler/Compiler.scala
@@ -17,24 +17,44 @@
 
 package org.apache.daffodil.compiler
 
-import java.io.{ File, FileInputStream, ObjectInputStream, StreamCorruptedException }
+import java.io.File
+import java.io.FileInputStream
+import java.io.ObjectInputStream
+import java.io.StreamCorruptedException
 import java.nio.channels.Channels
-import java.util.zip.{ GZIPInputStream, ZipException }
+import java.util.zip.GZIPInputStream
+import java.util.zip.ZipException
 
 import scala.collection.mutable.Queue
 import scala.xml.Node
 
 import org.apache.daffodil.ExecutionMode
-import org.apache.daffodil.api.{ DFDL, DaffodilSchemaSource, DaffodilTunables, URISchemaSource, UnitTestSchemaSource, ValidationMode }
-import org.apache.daffodil.dsom.{ ElementBase, SchemaComponent, SchemaComponentImpl, SchemaSet }
+import org.apache.daffodil.api.DFDL
+import org.apache.daffodil.api.DaffodilSchemaSource
+import org.apache.daffodil.api.DaffodilTunables
+import org.apache.daffodil.api.URISchemaSource
+import org.apache.daffodil.api.UnitTestSchemaSource
+import org.apache.daffodil.api.ValidationMode
+import org.apache.daffodil.api.ParseUnparsePolicyTunable
+import org.apache.daffodil.dsom.ElementBase
+import org.apache.daffodil.dsom.SchemaComponent
+import org.apache.daffodil.dsom.SchemaComponentImpl
+import org.apache.daffodil.dsom.SchemaSet
 import org.apache.daffodil.exceptions.Assert
-import org.apache.daffodil.externalvars.{ Binding, ExternalVariablesLoader }
+import org.apache.daffodil.externalvars.Binding
+import org.apache.daffodil.externalvars.ExternalVariablesLoader
 import org.apache.daffodil.oolag.OOLAG
-import org.apache.daffodil.processors.{ DataProcessor, Processor, SchemaSetRuntimeData, SerializableDataProcessor, VariableMap }
+import org.apache.daffodil.processors.DataProcessor
+import org.apache.daffodil.processors.Processor
+import org.apache.daffodil.processors.SchemaSetRuntimeData
+import org.apache.daffodil.processors.SerializableDataProcessor
+import org.apache.daffodil.processors.VariableMap
 import org.apache.daffodil.processors.parsers.NotParsableParser
 import org.apache.daffodil.processors.unparsers.NotUnparsableUnparser
 import org.apache.daffodil.schema.annotation.props.gen.ParseUnparsePolicy
-import org.apache.daffodil.util.{ LogLevel, Logging, Misc }
+import org.apache.daffodil.util.LogLevel
+import org.apache.daffodil.util.Logging
+import org.apache.daffodil.util.Misc
 import org.apache.daffodil.xml._
 
 /**
@@ -61,12 +81,12 @@ final class ProcessorFactory(val sset: SchemaSet)
   final override def enclosingComponentDef: Option[SchemaComponent] = None
 
   lazy val (generateParser, generateUnparser) = {
-    val (context, policy) =
-      if (tunable.parseUnparsePolicy.isDefined) {
-        (None, tunable.parseUnparsePolicy.get)
-      } else {
-        (Some(rootElem), rootElem.rootParseUnparsePolicy)
-      }
+    val (context, policy) = tunable.parseUnparsePolicy match {
+      case ParseUnparsePolicyTunable.FromRoot => (Some(rootElem), rootElem.rootParseUnparsePolicy)
+      case ParseUnparsePolicyTunable.ParseOnly => (None, ParseUnparsePolicy.ParseOnly)
+      case ParseUnparsePolicyTunable.UnparseOnly => (None, ParseUnparsePolicy.UnparseOnly)
+      case ParseUnparsePolicyTunable.Both => (None, ParseUnparsePolicy.Both)
+    }
     rootElem.checkParseUnparsePolicyCompatibility(context, policy)
     policy match {
       case ParseUnparsePolicy.Both => (true, true)
diff --git a/daffodil-core/src/test/scala/org/apache/daffodil/general/TestTunables.scala b/daffodil-core/src/test/scala/org/apache/daffodil/general/TestTunables.scala
index c434c15..e300987 100644
--- a/daffodil-core/src/test/scala/org/apache/daffodil/general/TestTunables.scala
+++ b/daffodil-core/src/test/scala/org/apache/daffodil/general/TestTunables.scala
@@ -85,8 +85,8 @@ class TestTunables extends Logging {
   }
 
   @Test def testTunableSuppressionListCopying() {
-    val t1 = DaffodilTunables("suppressschemadefinitionwarnings", "escapeSchemeRefUndefined")
-    val t2 = DaffodilTunables("suppressschemadefinitionwarnings", "all")
+    val t1 = DaffodilTunables("suppressSchemaDefinitionWarnings", "escapeSchemeRefUndefined")
+    val t2 = DaffodilTunables("suppressSchemaDefinitionWarnings", "all")
 
     val w1 = t1.suppressSchemaDefinitionWarnings.mkString(",")
     val w2 = t2.suppressSchemaDefinitionWarnings.mkString(",")
diff --git a/daffodil-lib/src/main/scala/org/apache/daffodil/api/DaffodilTunables.scala b/daffodil-lib/src/main/scala/org/apache/daffodil/api/DaffodilTunables.scala
index b08a6ff..6a9c064 100644
--- a/daffodil-lib/src/main/scala/org/apache/daffodil/api/DaffodilTunables.scala
+++ b/daffodil-lib/src/main/scala/org/apache/daffodil/api/DaffodilTunables.scala
@@ -15,313 +15,3 @@
  * limitations under the License.
  */
 
-package org.apache.daffodil.api
-
-import org.apache.daffodil.exceptions.Assert
-import org.apache.daffodil.schema.annotation.props.gen.ParseUnparsePolicy
-import org.apache.daffodil.util.LogLevel
-import org.apache.daffodil.util.Logging
-import org.apache.daffodil.util.Misc
-import org.apache.daffodil.xml.DaffodilXMLLoader
-import org.apache.daffodil.schema.annotation.props.EmptyElementParsePolicy
-
-object DaffodilTunables {
-
-  def apply(tunables: Map[String, String]): DaffodilTunables = {
-    apply().setTunables(tunables)
-  }
-
-  def apply(tunable: String, value: String): DaffodilTunables = {
-    apply().setTunable(tunable, value)
-  }
-
-  def apply(): DaffodilTunables = {
-    // override tunables from the global configuration file on the class path, if it exists
-    val (configOpt, _) = Misc.getResourceOption("/daffodil-config.xml")
-    val configTunables: Map[String, String] =
-      if (configOpt.isDefined) {
-        val loader = new DaffodilXMLLoader()
-        val node = loader.load(URISchemaSource(configOpt.get))
-        val trimmed = scala.xml.Utility.trim(node)
-        val tunablesNode = (trimmed \ "tunables").headOption
-        val tunablesMap: Map[String, String] = tunablesNode match {
-          case None => Map.empty
-          case Some(tunableNode) => {
-            tunableNode.child.map { n => (n.label, n.text) }.toMap
-          }
-        }
-        tunablesMap
-      } else {
-        Map.empty
-      }
-
-    new DaffodilTunables().setTunables(configTunables)
-  }
-}
-
-case class DaffodilTunables(
-  val maxSkipLengthInBytes: Long = 1024, // applicable to leadingSkip and trailingSkip
-  val maxBinaryDecimalVirtualPoint: Int = 200, // Can be as large as Int.MaxValue
-  val minBinaryDecimalVirtualPoint: Int = -200, // Can be as small as Int.MinValue
-  val generatedNamespacePrefixStem: String = "tns",
-  val readerByteBufferSize: Long = 8192,
-  //
-  // If true, require that the bitOrder property is specified. If false, use a
-  // default value for bitOrder if not defined in a schema
-  //
-  // Looks to be compile-time as it gets 'tunable' from Term.
-  //
-  val requireBitOrderProperty: Boolean = false,
-  //
-  // If true, require that the choiceDispatchKeyKind property is specified. If false, use a
-  // default value for bitOrder if not defined in a schema
-  //
-  // Looks to be compile-time as it gets 'tunable' from Term.
-  //
-  val requireChoiceDispatchKeyKindProperty: Boolean = false,
-  //
-  // If true, require that the choiceBranchKeyKind property is specified. If false, use a
-  // default value for bitOrder if not defined in a schema
-  //
-  // Looks to be compile-time as it gets 'tunable' from Term.
-  //
-  val requireChoiceBranchKeyKindProperty: Boolean = false,
-  //
-  // If true, require that the encodingErrorPolicy property is specified. If
-  // false, use a default value not defined in a schema and warn about missing property
-  //
-  // Looks to be compile-time as it gets 'tunable' from Term.
-  //
-  val requireEncodingErrorPolicyProperty: Boolean = false,
-  //
-  // If true, require that the encodingErrorPolicy property is specified. If
-  // false, warn about missing property
-  //
-  // Looks to be compile-time as it gets 'tunable' from Term.
-  //
-  val requireTextBidiProperty: Boolean = false,
-  //
-  // If true, require that the encodingErrorPolicy property is specified. If
-  // false, warn about missing property
-  //
-  // Looks to be compile-time as it gets 'tunable' from Term.
-  //
-  val requireFloatingProperty: Boolean = false,
-  //
-  // If true, require that the emptyElementParsePolicy property is specified. If
-  // false, warn about missing property
-  //
-  val requireEmptyElementParsePolicyProperty: Boolean = false,
-  val defaultEmptyElementParsePolicy: EmptyElementParsePolicy = EmptyElementParsePolicy.TreatAsEmpty,
-  //
-  // Whether to compile a schema to support parsing, unparsing, both, or to use
-  // the daf:parseUnparsePolicy from the root node. None means to use the
-  // policy from the schema, otherwise use whatever the value is
-  //
-  // Looks to be compile-time. Set in Compiler.
-  ///
-  val parseUnparsePolicy: Option[ParseUnparsePolicy] = None,
-  val maxFieldContentLengthInBytes: Long = 1024 * 1024, // Can be as large as Int.MaxValue
-  val defaultInitRegexMatchLimitInChars: Long = 32,
-  val maxDataDumpSizeInBytes: Long = 256,
-  val maxOccursBounds: Long = Int.MaxValue, // Can be as large as Int.MaxValue
-  //
-  // When unexpected text is found where a delimiter is expected, this is the maximum
-  // number of bytes (characters) to display when the expected delimiter is a variable
-  // length delimiter.
-  //
-  val maxLengthForVariableLengthDelimiterDisplay: Int = 10, // will display this number of bytes
-  //
-  // In certain I/O optimized situations (text-only, encodingErrorPolicy='replace', fixed-width encoding)
-  // input files larger than this will be mmapped. Input files smaller than this
-  // will be simply read using ordinary I/O (because for small files that is just faster).
-  // This exists because mmap is more expensive than ordinary I/O for small files.
-  //
-  val inputFileMemoryMapLowThreshold: Long = 32 * 1024 * 1024, // 32Meg
-  //
-  // TODO: In the future, when we can stream and handle input larger than the JVM single
-  // object limits, input files larger than this will be streamed, i.e., using java.io.InputStream.
-  // They will not be memory mapped. A CharBuffer 2x larger may be created, and that
-  // cannot exceed the JVM maximum size, so this has to be no bigger (and perhaps quite a bit
-  // smaller) than 1/2 the maximum JVM object size.
-  //
-  // val inputFileMemoryMapHighThreshold: Long = 256 * 1024 * 1024, // 256 Meg
-
-  //
-  // Initial array buffer size allocated for recurring elements (aka arrays)
-  //
-  // Applies to InfosetImpl, as such is a run-time thing
-  //
-  val initialElementOccurrencesHint: Long = 10,
-  val unqualifiedPathStepPolicy: UnqualifiedPathStepPolicy.Type = UnqualifiedPathStepPolicy.NoNamespace,
-  val suppressSchemaDefinitionWarnings: List[WarnID] = Nil,
-
-  // By default, path expressions in Daffodil will only work correctly if path
-  // steps are used in an expression defined in the schema when compiled. To
-  // enable the use of other expressions (e.g. during debugging, where not all
-  // expressions are known at schema compile time), set this tunable to true.
-  // This may cause a degredation of performance in path expression evaluation,
-  // so this should be avoided when in production. This flag is automatically
-  // enabled when debugging is enabled.
-  val allowExternalPathExpressions: Boolean = false,
-
-  // Daffodil supports Java 7+. This is essentially all version of java that
-  // are in use, so we no longer have any unsupported java versions. This
-  // tunable no longer has any affect and is only kept for backwards
-  // compatability.
-  val errorOnUnsupportedJavaVersion: Boolean = true,
-
-  val maximumSimpleElementSizeInCharacters: Int = 1024 * 1024,
-  val initialRegexMatchLimitInCharacters: Int = 64,
-  val maximumRegexMatchLengthInCharacters: Int = 1024 * 1024,
-
-  /* Due to differences in the DFDL spec and ICU4J SimpleDateFormat, we must have SimpleDateFormat
-   * parse in lenient mode, which allows the year value to overflow with very large years
-   * into possibly negative years. These tunables simply make sure that value we get back
-   * from SimpleDateFormat are reasonable
-   */
-  val minValidYear: Int = 0,
-  val maxValidYear: Int = 9999,
-
-  /* Defines how Daffodil coerces expressions where the result type differs
-   * from the expected type. As an example, assume the expected type of an
-   * expression is an xs:string, but the expression is { 3 }. In this case, the
-   * expression result is an xs:int, which should not be automatically coerced
-   * to an xs:string. Instead, the expression should be { xs:string(3) } or { "3" }
-   * If the value of this tunable is false, these types of expressions will
-   * result in a schema definition error. If the value is true, Daffodil will
-   * provide a warning and attempt to coerce the result type to the expected
-   * type.
-   */
-  val allowExpressionResultCoercion: Boolean = true)
-
-  extends Serializable
-  with Logging {
-
-  /* Appear to be Compile-Time as the tunable is obtained from:
-   *  Term, SchemaComponent, Element, etc.
-   *
-   *  maxSkipLengthInBytes
-   *  maxBinaryDecimalVirtualPoint
-   *  minBinaryDecimalVirtualPoint
-   *  requireEncodingErrorPolicyProperty
-   *  requireBitOrderProperty
-   *  requireEmptyElementPolicyProperty
-   *  emptyElementParsePolicy
-   *  generatedNamespacePrefixStem
-   *  parseUnparsePolicy
-   *
-   * Used by StepQNameFactory.  Appears to get tunable from:
-   *  Expressions's DPathCompileInfo
-   *  CompiledExpression's ElementRuntimeData
-   *
-   *  unqualifiedPathStepPolicy
-   *
-   * Appear to be Run-Time as the tunable is obtained from:
-   *  PState/UState
-   *
-   *  initialElementOccurrencesHint
-   *  maxOccursBounds
-   *  maxDataDumpSizeInBytes
-   *
-   * Only used in Main.scala for DataInputStream:
-   *
-   *  maxFieldContentLengthInBytes
-   *
-   * DataInputStream objects:
-   *
-   *  defaultInitRegexMatchLimitInChars
-   *
-   * Unused?
-   *
-   *  maxLengthForVariableLengthDelimiterDisplay
-   *
-   *  */
-
-  def setTunables(tunables: Map[String, String]): DaffodilTunables = {
-    var t = this
-    tunables.foreach { case (k, v) => t = t.setTunable(k, v) }
-    t
-  }
-
-  def setTunable(tunable: String, value: String): DaffodilTunables = {
-    tunable.toLowerCase match {
-      case "maxfieldcontentlengthinbytes" => this.copy(maxFieldContentLengthInBytes = java.lang.Long.valueOf(value))
-      case "defaultinitialregexmatchlimitinchars" => this.copy(defaultInitRegexMatchLimitInChars = java.lang.Long.valueOf(value))
-      case "maxdatadumpsizeinbytes" => this.copy(maxDataDumpSizeInBytes = java.lang.Long.valueOf(value))
-      case "maxoccursbounds" => this.copy(maxOccursBounds = java.lang.Long.valueOf(value))
-      case "maxlengthforvariablelengthdelimiterdisplay" => this.copy(maxLengthForVariableLengthDelimiterDisplay = java.lang.Integer.valueOf(value))
-      case "inputfilememorymaplowthreshold" => this.copy(inputFileMemoryMapLowThreshold = java.lang.Long.valueOf(value))
-      case "initialelementoccurrenceshint" => this.copy(initialElementOccurrencesHint = java.lang.Long.valueOf(value))
-      case "unqualifiedpathsteppolicy" => {
-        val policy = value.toLowerCase match {
-          case "nonamespace" => UnqualifiedPathStepPolicy.NoNamespace
-          case "defaultnamespace" => UnqualifiedPathStepPolicy.DefaultNamespace
-          case "preferdefaultnamespace" => UnqualifiedPathStepPolicy.PreferDefaultNamespace
-          case _ => Assert.usageError("Unknown value for unqualifiedPathStepPolicy tunable. Value must be \"noNamespace\", \"defaultNamespace\", or \"perferDefaultNamespace\".")
-        }
-        this.copy(unqualifiedPathStepPolicy = policy)
-      }
-      case "requirebitorderproperty" => this.copy(requireBitOrderProperty = java.lang.Boolean.valueOf(value))
-      case "requirechoicedispatchkeykindproperty" => this.copy(requireChoiceDispatchKeyKindProperty = java.lang.Boolean.valueOf(value))
-      case "requireencodingerrorpolicyproperty" => this.copy(requireEncodingErrorPolicyProperty = java.lang.Boolean.valueOf(value))
-      case "requiretextbidiproperty" => this.copy(requireTextBidiProperty = java.lang.Boolean.valueOf(value))
-      case "requirefloatingproperty" => this.copy(requireFloatingProperty = java.lang.Boolean.valueOf(value))
-      case "requireemptyelementparsepolicyproperty" => this.copy(requireEmptyElementParsePolicyProperty = java.lang.Boolean.valueOf(value))
-      case "defaultemptyelementparsepolicy" => {
-        val policy = value.toLowerCase match {
-          case "treatasmissing" => EmptyElementParsePolicy.TreatAsMissing
-          case "treatasempty" => EmptyElementParsePolicy.TreatAsEmpty
-          case _ => Assert.usageError("Unknown value for defaultEmptyElementParsePolicy tunable. Value must be \"treatAsMissing\" or \"treatAsEmpty\".")
-        }
-        this.copy(defaultEmptyElementParsePolicy = policy)
-      }
-      case "maxskiplengthinbytes" => this.copy(maxSkipLengthInBytes = java.lang.Long.valueOf(value))
-      case "maxbinarydecimalvirtualpoint" => this.copy(maxBinaryDecimalVirtualPoint = java.lang.Integer.valueOf(value))
-      case "minbinarydecimalvirtualpoint" => this.copy(minBinaryDecimalVirtualPoint = java.lang.Integer.valueOf(value))
-      case "generatednamespaceprefixstem" => this.copy(generatedNamespacePrefixStem = value)
-      case "readerbytebuffersize" => this.copy(readerByteBufferSize = java.lang.Long.valueOf(value))
-      case "parseunparsepolicy" => {
-        val policy = value.toLowerCase match {
-          case "parseonly" => Some(ParseUnparsePolicy.ParseOnly)
-          case "unparseonly" => Some(ParseUnparsePolicy.UnparseOnly)
-          case "both" => Some(ParseUnparsePolicy.Both)
-          case "schema" => None
-          case _ => Assert.usageError("Unknown value for parseUnparsePolicy tunable. Value must be \"parseOnly\", \"unparseOnly\", \"both\", or \"schema\".")
-        }
-        this.copy(parseUnparsePolicy = policy)
-      }
-      case "suppressschemadefinitionwarnings" => {
-        val ws = """\s+"""
-        // value is whitespace separated list of warning identifier strings
-        val warnIDs = value.split(ws).toSeq
-
-        var warningsList: List[WarnID] = Nil
-        warnIDs.foreach { warnIDString =>
-          {
-            WarnID.find(warnIDString) match {
-              case None => log(LogLevel.Warning, "Ignoring unknown warning identifier: %s", warnIDString)
-              case Some(foundID) => warningsList = foundID :: warningsList
-            }
-          }
-        }
-        this.copy(suppressSchemaDefinitionWarnings = warningsList)
-      }
-      case "allowexternalpathexpressions" => this.copy(allowExternalPathExpressions = java.lang.Boolean.valueOf(value))
-      case "erroronunsupportedjavaversion" => this.copy(errorOnUnsupportedJavaVersion = java.lang.Boolean.valueOf(value))
-      case "maximumsimpleelementsizeincharacters" => this.copy(maximumSimpleElementSizeInCharacters = java.lang.Integer.valueOf(value))
-      case "initialregexmatchlimitincharacters" => this.copy(initialRegexMatchLimitInCharacters = java.lang.Integer.valueOf(value))
-      case "maximumregexmatchlengthincharacters" => this.copy(maximumRegexMatchLengthInCharacters = java.lang.Integer.valueOf(value))
-      case "allowexpressionresultcoercion" => this.copy(allowExpressionResultCoercion = java.lang.Boolean.valueOf(value))
-      case _ => {
-        log(LogLevel.Warning, "Ignoring unknown tunable: %s", tunable)
-        this
-      }
-    }
-  }
-
-  def notSuppressedWarning(warnID: WarnID) =
-    !suppressSchemaDefinitionWarnings.contains(warnID) &&
-      !suppressSchemaDefinitionWarnings.contains(WarnID.All)
-
-}
diff --git a/daffodil-lib/src/main/scala/org/apache/daffodil/api/UnqualifiedPathStepPolicy.scala b/daffodil-lib/src/main/scala/org/apache/daffodil/api/UnqualifiedPathStepPolicy.scala
deleted file mode 100644
index ccd3776..0000000
--- a/daffodil-lib/src/main/scala/org/apache/daffodil/api/UnqualifiedPathStepPolicy.scala
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.daffodil.api
-
-import org.apache.daffodil.util.Enum
-
-  /**
-   * Specified how unqualified path steps are resolved.
-   *
-   * NoNamespace:
-   *  Unqualified path steps remain unqualified and will only match elements in
-   *  NoNamespace. A prefix must be provided to match namespaced elements.
-   *
-   * DefaultNamespace:
-   *  Unqualified path steps will always use the default namespace. If a default
-   *  namespace is defined, it is not possible to match a NoNamespace element
-   *  with this policy. Because of this, this may not work well with
-   *  elementFormDefault="unqualified".
-   *
-   * PreferDefaultNamespace
-   *  Attempt to use the default namespace to resolve a step. If that fails to
-   *  match an element, then try to resolve using NoNamespace.
-   */
-  object UnqualifiedPathStepPolicy extends Enum {
-    abstract sealed trait Type extends EnumValueType
-    case object NoNamespace extends Type
-    case object DefaultNamespace extends Type
-    case object PreferDefaultNamespace extends Type
-  }
\ No newline at end of file
diff --git a/daffodil-lib/src/main/scala/org/apache/daffodil/api/WarnID.scala b/daffodil-lib/src/main/scala/org/apache/daffodil/api/WarnID.scala
deleted file mode 100644
index 4a7c99b..0000000
--- a/daffodil-lib/src/main/scala/org/apache/daffodil/api/WarnID.scala
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.daffodil.api
-
-import org.apache.daffodil.exceptions.ThrowsSDE
-import org.apache.daffodil.exceptions.Assert
-import org.apache.daffodil.schema.annotation.props.{ Enum => PropsEnum }
-
-sealed trait WarnID extends WarnID.Value
-
-/**
- * Warning Identifiers for use in suppressing warning messages that are
- * unavoidable and not helpful.
- *
- * TODO: This file really should be generated from dafext.xsd's
- * enumerations for the XML syntax that specifies these suppressions in
- * config files. As this list grows, it's more and more unwieldy.
- */
-object WarnID extends PropsEnum[WarnID] {
-  /**
-   * Suppresses All Warnings
-   */
-  case object All extends WarnID; forceConstruction(All)
-
-  /**
-   * For selective suppression of individual warnings.
-   *
-   * Please add additional, preserving alphabetical order and copying the
-   * apparent naming conventions.
-   */
-  case object AlignmentNotSame extends WarnID; forceConstruction(AlignmentNotSame)
-  case object AppinfoDFDLSourceWrong extends WarnID; forceConstruction(AppinfoDFDLSourceWrong)
-  case object AppinfoNoSource extends WarnID; forceConstruction(AppinfoNoSource)
-  case object ChoiceInsideHiddenGroup extends WarnID; forceConstruction(ChoiceInsideHiddenGroup)
-
-  /**
-   * For DeprecatedThing warning suppression
-   */
-  case object DeprecatedBuiltInFormats extends WarnID; forceConstruction(DeprecatedBuiltInFormats)
-  case object DeprecatedEncodingNameUSASCII7BitPacked extends WarnID; forceConstruction(DeprecatedEncodingNameUSASCII7BitPacked)
-  case object DeprecatedFunctionDAFError extends WarnID; forceConstruction(DeprecatedFunctionDAFError)
-
-  /**
-   * Deprecated properties should all begin with "DeprecatedProperty..."
-   */
-  case object DeprecatedPropertySeparatorPolicy extends WarnID; forceConstruction(DeprecatedPropertySeparatorPolicy)
-  case object EncodingErrorPolicyError extends WarnID; forceConstruction(EncodingErrorPolicyError)
-  case object TextBidiError extends WarnID; forceConstruction(TextBidiError)
-  case object FloatingError extends WarnID; forceConstruction(FloatingError)
-  case object EscapeSchemeRefUndefined extends WarnID; forceConstruction(EscapeSchemeRefUndefined)
-  case object FacetExplicitLengthOutOfRange extends WarnID; forceConstruction(FacetExplicitLengthOutOfRange)
-  case object InconsistentLengthKind extends WarnID; forceConstruction(InconsistentLengthKind)
-  case object IgnoreImport extends WarnID; forceConstruction(IgnoreImport)
-  case object MultipleChoiceBranches extends WarnID; forceConstruction(MultipleChoiceBranches)
-  case object NamespaceDifferencesOnly extends WarnID; forceConstruction(NamespaceDifferencesOnly)
-  case object NoEmptyDefault extends WarnID; forceConstruction(NoEmptyDefault)
-  case object PathNotToArray extends WarnID; forceConstruction(PathNotToArray)
-  case object PatternEncodingSlashW extends WarnID; forceConstruction(PatternEncodingSlashW)
-  case object QueryStylePathExpression extends WarnID; forceConstruction(QueryStylePathExpression)
-  case object RegexPatternZeroLength extends WarnID; forceConstruction(RegexPatternZeroLength)
-  case object EmptyElementParsePolicyError extends WarnID; forceConstruction(EmptyElementParsePolicyError)
-  /**
-   * UnsupportedThing warning suppression.
-   */
-  case object UnsupportedAttributeBlockDefault extends WarnID; forceConstruction(UnsupportedAttributeBlockDefault)
-  case object UnsupportedAttributeFinalDefault extends WarnID; forceConstruction(UnsupportedAttributeFinalDefault)
-  case object UnsupportedAttributeSchemaLocation extends WarnID; forceConstruction(UnsupportedAttributeSchemaLocation)
-  case object UnsupportedAttributeFormDefault extends WarnID; forceConstruction(UnsupportedAttributeFormDefault)
-
-  /**
-   * textOutputMinLength checking
-   */
-  case object TextOutputMinLengthOutOfRange extends WarnID; forceConstruction(TextOutputMinLengthOutOfRange)
-
-  /**
-   * Automatic expression result type coercion
-   */
-  case object DeprecatedExpressionResultCoercion extends WarnID; forceConstruction(DeprecatedExpressionResultCoercion)
-
-  override def apply(name: String, context: ThrowsSDE) = Assert.usageError("not to be called. Call find(name) method instead.")
-
-  def find(name: String): Option[WarnID] = optionStringToEnum("warning identifier", name)
-}
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 1db4e4f..dac12db 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
@@ -15,155 +15,427 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 -->
-<xsd:schema targetNamespace="urn:ogf:dfdl:2013:imp:daffodil.apache.org:2018:ext"
-  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+
+<xs:schema
+  targetNamespace="urn:ogf:dfdl:2013:imp:daffodil.apache.org:2018:ext"
+  xmlns:xs="http://www.w3.org/2001/XMLSchema"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:daf="urn:ogf:dfdl:2013:imp:daffodil.apache.org:2018:ext"
   xmlns:dafint="urn:ogf:dfdl:2013:imp:daffodil.apache.org:2018:int"
-  attributeFormDefault="unqualified" elementFormDefault="qualified"
+  attributeFormDefault="unqualified"
+  elementFormDefault="qualified"
   xsi:schemaLocation="http://www.w3.org/2001/XMLSchema XMLSchema.xsd
   urn:ogf:dfdl:2013:imp:daffodil.apache.org:2018:int xsd/dafint.xsd">
 
-  <xsd:import namespace="urn:ogf:dfdl:2013:imp:daffodil.apache.org:2018:int"/>
+  <xs:import namespace="urn:ogf:dfdl:2013:imp:daffodil.apache.org:2018:int"/>
 
-  <xsd:attribute name="parseUnparsePolicy" type="daf:ParseUnparsePolicyEnum"/>
+  <xs:attribute name="parseUnparsePolicy" type="daf:ParseUnparsePolicyEnum"/>
 
+  <xs:simpleType name="ParseUnparsePolicyEnum">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="both" />
+      <xs:enumeration value="parseOnly" />
+      <xs:enumeration value="unparseOnly" />
+    </xs:restriction>
+  </xs:simpleType>
   
-  <xsd:simpleType name="ParseUnparsePolicyEnum">
-    <xsd:restriction base="xsd:string">
-      <xsd:enumeration value="parseOnly" />
-      <xsd:enumeration value="unparseOnly" />
-      <xsd:enumeration value="both" />
-    </xsd:restriction>
-  </xsd:simpleType>
-  
-  <xsd:attribute name="emptyElementParsePolicy" type="daf:EmptyElementParsePolicyEnum"/>
+  <xs:attribute name="emptyElementParsePolicy" type="daf:EmptyElementParsePolicyEnum"/>
   
-  <xsd:simpleType name="EmptyElementParsePolicyEnum">
-    <xsd:restriction base="xsd:string">
-      <xsd:enumeration value="treatAsMissing" />
-      <xsd:enumeration value="treatAsEmpty" />
-    </xsd:restriction>
-  </xsd:simpleType>
-
-  <xsd:element name="property" type="daf:PropertyType" />
-
-  <xsd:complexType name="PropertyType">
-    <xsd:simpleContent>
-      <xsd:extension base="xsd:string">
-        <xsd:attribute name="name" type="daf:PropertyNameType" use='required'/>
-        <xsd:attributeGroup ref="dafint:daffodilAG"/>
-      </xsd:extension>
-    </xsd:simpleContent>
-  </xsd:complexType>
-
-  <xsd:simpleType name="PropertyNameType">
-    <xsd:restriction base="xsd:string">
-      <xsd:enumeration value="parseUnparsePolicy"/>
-      <xsd:enumeration value="emptyElementParsePolicy"/>
-    </xsd:restriction>
-  </xsd:simpleType>
+  <xs:simpleType name="EmptyElementParsePolicyEnum">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="treatAsEmpty" />
+      <xs:enumeration value="treatAsMissing" />
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:element name="property" type="daf:PropertyType" />
+
+  <xs:complexType name="PropertyType">
+    <xs:simpleContent>
+      <xs:extension base="xs:string">
+        <xs:attribute name="name" type="daf:PropertyNameType" use='required'/>
+        <xs:attributeGroup ref="dafint:daffodilAG"/>
+      </xs:extension>
+    </xs:simpleContent>
+  </xs:complexType>
 
+  <xs:simpleType name="PropertyNameType">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="emptyElementParsePolicy"/>
+      <xs:enumeration value="parseUnparsePolicy"/>
+    </xs:restriction>
+  </xs:simpleType>
 
   <!-- properties related to daffodil configuration -->
 
-  <xsd:element name="externalVariableBindings" type="daf:externalVarType" />
-  <xsd:complexType name="externalVarType">
-    <xsd:sequence>
-      <xsd:element ref="daf:bind" minOccurs="0" maxOccurs="unbounded" />
-    </xsd:sequence>
-  </xsd:complexType>
-
-  <xsd:element name="bind" type="daf:bindType" />
-
-  <xsd:simpleType name="bindNameType">
-    <xsd:restriction base="xsd:string" />
-  </xsd:simpleType>
-  <xsd:complexType name="bindType">
-    <xsd:simpleContent>
-      <xsd:extension base="daf:bindNameType">
-        <xsd:attribute name="name" use="required">
-          <xsd:simpleType>
-            <xsd:restriction base="xsd:string" />
-          </xsd:simpleType>
-        </xsd:attribute>
-      </xsd:extension>
-    </xsd:simpleContent>
-  </xsd:complexType>
-
-  <xsd:element name="tunables">
-      <xsd:complexType>
-      <xsd:all><!-- any order but only 0 or 1 time each -->
-        <xsd:element name="requireBitOrderProperty" minOccurs="0" type="xsd:boolean" />
-        <xsd:element name="requireEncodingErrorPolicyProperty" minOccurs="0" type="xsd:boolean" />
-        <xsd:element name="requireTextBidiProperty" minOccurs="0" type="xsd:boolean" />
-        <xsd:element name="requireFloatingProperty" minOccurs="0" type="xsd:boolean" />
-        <xsd:element name="maxFieldContentLengthInBytes" minOccurs="0" type="xsd:int" />
-        <xsd:element name="maxOccursBounds" minOccurs="0" type="xsd:int" />
-        <xsd:element name="maxSkipLengthInBytes" minOccurs="0" type="xsd:int" />
-        <xsd:element name="maxBinaryDecimalVirtualPoint" minOccurs="0" type="xsd:int" />
-        <xsd:element name="minBinaryDecimalVirtualPoint" minOccurs="0" type="xsd:int" />
-        <xsd:element name="generatedNamespacePrefixStem" minOccurs="0" type="xsd:string" />
-        <xsd:element name="readerByteBufferSize" minOccurs="0" type="xsd:int" />
-        <xsd:element name="maxLengthForVariableLengthDelimiterDisplay" minOccurs="0" type="xsd:int" />
-        <xsd:element name="inputFileMemoryMapLowThreshold" minOccurs="0" type="xsd:int" />
-        <xsd:element name="maximumSimpleElementSizeInCharacters" minOccurs="0" type="xsd:int" />
-        <xsd:element name="initialRegexMatchLimitInCharacters" minOccurs="0" type="xsd:int" />
-        <xsd:element name="maximumRegexMatchLengthInCharacters" minOccurs="0" type="xsd:int" />
-        <xsd:element name="parseUnparsePolicy" minOccurs="0" type="daf:ParseUnparsePolicyEnum"/>
-        <xsd:element name="unqualifiedPathStepPolicy" minOccurs="0">
-          <xsd:simpleType>
-            <xsd:restriction base="xsd:string">
-              <xsd:enumeration value="noNamespace" />
-              <xsd:enumeration value="defaultNamespace" />
-              <xsd:enumeration value="preferDefaultNamespace" />
-            </xsd:restriction>
-          </xsd:simpleType>
-        </xsd:element>
-        <xsd:element name="suppressSchemaDefinitionWarnings" minOccurs="0">
-           <xsd:simpleType>
-           <xsd:list>
-             <xsd:simpleType>
-               <xsd:restriction base="xsd:token">
-                 <xsd:enumeration value="all"/>
-                 <!-- 
-                    Please keep these in alphabetical order
-                     -->
-                 <xsd:enumeration value="alignmentNotSame"/>
-                 <xsd:enumeration value="appinfoDFDLSourceWrong"/>
-                 <xsd:enumeration value="appinfoNoSource"/>
-                 <xsd:enumeration value="choiceInsideHiddenGroup" />
-                 <xsd:enumeration value="deprecatedBuiltInFormats"/>
-                 <xsd:enumeration value="deprecatedEncodingNameUSASCII7BitPacked"/>
-                 <xsd:enumeration value="deprecatedFunctionDAFError"/>
-                 <xsd:enumeration value="deprecatedPropertySeparatorPolicy" />
-                 <xsd:enumeration value="deprecatedExpressionResultCoercion" />
-                 <xsd:enumeration value="emptyElementParsePolicyError" />
-                 <xsd:enumeration value="encodingErrorPolicyError"/>
-                 <xsd:enumeration value="escapeSchemeRefUndefined"/>
-                 <xsd:enumeration value="facetExplicitLengthOutOfRange"/>
-                 <xsd:enumeration value="inconsistentLengthKind"/>
-                 <xsd:enumeration value="multipleChoiceBranches"/>
-                 <xsd:enumeration value="namespaceDifferencesOnly"/>
-                 <xsd:enumeration value="noEmptyDefault"/>
-                 <xsd:enumeration value="pathNotToArray" />
-                 <xsd:enumeration value="patternEncodingSlashW"/>
-                 <xsd:enumeration value="queryStylePathExpression"/>
-                 <xsd:enumeration value="regexPatternZeroLength" />
-                 <xsd:enumeration value="unsupportedAttributeBlockDefault" />
-                 <xsd:enumeration value="unsupportedAttributeFinalDefault" />
-                 <xsd:enumeration value="unsupportedAttributeFormDefault" />
-                 <xsd:enumeration value="unsupportedAttributeSchemaLocation" />
-               </xsd:restriction>
-             </xsd:simpleType>
-           </xsd:list>
-           </xsd:simpleType>
-        </xsd:element>
-        <xsd:element name="allowExpressionResultCoercion" minOccurs="0" type="xsd:boolean" />
-        <xsd:element name="defaultEmptyElementParsePolicy" minOccurs="0" type="daf:EmptyElementParsePolicyEnum"/>
-        <xsd:element name="requireEmptyElementParsePolicyProperty" minOccurs="0" type="xsd:boolean" />
-      </xsd:all>
-    </xsd:complexType>
-  </xsd:element>
-
-</xsd:schema>
+  <xs:element name="externalVariableBindings" type="daf:externalVarType" />
+
+  <xs:complexType name="externalVarType">
+    <xs:sequence>
+      <xs:element ref="daf:bind" minOccurs="0" maxOccurs="unbounded" />
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:element name="bind" type="daf:bindType" />
+
+  <xs:simpleType name="bindNameType">
+    <xs:restriction base="xs:string" />
+  </xs:simpleType>
+
+  <xs:complexType name="bindType">
+    <xs:simpleContent>
+      <xs:extension base="daf:bindNameType">
+        <xs:attribute name="name" use="required">
+          <xs:simpleType>
+            <xs:restriction base="xs:string" />
+          </xs:simpleType>
+        </xs:attribute>
+      </xs:extension>
+    </xs:simpleContent>
+  </xs:complexType>
+
+  <xs:element name="tunables">
+    <xs:complexType>
+      <xs:all>
+        <xs:element name="allowExpressionResultCoercion" type="xs:boolean" default="true" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              Defines how Daffodil coerces expressions where the result type differs
+              from the expected type. As an example, assume the expected type of an
+              expression is an xs:string, but the expression is { 3 }. In this case, the
+              expression result is an xs:int, which should not be automatically coerced
+              to an xs:string. Instead, the expression should be { xs:string(3) } or { "3" }
+              If the value of this tunable is false, these types of expressions will
+              result in a schema definition error. If the value is true, Daffodil will
+              provide a warning and attempt to coerce the result type to the expected
+              type.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="allowExternalPathExpressions" type="xs:boolean" default="false" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              By default, path expressions in Daffodil will only work correctly if path
+              steps are used in an expression defined in the schema when compiled. To
+              enable the use of other expressions (e.g. during debugging, where not all
+              expressions are known at schema compile time), set this tunable to true.
+              This may cause a degredation of performance in path expression evaluation,
+              so this should be avoided when in production. This flag is automatically
+              enabled when debugging is enabled.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="defaultInitialRegexMatchLimitInChars" type="xs:int" 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:element>
+        <xs:element name="errorOnUnsupportedJavaVersion" type="xs:boolean" default="true" 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="generatedNamespacePrefixStem" type="xs:string" default="tns" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              Stem to use when generating a namespace prefix when one is not defined for
+              the target naespace.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="initialElementOccurrencesHint" type="xs:int" default="10" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              Initial array buffer size allocated for recurring elements/arrays.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="initialRegexMatchLimitInCharacters" type="xs:int" default="64" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              Initial number of characters to match when performing regular expression
+              matches on input data. When a regex fails to match, more data may be
+              consumed up to the maximumRegexMatchLengthInCharacters tunable.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="inputFileMemoryMapLowThreshold" type="xs:int" default="33554432" 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="maxBinaryDecimalVirtualPoint" type="xs:int" default="200" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              The largest allowed value of the dfdl:binaryDecimalVirtualPoint property.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="maxDataDumpSizeInBytes" type="xs:int" default="256" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              The maximum size of data to retrive when When getting data to display
+              for debugging.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="maxFieldContentLengthInBytes" type="xs:int" default="1048576" 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="maxLengthForVariableLengthDelimiterDisplay" type="xs:int" default="10" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              When unexpected text is found where a delimiter is expected, this is the maximum
+              number of bytes (characters) to display when the expected delimiter is a variable
+              length delimiter.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="maxOccursBounds" type="xs:int" default="2147483647" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              Maximum number of occurances of an array element.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="maxSkipLengthInBytes" type="xs:int" default="1024" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              Maximum number of bytes allowed to skip in a skip region.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="maxValidYear" type="xs:int" default="9999" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              Due to differences in the DFDL spec and ICU4J SimpleDateFormat, we must
+              have SimpleDateFormat parse in lenient mode, which allows the year value
+              to overflow with very large years into possibly negative years. This
+              tunable tunable sets an upper limit for values to prevent overflow.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="maximumRegexMatchLengthInCharacters" type="xs:int" 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:element>
+        <xs:element name="maximumSimpleElementSizeInCharacters" type="xs:int" default="1048576" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              Maximum number of characters to parse when parsing string data.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="minBinaryDecimalVirtualPoint" type="xs:int" default="-200" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              The smallest allowed value of the dfdl:binaryDecimalVirtualPoint property.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="minValidYear" type="xs:int" default="0" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              Due to differences in the DFDL spec and ICU4J SimpleDateFormat, we must
+              have SimpleDateFormat parse in lenient mode, which allows the year value
+              to overflow with very large years into possibly negative years. This
+              tunable tunable sets an upper limit for values to prevent underflow.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="parseUnparsePolicy" type="daf:TunableParseUnparsePolicyTunable" default="fromRoot" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              Whether to compile a schema to support only parsing, only unparsing, both, or to
+              use the daf:parseUnparsePolicy from the root node. All child elements of the root
+              must have a compatable daf:parseUnaprsePolicy property.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="readerByteBufferSize" type="xs:int" default="8192" 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="requireBitOrderProperty" type="xs:boolean" default="false" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              If true, require that the dfdl:bitOrder property is specified. If false, use a
+              default value if the property is not defined in the schema.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="requireChoiceDispatchKeyKindProperty" type="xs:boolean" default="false" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              If true, require that the dfdl:choiceDispatchKeyKind property is specified. If false, use a
+              default value if the property is not defined in the schema.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="requireChoiceBranchKeyKindProperty" type="xs:boolean" default="false" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              If true, require that the dfdl:choiceBranchKeyKind property is specified. If false, use a
+              default value if the property is not defined in the schema.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="requireEmptyElementParsePolicyProperty" type="xs:boolean" default="false" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              If true, require that the dfdl:emptyElementParsePolicy property is specified in
+              the schema. If false, and not defined in the schema, uses the
+              defaultEmptyElementParsePolicy as the value of emptyElementParsePolicy.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="requireEncodingErrorPolicyProperty" type="xs:boolean" default="false" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              If true, require that the dfdl:encodingErrorPolicy property is specified. If
+              false, use a default value if the property is not defined in the schema.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="requireFloatingProperty" type="xs:boolean" default="false" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              If true, require that the dfdl:floating property is specified. If
+              false, use a default value if the property is not defined in the schema.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="requireTextBidiProperty" type="xs:boolean" default="false" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              If true, require that the dfdl:testBidi property is specified. If
+              false, use a default value if the property is not defined in the schema.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="suppressSchemaDefinitionWarnings" type="daf:TunableSuppressSchemaDefinitionWarnings" default="" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              Space-separated list of schema definition warnings that should be ignored,
+              or "all" to ignore all warnings.
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element name="unqualifiedPathStepPolicy" type="daf:TunableUnqualifiedPathStepPolicy" default="noNamespace" minOccurs="0">
+          <xs:annotation>
+            <xs:documentation>
+              Defines how to lookup DFDL expression path steps that to not include a
+              namespace prefix. Values are:
+              - noNamespace: only match elements that do not have a namespace
+              - defaultNamespace: only match elements defined in the default namespace
+              - preferDefaultNamespace: match elements defined in the default namespace;
+                  if non are found, match elemnts that do not have a namespace
+            </xs:documentation>
+          </xs:annotation>
+        </xs:element>
+      </xs:all>
+    </xs:complexType>
+  </xs:element>
+
+  <xs:simpleType name="TunableEmptyElementParsePolicy">
+    <xs:restriction base="daf:EmptyElementParsePolicyEnum" />
+  </xs:simpleType>
+
+  <!--
+    The two 'Tunables' in the name are intentional. The first is the standard for
+    Tunable enums used by the generator. The second is to differentiate between
+    the dfdl property enum and the tunable enum, since they have different allowed
+    values.
+  -->
+  <xs:simpleType name="TunableParseUnparsePolicyTunable">
+    <xs:union>
+      <xs:simpleType>
+        <xs:restriction base="daf:ParseUnparsePolicyEnum" />
+      </xs:simpleType>
+      <xs:simpleType>
+        <xs:restriction base="xs:string">
+          <xs:enumeration value="fromRoot" />
+        </xs:restriction>
+      </xs:simpleType>
+    </xs:union>
+  </xs:simpleType>
+
+  <xs:simpleType name="TunableUnqualifiedPathStepPolicy">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="defaultNamespace" />
+      <xs:enumeration value="noNamespace" />
+      <xs:enumeration value="preferDefaultNamespace" />
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:simpleType name="TunableSuppressSchemaDefinitionWarnings">
+    <xs:list>
+      <xs:simpleType>
+        <xs:restriction base="xs:token">
+          <xs:enumeration value="all" />
+          <xs:enumeration value="alignmentNotSame" />
+          <xs:enumeration value="appinfoDFDLSourceWrong" />
+          <xs:enumeration value="appinfoNoSource" />
+          <xs:enumeration value="choiceInsideHiddenGroup" />
+          <xs:enumeration value="deprecatedBuiltInFormats" />
+          <xs:enumeration value="deprecatedEncodingNameUSASCII7BitPacked" />
+          <xs:enumeration value="deprecatedExpressionResultCoercion" />
+          <xs:enumeration value="deprecatedFunctionDAFError" />
+          <xs:enumeration value="deprecatedPropertySeparatorPolicy" />
+          <xs:enumeration value="emptyElementParsePolicyError" />
+          <xs:enumeration value="encodingErrorPolicyError" />
+          <xs:enumeration value="escapeSchemeRefUndefined" />
+          <xs:enumeration value="facetExplicitLengthOutOfRange" />
+          <xs:enumeration value="floatingError" />
+          <xs:enumeration value="ignoreImport" />
+          <xs:enumeration value="inconsistentLengthKind" />
+          <xs:enumeration value="multipleChoiceBranches" />
+          <xs:enumeration value="namespaceDifferencesOnly" />
+          <xs:enumeration value="noEmptyDefault" />
+          <xs:enumeration value="pathNotToArray" />
+          <xs:enumeration value="patternEncodingSlashW" />
+          <xs:enumeration value="queryStylePathExpression" />
+          <xs:enumeration value="regexPatternZeroLength" />
+          <xs:enumeration value="textBidiError" />
+          <xs:enumeration value="textOutputMinLengthOutOfRange" />
+          <xs:enumeration value="unsupportedAttributeBlockDefault" />
+          <xs:enumeration value="unsupportedAttributeFinalDefault" />
+          <xs:enumeration value="unsupportedAttributeFormDefault" />
+          <xs:enumeration value="unsupportedAttributeSchemaLocation" />
+        </xs:restriction>
+      </xs:simpleType>
+    </xs:list>
+  </xs:simpleType>
+
+</xs:schema>
diff --git a/daffodil-propgen/src/main/scala/org/apache/daffodil/propGen/PropertyGenerator.scala b/daffodil-propgen/src/main/scala/org/apache/daffodil/propGen/PropertyGenerator.scala
index 76fb639..ce092c2 100644
--- a/daffodil-propgen/src/main/scala/org/apache/daffodil/propGen/PropertyGenerator.scala
+++ b/daffodil-propgen/src/main/scala/org/apache/daffodil/propGen/PropertyGenerator.scala
@@ -39,7 +39,8 @@ class PropertyGenerator(arg: Node) {
   val excludedTypes = List("Property", "EmptyElementParsePolicy", "TextNumberBase", "AlignmentType", "FillByteType", "BinaryBooleanTrueRepType", "BinaryBooleanFalseRepType",
     "SeparatorSuppressionPolicy", "dafint:daffodilAG", "TextStandardExponentRep", "TextOutputMinLength", // Do these by hand.
     "PropertyNameType", "PropertyType", // Not used and causes conflict with daf namespace
-    "externalVariableBindings", "externalVarType", "bind", "bindNameType", "bindType", "tunables") // Ignore daffodil configuration types
+    "externalVariableBindings", "externalVarType", "bind", "bindNameType", "bindType", "tunables", // Ignore daffodil configuration types
+    "TunableEmptyElementParsePolicy", "TunableParseUnparsePolicyTunable", "TunableSuppressSchemaDefinitionWarnings", "TunableUnqualifiedPathStepPolicy") // Ignore tunable types
 
   val excludedAttributes = List("EmptyElementParsePolicy", "TextNumberBase",
     "SeparatorSuppressionPolicy", "TextStandardExponentRep", "TextOutputMinLength") // Do these by hand.
@@ -641,6 +642,12 @@ object PropertyGenerator {
   def generatedCodeFilename = "GeneratedCode.scala"
   def generatedCodePackage = "org.apache.daffodil.schema.annotation.props.gen"
 
+  def tunableCodeFilename = "DaffodilTunablesGen.scala"
+  def tunableCodePackage = "org.apache.daffodil.api"
+
+  def warnIdCodeFilename = "WarnIdGen.scala"
+  def warnIdCodePackage = "org.apache.daffodil.api"
+
   def preamble = "package " + generatedCodePackage + """
 
 ////////////////////////////////////////////////////////////////////////////////////////////
@@ -677,6 +684,13 @@ import org.apache.daffodil.exceptions.ThrowsSDE
     allThunks
   }
 
+  def getGeneratedFilePath(rootDir: String, pkg: String, filename: String): String = {
+    val outDir = new java.io.File(rootDir + "/" + pkg.split('.').reduceLeft(_ + "/" + _))
+    outDir.mkdirs()
+    val outPath = outDir + "/" + filename
+    outPath
+  }
+
   /**
    * Main - run as a scala application to actually create a new GeneratedCode.scala file in the gen directory.
    */
@@ -687,14 +701,20 @@ import org.apache.daffodil.exceptions.ThrowsSDE
 
     val thunks = generateThunks()
 
-    val outDir = new java.io.File(args(0) + "/" + generatedCodePackage.split('.').reduceLeft(_ + "/" + _))
-    outDir.mkdirs()
-    val outPath = outDir + "/" + generatedCodeFilename
-    val outwriter = new java.io.FileWriter(outPath)
+    val generatedCodePath = getGeneratedFilePath(args(0), generatedCodePackage, generatedCodeFilename)
+    writeGeneratedCode(thunks, new java.io.FileWriter(generatedCodePath))
+    System.out.println(generatedCodePath)
+
+    val tunablePath = getGeneratedFilePath(args(0), tunableCodePackage, tunableCodeFilename)
+    val tunableGenerator = new TunableGenerator(daffodilExtensionsXML)
+    tunableGenerator.writeGeneratedCode(new java.io.FileWriter(tunablePath))
+    System.out.println(tunablePath)
 
-    writeGeneratedCode(thunks, outwriter)
+    val warnIdPath = getGeneratedFilePath(args(0), warnIdCodePackage, warnIdCodeFilename)
+    val warnIdGenerator = new WarnIDGenerator(daffodilExtensionsXML)
+    warnIdGenerator.writeGeneratedCode(new java.io.FileWriter(warnIdPath))
+    System.out.println(warnIdPath)
 
-    System.out.println(outPath)
   }
 
   //
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
new file mode 100644
index 0000000..c2be36e
--- /dev/null
+++ b/daffodil-propgen/src/main/scala/org/apache/daffodil/propGen/TunableGenerator.scala
@@ -0,0 +1,292 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.daffodil.propGen
+
+import scala.xml.XML
+
+class TunableGenerator(schema: scala.xml.Node) {
+
+  val top = """
+    |/*
+    | * Licensed to the Apache Software Foundation (ASF) under one or more
+    | * contributor license agreements.  See the NOTICE file distributed with
+    | * this work for additional information regarding copyright ownership.
+    | * The ASF licenses this file to You 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 org.apache.daffodil.api
+    |
+    |////////////////////////////////////////////////////////////////////////////////////////////
+    |//
+    |// Generated Code - Do not hand modify!
+    |//
+    |// This file is entirely generated code created from the
+    |// XML Schema files that describe Daffodil configuration files.
+    |//
+    |// Don't edit this. Go fix the generator to create what you need instead.
+    |//
+    |////////////////////////////////////////////////////////////////////////////////////////////
+    |
+    |import org.apache.daffodil.exceptions.Assert
+    |import org.apache.daffodil.exceptions.ThrowsSDE
+    |import org.apache.daffodil.schema.annotation.props.EmptyElementParsePolicy
+    |import org.apache.daffodil.schema.annotation.props.Enum
+    |import org.apache.daffodil.util.LogLevel
+    |import org.apache.daffodil.util.Logging
+    |import org.apache.daffodil.util.Misc
+    |import org.apache.daffodil.xml.DaffodilXMLLoader
+    |
+    |object DaffodilTunables {
+    |
+    |  def apply(tunables: Map[String, String]): DaffodilTunables = {
+    |    apply().setTunables(tunables)
+    |  }
+    |
+    |  def apply(tunable: String, value: String): DaffodilTunables = {
+    |    apply().setTunable(tunable, value)
+    |  }
+    |
+    |  def apply(): DaffodilTunables = {
+    |    // override tunables from the global configuration file on the class path, if it exists
+    |    val (configOpt, _) = Misc.getResourceOption("/daffodil-config.xml")
+    |    val configTunables: Map[String, String] =
+    |      if (configOpt.isDefined) {
+    |        val loader = new DaffodilXMLLoader()
+    |        val node = loader.load(URISchemaSource(configOpt.get))
+    |        val trimmed = scala.xml.Utility.trim(node)
+    |        val tunablesNode = (trimmed \ "tunables").headOption
+    |        val tunablesMap: Map[String, String] = tunablesNode match {
+    |          case None => Map.empty
+    |          case Some(tunableNode) => {
+    |            tunableNode.child.map { n => (n.label, n.text) }.toMap
+    |          }
+    |        }
+    |        tunablesMap
+    |      } else {
+    |        Map.empty
+    |      }
+    |
+    |    new DaffodilTunables().setTunables(configTunables)
+    |  }
+    |}
+    |
+    |case class DaffodilTunables private (
+    """.trim.stripMargin
+
+  val middle = """
+    |  extends Serializable
+    |  with Logging {
+    |
+    |  def setTunables(tunables: Map[String, String]): DaffodilTunables = {
+    |    tunables.foldLeft(this) { case (dafTuns, (tunable, value)) => dafTuns.setTunable(tunable, value) }
+    |  }
+    |
+    |  def setTunable(tunable: String, value: String): DaffodilTunables = {
+    |    tunable match {
+    """.trim.stripMargin
+
+  val bottom = """
+    |      case _ => throw new IllegalArgumentException("Unknown tunable: " + tunable)
+    |    }
+    |  }
+    |
+    |  def notSuppressedWarning(warnID: WarnID) =
+    |    !suppressSchemaDefinitionWarnings.contains(warnID) &&
+    |      !suppressSchemaDefinitionWarnings.contains(WarnID.All)
+    |
+    |}
+    """.trim.stripMargin
+
+  val tunablesRoot = (schema \ "element").find(_ \@ "name" == "tunables").get
+  val tunableNodes = tunablesRoot \\ "all" \ "element"
+
+  val excludedSimpleTypes = Seq(
+    "TunableEmptyElementParsePolicy",
+    "TunableSuppressSchemaDefinitionWarnings"
+  )
+  val tunableSimpleTypeNodes = (schema \ "simpleType")
+    .filter { st => (st \@ "name").startsWith("Tunable") }
+    .filter { st => !excludedSimpleTypes.contains(st \@ "name") }
+
+  def writeGeneratedCode(w: java.io.FileWriter) {
+    val tunables =
+      tunableNodes.map { tunableNode =>
+        val schemaName = tunableNode \@ "name"
+        val schemaType = tunableNode \@ "type"
+        val schemaDefault = tunableNode \@ "default"
+
+        val tunable =
+          if (schemaName == "suppressSchemaDefinitionWarnings") {
+            // special case, list of enums
+            new EnumListTunable(schemaName, schemaType, schemaDefault, "WarnID")
+          } else if (!schemaType.startsWith("xs:")) {
+            // non-primitive type, assume a single enum
+            new EnumTunable(schemaName, schemaType, schemaDefault)
+          } else {
+            // primitive type
+            new PrimitiveTunable(schemaName, schemaType, schemaDefault)
+          }
+        tunable
+      }
+
+    w.write(top)
+    w.write("\n")
+    w.write(tunables.map(_.scalaDefinition).mkString("  ", ",\n  ", ")"))
+    w.write("\n")
+    w.write(middle)
+    w.write("\n")
+    w.write(tunables.map(_.scalaConversion.split("\n").mkString("      ", "\n      ", "")).mkString("\n"))
+    w.write("\n")
+    w.write(bottom)
+    w.write("\n")
+    w.write("\n")
+
+    val tunableDefinitions =
+      tunableSimpleTypeNodes.map { n =>
+        new TunableEnumDefinition(schema, n)
+      }
+
+    w.write(tunableDefinitions.map(_.scalaEnumeration).mkString("\n"))
+
+    w.flush();
+  }
+}
+
+abstract class TunableBase {
+  def scalaDefinition: String
+  def scalaConversion: String
+}
+
+class PrimitiveTunable(name: String, schemaType: String, schemaDefault: String)
+  extends TunableBase {
+
+  private val scalaType = schemaType match {
+    case "xs:boolean" => "Boolean"
+    case "xs:int" =>  "Int"
+    case "xs:string" => "String"
+  }
+
+  private val scalaDefault = schemaType match {
+    case "xs:string" => "\"" + schemaDefault + "\""
+    case _ => schemaDefault
+  }
+
+  override val scalaDefinition = s"""val ${name}: ${scalaType} = ${scalaDefault}"""
+  override val scalaConversion = s"""case "${name}" => this.copy(${name} = value.to${scalaType})"""
+}
+
+class EnumTunable(name: String, schemaType: String, schemaDefault: String)
+  extends TunableBase {
+
+  private val scalaType = schemaType.stripPrefix("daf:Tunable")
+  private val scalaDefault = scalaType + "." + schemaDefault.head.toUpper + schemaDefault.tail
+
+  override val scalaDefinition = s"""val ${name}: ${scalaType} = ${scalaDefault}"""
+  override val scalaConversion = s"""
+    |case "${name}" => {
+    |  val vOpt = ${scalaType}.optionStringToEnum("${scalaType}", value)
+    |  val v = vOpt.getOrElse(throw new IllegalArgumentException("For input string: \\"" + value + "\\""))
+    |  this.copy(${name} = v)
+    |}
+    """.trim.stripMargin
+}
+
+class EnumListTunable(name: String, schemaType: String, schemaDefault: String, listType: String)
+  extends TunableBase {
+
+  val scalaDefault = {
+    val trimmedDefault = schemaDefault.trim
+    if (trimmedDefault == "") {
+      "Nil"
+    } else {
+      val defaultSeq = trimmedDefault.split("\\s+").map(d => s"${listType}.${d.head.toUpper + d.tail}")
+      s"""Seq(${defaultSeq.mkString(", ")})"""
+    }
+
+  }
+
+  override val scalaDefinition = s"val ${name}: Seq[${listType}] = ${scalaDefault}"
+  override val scalaConversion = s"""
+    |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 + "\\""))
+    |  }
+    |  this.copy(${name} = values)
+    |}
+    """.trim.stripMargin
+}
+
+class TunableEnumDefinition(schemaRoot: scala.xml.Node, simpleTypeNode: scala.xml.Node) {
+  private val nodeName = (simpleTypeNode \@ "name").stripPrefix("Tunable")
+  private val scalaType = nodeName.head.toUpper + nodeName.tail
+
+  /**
+   * Returns a list of all string values of enumerations. If a simpletype is a
+   * untion of other simple types, it recursively gets their enumeration values
+   * and combines everything.
+   */
+  private def getAllEnumerationValues(node: scala.xml.Node): Seq[String] = {
+    val restrictions = node \\ "restriction"
+    restrictions.flatMap { r =>
+      val base = r \@ "base"
+      val enumerationValues =
+        if (base.startsWith("xs:")) {
+          (r \ "enumeration").map(_ \@ "value")
+        } else {
+          val local = base.split(":")(1)
+          val restrictionSimpleTypeNode =
+            (schemaRoot \ "simpleType").find(_ \@ "name" == base.split(":")(1)).get
+          getAllEnumerationValues(restrictionSimpleTypeNode)
+        }
+      enumerationValues
+    }
+  }
+
+  private val allEnumerationValues = getAllEnumerationValues(simpleTypeNode)
+
+  private val top = s"""
+    |sealed trait ${scalaType} extends ${scalaType}.Value
+    |object ${scalaType} extends Enum[${scalaType}] {
+""".trim.stripMargin
+
+  private val scalaEnums = {
+    val scalaEnumValues = allEnumerationValues.map { e => e.head.toUpper + e.tail }
+    scalaEnumValues.map { e => s"""  case object ${e} extends ${scalaType}; forceConstruction(${e})""" }
+  }
+
+  private val bottom = s"""
+    |  override def apply(name: String, context: ThrowsSDE) = Assert.usageError("not to be called. Use optionStringToEnum")
+    |}
+""".stripMargin
+
+  val scalaEnumeration = {
+    top + "\n" + scalaEnums.mkString("\n") + "\n" + bottom
+  }
+
+}
diff --git a/daffodil-propgen/src/main/scala/org/apache/daffodil/propGen/WarnIDGenerator.scala b/daffodil-propgen/src/main/scala/org/apache/daffodil/propGen/WarnIDGenerator.scala
new file mode 100644
index 0000000..88eee5e
--- /dev/null
+++ b/daffodil-propgen/src/main/scala/org/apache/daffodil/propGen/WarnIDGenerator.scala
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.daffodil.propGen
+
+import scala.xml.XML
+
+class WarnIDGenerator(schema: scala.xml.Node) {
+
+  val top = """
+    |/*
+    | * Licensed to the Apache Software Foundation (ASF) under one or more
+    | * contributor license agreements.  See the NOTICE file distributed with
+    | * this work for additional information regarding copyright ownership.
+    | * The ASF licenses this file to You 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 org.apache.daffodil.api
+    |
+    |////////////////////////////////////////////////////////////////////////////////////////////
+    |//
+    |// Generated Code - Do not hand modify!
+    |//
+    |// This file is entirely generated code created from the
+    |// XML Schema files that describe Daffodil configuration files.
+    |//
+    |// Don't edit this. Go fix the generator to create what you need instead.
+    |//
+    |////////////////////////////////////////////////////////////////////////////////////////////
+    |
+    |import org.apache.daffodil.exceptions.Assert
+    |import org.apache.daffodil.exceptions.ThrowsSDE
+    |import org.apache.daffodil.schema.annotation.props.Enum
+    |
+    |sealed trait WarnID extends WarnID.Value
+    |object WarnID extends Enum[WarnID] {
+    """.trim.stripMargin
+
+  val bottom = """
+    |  override def apply(name: String, context: ThrowsSDE) = Assert.usageError("not to be called. Use optionStringToEnum")
+    |}
+    """.trim.stripMargin
+
+  val ssdwNode = (schema \ "simpleType").find( _ \@ "name" == "TunableSuppressSchemaDefinitionWarnings").get
+  val enumerationNodes = (ssdwNode \\ "enumeration")
+
+  def writeGeneratedCode(w: java.io.FileWriter) {
+    w.write(top)
+    w.write("\n")
+
+    enumerationNodes.foreach { node =>
+      val enumName = node \@ "value"
+      val scalaName = enumName.head.toUpper + enumName.tail
+      w.write(s"  case object ${scalaName} extends WarnID; forceConstruction($scalaName)\n")
+    }
+
+    w.write("\n")
+    w.write(bottom)
+    w.flush();
+  }
+}