| /* |
| * 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 |
| |
| import org.apache.daffodil.util._ |
| |
| object Processor { |
| /** |
| * This initialize routine is really part of compiling the DFDL schema so should be called from there. |
| * This insures that it is not, for example, being multi-threaded. If called from the runtime module, compilation might |
| * actually end up happening at run time. |
| */ |
| def initialize(proc: Processor) { |
| ensureCompiled(proc) |
| } |
| |
| private def ensureCompiled(proc: Processor) { |
| if (!proc.isInitialized) { |
| proc.isInitialized = true |
| // proc.childProcessors.foreach { cp => |
| // Assert.invariant(!cp.isEmpty) |
| // } |
| proc.runtimeDependencies.foreach { ensureCompiled } |
| proc.childProcessors.foreach { ensureCompiled } |
| } |
| } |
| |
| private def ensureCompiled(ev: Evaluatable[AnyRef]) { |
| ev.ensureCompiled |
| ev.runtimeDependencies.foreach { ensureCompiled } |
| } |
| } |
| |
| /** |
| * Captures common members for any processor, parser or unparser. |
| */ |
| trait Processor |
| extends ToBriefXMLImpl |
| with Logging |
| with Serializable { |
| // things common to both unparser and parser go here. |
| def context: RuntimeData |
| override def childProcessors: Vector[Processor] |
| def runtimeDependencies: Vector[Evaluatable[AnyRef]] |
| |
| var isInitialized: Boolean = false |
| |
| /** |
| * True if alignment, bit/byte order, and other aspects of real data on the data stream |
| * are relevant. |
| * |
| * True for primitive processors that actually touch the data stream, false |
| * for NoData, and for combinators. |
| * |
| * This enables an optimization in the runtime that doesn't evaluate |
| * expensive expressions for values or checking of encoding, byteOrder, bitOrder |
| * and so forth except for processors where it matters because they actually |
| * interact with the data stream. |
| */ |
| def isPrimitive: Boolean |
| |
| def isEmpty: Boolean |
| } |
| |
| /** |
| * A Prim or Primitive processor does not orchestrate the operation of |
| * other processors, it actually does the work of parsing/unparsing. |
| * |
| * Most PrimProcessor actually manipulate data to/from the data stream. |
| * Some (NoData) do not. |
| */ |
| trait PrimProcessor extends Processor { |
| override def childProcessors: Vector[Processor] = Vector() |
| |
| /** |
| * True if alignment, bit/byte order, and other aspects of real data on the data stream |
| * are relevant. |
| * |
| * True for primitive processors that actually touch the data stream, false |
| * otherwise. |
| */ |
| override def isPrimitive = true |
| } |
| |
| /** |
| * A PrimProcessor which does other work than manipulating the data, such |
| * as evaluating DPath expressions. |
| */ |
| trait PrimProcessorNoData extends Processor { |
| override def childProcessors: Vector[Processor] = Vector() |
| |
| /** |
| * False because NoData processors don't touch the data stream. |
| */ |
| override def isPrimitive = false |
| } |
| |
| /** |
| * A combinator is a processor that orchestrates the operation of |
| * other processors. |
| * |
| * Combinators must be pure. They cannot both touch the data stream directly and |
| * also orchestrate other processors. |
| */ |
| trait CombinatorProcessor extends Processor { |
| |
| /** |
| * False because combinators don't touch the data stream themselves. The |
| * processors they call do that work. |
| */ |
| override final def isPrimitive = false |
| } |
| |
| /** must mixin to all processors that deal with text */ |
| trait TextProcessor |
| |
| /** |
| * BriefXML is XML-style output, but intended for specific purposes. It is NOT |
| * an XML serialization of the data structure. It's an XML-style string, suitable to |
| * manipulate, by people, in XML tooling. E.g., can stick into an XML editor to |
| * then get it all indented nicely, use a structure editor to expand/collapse subregions, |
| * but it is NOT intended to capture all of the state of the object. |
| */ |
| trait ToBriefXMLImpl { |
| |
| private lazy val nom_ : String = Misc.getNameFromClass(this) |
| def nom = nom_ |
| |
| protected def briefXMLAttributes: String = "" |
| |
| def childProcessors: Seq[Processor] |
| |
| // TODO: make this create a DOM tree, not a single string (because of size limits) |
| def toBriefXML(depthLimit: Int = -1): String = { |
| val eltStartText = nom + (if (briefXMLAttributes == "") "" else " " + briefXMLAttributes + " ") |
| if (depthLimit == 0) "..." |
| else if (childProcessors.length == 0) "<" + eltStartText + "/>" |
| else { |
| val lessDepth = depthLimit - 1 |
| val sb = new StringBuilder |
| childProcessors.foreach { |
| cp => |
| val s = cp.toBriefXML(lessDepth) |
| if (sb.size < 3000) sb.append(s) // hack! |
| else sb.append("...") |
| } |
| "<" + eltStartText + ">" + sb + "</" + nom + ">" |
| } |
| } |
| |
| override def toString = toBriefXML() // pParser.toString + " ~ " + qParser.toString |
| } |