blob: 9d4adb2ff7bc7a288627e8887a43487073b29509 [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.processors.unparsers
import org.apache.daffodil.processors.{ SequenceRuntimeData, TermRuntimeData }
import org.apache.daffodil.processors.ElementRuntimeData
import org.apache.daffodil.exceptions.Assert
import org.apache.daffodil.schema.annotation.props.gen.OccursCountKind
trait Unseparated { self: SequenceChildUnparser =>
val childProcessors = Vector(childUnparser)
}
class ScalarOrderedUnseparatedSequenceChildUnparser(
childUnparser: Unparser,
srd: SequenceRuntimeData,
trd: TermRuntimeData)
extends SequenceChildUnparser(childUnparser, srd, trd)
with Unseparated {
override protected def unparse(state: UState) = childUnparser.unparse1(state)
}
class RepOrderedUnseparatedSequenceChildUnparser(
childUnparser: Unparser,
srd: SequenceRuntimeData,
erd: ElementRuntimeData)
extends RepeatingChildUnparser(childUnparser, srd, erd)
with Unseparated {
private val ock = erd.maybeOccursCountKind.get
override def checkArrayPosAgainstMaxOccurs(state: UState): Boolean = {
if (ock eq OccursCountKind.Implicit)
state.arrayPos <= maxRepeats(state)
else
true
}
}
class OrderedUnseparatedSequenceUnparser(rd: SequenceRuntimeData, childUnparsers: Seq[SequenceChildUnparser])
extends OrderedSequenceUnparserBase(rd, childUnparsers.toVector) {
/**
* Unparses one iteration of an array/optional element
*/
protected def unparseOne(
unparser: SequenceChildUnparser,
trd: TermRuntimeData,
state: UState): Unit = {
unparser.unparse1(state)
}
/**
* Unparses an entire sequence, including both scalar and array/optional children.
*/
protected def unparse(state: UState): Unit = {
state.groupIndexStack.push(1L) // one-based indexing
var index = 0
var doUnparser = false
val limit = childUnparsers.length
while (index < limit) {
val childUnparser = childUnparsers(index)
val trd = childUnparser.trd
state.pushTRD(trd) // because we inspect before we invoke the unparser
//
// Unparsing an ordered sequence depends on the incoming
// stream of infoset events matching up with the order that
// they are expected as the unparser recurses through the
// child term unparsers.
//
childUnparser match {
case unparser: RepeatingChildUnparser => {
state.arrayIndexStack.push(1L)
val erd = unparser.erd
var numOccurrences = 0
val maxReps = unparser.maxRepeats(state)
val minReps = unparser.minRepeats(state)
//
// The number of occurrances we unparse is always exactly driven
// by the number of infoset events for the repeating/optional element.
//
// For RepUnparser - array/optional case - in all cases we should get a
// startArray event. If we don't then
// the element must be entirely optional, so we get no events for it
// at all.
//
if (state.inspect) {
val ev = state.inspectAccessor
val isArr = ev.isArray
if (ev.isStart && (isArr || ev.erd.isOptional)) {
val eventNQN = ev.namedQName
if (ev.erd eq erd) {
//
// StartArray for this unparser's array element
//
unparser.startArrayOrOptional(state)
while ({
doUnparser = unparser.shouldDoUnparser(unparser, state)
doUnparser
}) {
if (isArr) if (state.dataProc.isDefined) state.dataProc.get.beforeRepetition(state, this)
unparseOne(unparser, erd, state)
numOccurrences += 1
state.moveOverOneArrayIndexOnly()
state.moveOverOneGroupIndexOnly() // array elements are always represented.
if (isArr) if (state.dataProc.isDefined) state.dataProc.get.afterRepetition(state, this)
}
unparser.checkFinalOccursCountBetweenMinAndMaxOccurs(state, unparser, numOccurrences, maxReps, state.arrayPos - 1)
unparser.endArrayOrOptional(erd, state)
} else {
//
// start array but not for the expected array,
// rather for some other array. Not this one. So we
// don't unparse anything here, and we'll go on to the next
// sequence child, which hopefully will be a matching array.
//
// minReps has to be 0, meaning it is allowed to have zero
// occurrences (not necessarily valid, but allowed),
// because we got zero instances of this array
//
Assert.invariant(minReps == 0L)
}
} else if (ev.isStart) {
Assert.invariant(!isArr && !ev.erd.isOptional)
//
// start of scalar.
// That has to be for a different element later in the sequence
// since this one has a RepUnparser (i.e., is NOT scalar)
val eventNQN = ev.namedQName
Assert.invariant(eventNQN != erd.namedQName)
} else {
Assert.invariant(ev.isEnd && ev.erd.isComplexType)
unparser.checkFinalOccursCountBetweenMinAndMaxOccurs(state, unparser, numOccurrences, maxReps, 0)
}
} else {
// no event (state.inspect returned false)
Assert.invariantFailed("No event for unparing.")
}
state.arrayIndexStack.pop()
}
//
case scalarUnparser => {
unparseOne(scalarUnparser, trd, state)
// only move over in group if the scalar "thing" is an element
// that is represented.
scalarUnparser.trd match {
case erd: ElementRuntimeData if (!erd.isRepresented) => // ok, skip group advance
case _ => state.moveOverOneGroupIndexOnly()
}
}
}
state.popTRD(trd)
index += 1
//
// Note: the invariant is that unparsers move over 1 within their group themselves
// we do not do the moving over here as we are the caller of the unparser.
//
}
state.groupIndexStack.pop()
//
// this is establishing the invariant that unparsers (in this case the sequence unparser)
// moves over within its containing group. The caller of an unparser does not do this move.
//
// state.moveOverOneGroupIndexOnly() // move past this sequence itself, next group child it ITS parent.
}
}