blob: 2f8b9fa30950a2ddbdd8f1a10e4a9d3b0c5e84e1 [file] [log] [blame]
/* Copyright (c) 2012-2014 Tresys Technology, LLC. All rights reserved.
*
* Developed by: Tresys Technology, LLC
* http://www.tresys.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal with
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimers.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimers in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the names of Tresys Technology, nor the names of its contributors
* may be used to endorse or promote products derived from this Software
* without specific prior written permission.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
* SOFTWARE.
*/
package edu.illinois.ncsa.daffodil.api
import edu.illinois.ncsa.daffodil.exceptions.Assert
import edu.illinois.ncsa.daffodil.schema.annotation.props.gen.ParseUnparsePolicy
import edu.illinois.ncsa.daffodil.util.LogLevel
import edu.illinois.ncsa.daffodil.util.Logging
object DaffodilTunables {
def apply(tunables: Map[String, String]): DaffodilTunables = {
new DaffodilTunables().setTunables(tunables)
}
def apply(tunable: String, value: String): DaffodilTunables = {
new DaffodilTunables().setTunable(tunable, value)
}
def apply(): DaffodilTunables = new DaffodilTunables()
}
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 encodingErrorPolicy property is specified. If
// false, use a default value not defined in a schema
//
// Looks to be compile-time as it gets 'tunable' from Term.
//
val requireEncodingErrorPolicyProperty: Boolean = false,
//
// 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 = 1024, // 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)
extends Serializable
with Logging
with DataStreamLimits {
/* Appear to be Compile-Time as the tunable is obtained from:
* Term, SchemaComponent, Element, etc.
*
* maxSkipLengthInBytes
* maxBinaryDecimalVirtualPoint
* minBinaryDecimalVirtualPoint
* requireEncodingErrorPolicyProperty
* requireBitOrderProperty
* 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 "requireencodingerrorpolicyproperty" => this.copy(requireEncodingErrorPolicyProperty = java.lang.Boolean.valueOf(value))
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 _ => {
log(LogLevel.Warning, "Ignoring unknown tunable: %s", tunable)
this
}
}
}
def notSuppressedWarning(warnID: WarnID) =
!suppressSchemaDefinitionWarnings.contains(warnID) &&
!suppressSchemaDefinitionWarnings.contains(WarnID.All)
def maximumSimpleElementSizeInBytes: Long = this.maxFieldContentLengthInBytes
def maximumSimpleElementSizeInCharacters: Long = this.maxFieldContentLengthInBytes
def maximumForwardSpeculationLengthInBytes: Long = this.maxFieldContentLengthInBytes
def maximumRegexMatchLengthInCharacters: Long = this.maxFieldContentLengthInBytes
def defaultInitialRegexMatchLimitInChars: Long = this.defaultInitRegexMatchLimitInChars
}