blob: 00fd36d8b1f72ae2f85196d3e36239f1d6691f53 [file] [log] [blame]
/*
* 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.runtime1.layers
import org.apache.daffodil.io.processors.charset.BitsCharsetJava
import org.apache.daffodil.io.processors.charset.BitsCharsetNonByteSize
import org.apache.daffodil.lib.api.WarnID
import org.apache.daffodil.lib.schema.annotation.props.gen.LayerLengthKind
import org.apache.daffodil.lib.schema.annotation.props.gen.LayerLengthUnits
import org.apache.daffodil.lib.xml.NS
import org.apache.daffodil.lib.xml.RefQName
import org.apache.daffodil.runtime1.dpath.NodeInfo.PrimType
import org.apache.daffodil.runtime1.dsom.ImplementsThrowsOrSavesSDE
import org.apache.daffodil.runtime1.processors.SequenceRuntimeData
import org.apache.daffodil.runtime1.processors.VariableRuntimeData
/**
* Must be implemented by all layers.
*
* These are the classes which must be dynamically loaded in order to add a layer implementation
* to Daffodil.
*
* These instances are NOT serialized as part of a saved processor. The compileLayer method
* is called and the resulting LayerTransformerFactory is the serialized object.
*/
abstract class LayerCompiler(nom: String) {
def name() = nom
/**
* Performs all schema-compile-time checking for the layer parameters, and constructs
* a LayerTransformerFactory which is the serialized runtime object that becomes part of the
* processor.
* @param layerCompileInfo Schema-compilation time information about the layer properties.
* @return
*/
def compileLayer(layerCompileInfo: LayerCompileInfo): LayerTransformerFactory
}
/**
* Provides access to DFDL schema compile-time information about the layer properties.
*
* Allows reporting of schema definition errors and warnings at schema compile time.
*/
final class LayerCompileInfo(
sequence: ImplementsThrowsOrSavesSDE,
val layerRuntimeInfo: LayerRuntimeInfo,
) {
private def lri = layerRuntimeInfo
private def srd: SequenceRuntimeData = lri.runtimeData
def getVariableRuntimeData(
prefix: String,
namespace: String,
localName: String,
primType: PrimType,
): VariableRuntimeData = {
val varNamespace = NS(namespace)
val qName = RefQName(Some(prefix), localName, varNamespace).toGlobalQName
val vrd = srd.variableMap.getVariableRuntimeData(qName).getOrElse {
srd.SDE("Variable '%s' is not defined.", qName.toExtendedSyntax)
}
srd.schemaDefinitionUnless(
vrd.primType == primType,
"Variable '%s' is not of type '%s'.",
qName.toExtendedSyntax,
primType,
)
vrd
}
/**
* If defined, and the value is a compile-time constant then this will be Some(Some(Charset))
* If defined, and the value is non-constant or not a regular JVM charset, then this will be Some(None)
* If undefined, the value is None
*/
def optLayerJavaCharsetOptConstantValue: Option[Option[java.nio.charset.Charset]] = {
if (lri.maybeLayerCharsetEv.isEmpty) None
else
lri.maybeLayerCharsetEv.get.optConstant.map {
case java: BitsCharsetJava => Some(java.javaCharset)
case _: BitsCharsetNonByteSize => None
}
}
def optLayerLengthKind: Option[LayerLengthKind] = {
lri.maybeLayerLengthKind.toScalaOption
}
def optLayerLengthOptConstantValue: Option[Option[Long]] = {
if (lri.maybeLayerLengthEv.isEmpty) None
else
Some(lri.maybeLayerLengthEv.get.optConstant.map {
_.toLong
})
}
def optLayerLengthUnits: Option[LayerLengthUnits] = {
lri.maybeLayerLengthUnits.toScalaOption
}
def optLayerBoundaryMarkOptConstantValue: Option[Option[String]] = {
if (lri.maybeLayerBoundaryMarkEv.isEmpty) None
else Some(lri.maybeLayerBoundaryMarkEv.get.optConstant)
}
def schemaDefinitionError(message: String, args: Any*): Nothing = {
sequence.schemaDefinitionError(message, args: _*)
}
def schemaDefinitionWarning(message: String, args: Any*): Unit = {
sequence.SDW(WarnID.LayerCompileWarning, message, args: _*)
}
def SDEUnless(test: Boolean, message: String, args: Any*): Unit =
if (!test) SDE(message, args: _*)
def SDE(message: String, args: Any*): Nothing = schemaDefinitionError(message, args: _*)
}