Skip to content
Permalink
Browse files
Allow custom debuggers through SAPI and JAPI
DAFFODIL-2491
  • Loading branch information
jw3 committed Mar 31, 2021
1 parent 5032694 commit 7faeb04aa17337487848f5f61141a74d7d82484b
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 23 deletions.
@@ -58,6 +58,7 @@ import java.net.URI

import org.apache.daffodil.api.URISchemaSource
import org.apache.daffodil.api.Validator
import org.apache.daffodil.debugger.Debugger
import org.apache.daffodil.util.Maybe
import org.apache.daffodil.util.Maybe._
import org.apache.daffodil.util.MaybeULong
@@ -532,7 +533,8 @@ class DataProcessor private[japi] (private var dp: SDataProcessor)
/**
* Enable/disable debugging.
*
* Before enabling, [[DataProcessor#setDebugger(DebuggerRunner)]] must be called with a non-null debugger.
* Before enabling, [[DataProcessor#withDebugger]] or [[DataProcessor#withDebuggerRunner(DebuggerRunner)]] must be
* called with a non-null debugger.
*
* @param flag true to enable debugging, false to disabled
*/
@@ -544,7 +546,8 @@ class DataProcessor private[japi] (private var dp: SDataProcessor)
/**
* Obtain a new [[DataProcessor]] instance with debugging enabled or disabled.
*
* Before enabling, [[DataProcessor#withDebugger(DebuggerRunner)]] must be called to obtain a [[DataProcessor]] with a non-null debugger.
* Before enabling, [[DataProcessor#withDebugger(Debugger)]] or [[DataProcessor#withDebuggerRunner(DebuggerRunner)]]
* must be called to obtain a [[DataProcessor]] with a non-null debugger.
*
* @param flag true to enable debugging, false to disabled
*/
@@ -557,7 +560,7 @@ class DataProcessor private[japi] (private var dp: SDataProcessor)
*
* @param dr debugger runner
*/
@deprecated("Use withDebugger.", "2.6.0")
@deprecated("Use withDebuggerRunner.", "2.6.0")
def setDebugger(dr: DebuggerRunner): Unit = {
val debugger = newDebugger(dr)
dp = dp.withDebugger(debugger)
@@ -568,11 +571,20 @@ class DataProcessor private[japi] (private var dp: SDataProcessor)
*
* @param dr debugger runner
*/
def withDebugger(dr: DebuggerRunner): DataProcessor = {
def withDebuggerRunner(dr: DebuggerRunner): DataProcessor = {
val debugger = newDebugger(dr)
copy(dp = dp.withDebugger(debugger))
}

/**
* Obtain a new [[DataProcessor]] with a specified debugger.
*
* @param dbg debugger
*/
def withDebugger(dbg: Debugger): DataProcessor = {
copy(dp = dp.withDebugger(dbg))
}

private def newDebugger(dr: DebuggerRunner) = {
val runner = dr match {
case tdr: TraceDebuggerRunner => new STraceDebuggerRunner()
@@ -0,0 +1,79 @@
/*
* 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.example;

import org.apache.daffodil.debugger.Debugger;
import org.apache.daffodil.japi.Daffodil;
import org.apache.daffodil.japi.DataProcessor;
import org.apache.daffodil.japi.ParseResult;
import org.apache.daffodil.japi.ProcessorFactory;
import org.apache.daffodil.japi.infoset.NullInfosetOutputter;
import org.apache.daffodil.japi.io.InputSourceDataInputStream;
import org.apache.daffodil.processors.parsers.PState;
import org.apache.daffodil.processors.parsers.Parser;
import org.apache.daffodil.util.Misc;
import org.junit.Test;

import java.io.IOException;
import java.net.URI;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class TestCustomDebuggerAPI {
static class CustomDebugger implements Debugger {
public int nodes;
public boolean inited;
public boolean finished;

@Override
public void init(PState state, Parser processor) {
inited = true;
}

@Override
public void before(PState state, Parser processor) {
nodes += 1;
}

@Override
public void fini(Parser processor) {
finished = true;
}
}
@Test
public void testCustomDebugger() throws IOException, ClassNotFoundException {
org.apache.daffodil.japi.Compiler c = Daffodil.compiler();

CustomDebugger dbg = new CustomDebugger();
URI schemaFileName = Misc.getRequiredResource("/test/japi/mySchema1.dfdl.xsd");
ProcessorFactory pf = c.compileSource(schemaFileName);
DataProcessor dp = pf.onPath("/")
.withDebugger(dbg)
.withDebugging(true);

String file = Misc.getRequiredResource("/test/japi/myData2.dat").toURL().getFile();
java.io.FileInputStream fis = new java.io.FileInputStream(file);
InputSourceDataInputStream dis = new InputSourceDataInputStream(fis);
ParseResult res = dp.parse(dis, new NullInfosetOutputter());

assertEquals(6, dbg.nodes);
assertTrue(dbg.inited);
assertTrue(dbg.finished);
}
}
@@ -99,7 +99,7 @@ public void testJavaAPI1() throws IOException, ClassNotFoundException {
ProcessorFactory pf = c.compileFile(schemaFile);
DataProcessor dp = pf.onPath("/");
dp = reserializeDataProcessor(dp);
dp = dp.withDebugger(debugger);
dp = dp.withDebuggerRunner(debugger);
dp = dp.withDebugging(true);

java.io.File file = getResource("/test/japi/myData.dat");
@@ -154,7 +154,7 @@ public void testJavaAPI1_A() throws Exception {
ReadableByteChannel input = Channels.newChannel(is);
org.apache.daffodil.japi.Compiler compiler = Daffodil.compiler();
DataProcessor parser = compiler.reload(input);
parser = parser.withDebugger(debugger);
parser = parser.withDebuggerRunner(debugger);
parser = parser.withDebugging(true);

java.io.File file = getResource("/test/japi/myData.dat");
@@ -199,7 +199,7 @@ public void testJavaAPI1_A_FullFails() throws Exception {
java.io.File schemaFile = getResource("/test/japi/mySchema1.dfdl.xsd");
ProcessorFactory pf = c.compileFile(schemaFile);
DataProcessor dp = pf.onPath("/");
dp = dp.withDebugger(debugger);
dp = dp.withDebuggerRunner(debugger);
dp = dp.withDebugging(true);

// Serialize the parser to memory, then deserialize for parsing.
@@ -661,7 +661,7 @@ public void testJavaAPI12() throws IOException, ClassNotFoundException {
ProcessorFactory pf = c.compileFile(schemaFile);
DataProcessor dp = pf.onPath("/");
dp = reserializeDataProcessor(dp);
dp = dp.withDebugger(debugger);
dp = dp.withDebuggerRunner(debugger);
dp = dp.withDebugging(true);

java.io.File file = getResource("/test/japi/myData.dat");
@@ -702,7 +702,7 @@ public void testJavaAPI13() throws IOException, ClassNotFoundException {

DataProcessor dp = pf.onPath("/");
dp = reserializeDataProcessor(dp);
dp = dp.withDebugger(debugger);
dp = dp.withDebuggerRunner(debugger);
dp = dp.withDebugging(true);
dp = dp.withExternalVariables(extVarsFile);

@@ -744,7 +744,7 @@ public void testJavaAPI14() throws IOException, ClassNotFoundException {
ProcessorFactory pf = c.compileFile(schemaFile);
DataProcessor dp = pf.onPath("/");
dp = reserializeDataProcessor(dp);
dp = dp.withDebugger(debugger);
dp = dp.withDebuggerRunner(debugger);
dp = dp.withDebugging(true);
dp = dp.withExternalVariables(extVarFile);

@@ -1085,7 +1085,7 @@ public void testJavaAPI22_setExternalVariablesUsingAbstractMap() throws IOExcept
ProcessorFactory pf = c.compileFile(schemaFile);
DataProcessor dp = pf.onPath("/");
dp = reserializeDataProcessor(dp);
dp = dp.withDebugger(debugger);
dp = dp.withDebuggerRunner(debugger);
dp = dp.withDebugging(true);

java.util.AbstractMap<String, String> extVarsMap = new java.util.HashMap<String, String>();
@@ -56,6 +56,7 @@ import java.net.URI

import org.apache.daffodil.api.URISchemaSource
import org.apache.daffodil.api.Validator
import org.apache.daffodil.debugger.Debugger
import org.apache.daffodil.sapi.ValidationMode.ValidationMode
import org.apache.daffodil.util.Maybe
import org.apache.daffodil.util.Maybe._
@@ -494,7 +495,8 @@ class DataProcessor private[sapi] (private var dp: SDataProcessor)
/**
* Enable/disable debugging.
*
* Before enabling, [[DataProcessor#setDebugger]] must be called with a non-null debugger.
* Before enabling, [[DataProcessor#withDebugger]] or [[DataProcessor#withDebuggerRunner]] must be called with a
* non-null debugger.
*
* @param flag true to enable debugging, false to disabled
*/
@@ -506,7 +508,8 @@ class DataProcessor private[sapi] (private var dp: SDataProcessor)
/**
* Obtain a new [[DataProcessor]] instance with debugging enabled or disabled.
*
* Before enabling, [[DataProcessor#withDebugger]] must be called to obtain a [[DataProcessor]] with a non-null debugger.
* Before enabling, [[DataProcessor#withDebugger]] or [[DataProcessor#withDebuggerRunner]] must be called to obtain
* a [[DataProcessor]] with a non-null debugger.
*
* @param flag true to enable debugging, false to disabled
*/
@@ -519,7 +522,7 @@ class DataProcessor private[sapi] (private var dp: SDataProcessor)
*
* @param dr debugger runner
*/
@deprecated("Use withDebugger.", "2.6.0")
@deprecated("Use withDebuggerRunner.", "2.6.0")
def setDebugger(dr: DebuggerRunner): Unit = {
val debugger = newDebugger(dr)
dp = dp.withDebugger(debugger)
@@ -530,11 +533,20 @@ class DataProcessor private[sapi] (private var dp: SDataProcessor)
*
* @param dr debugger runner
*/
def withDebugger(dr: DebuggerRunner): DataProcessor = {
def withDebuggerRunner(dr: DebuggerRunner): DataProcessor = {
val debugger = newDebugger(dr)
copy(dp = dp.withDebugger(debugger))
}

/**
* Obtain a new [[DataProcessor]] with a specified debugger.
*
* @param dbg debugger
*/
def withDebugger(dbg: Debugger): DataProcessor = {
copy(dp = dp.withDebugger(dbg))
}

private def newDebugger(dr: DebuggerRunner) = {
val runner = dr match {
case tdr: TraceDebuggerRunner => new STraceDebuggerRunner()
@@ -0,0 +1,62 @@
/*
* 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.example

import org.apache.daffodil.debugger.Debugger
import org.apache.daffodil.processors.parsers.PState
import org.apache.daffodil.processors.parsers.Parser
import org.apache.daffodil.sapi.Daffodil
import org.apache.daffodil.sapi.infoset.NullInfosetOutputter
import org.apache.daffodil.sapi.io.InputSourceDataInputStream
import org.apache.daffodil.util.Misc
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test

class TestCustomDebuggerAPI {
class CustomDebugger extends Debugger {
var nodes = 0
var inited = false
var finished = false

override def init(state: PState, processor: Parser): Unit = inited = true
override def before(state: PState, processor: Parser): Unit = nodes += 1
override def fini(processor: Parser): Unit = finished = true
}

@Test
def testCustomDebugger(): Unit = {
val c = Daffodil.compiler()
val dbg = new CustomDebugger()

val schemaFile = Misc.getRequiredResource("/test/sapi/mySchema1.dfdl.xsd")
val pf = c.compileSource(schemaFile)
val dp = pf.onPath("/")
.withDebugger(dbg)
.withDebugging(true)

val file = Misc.getRequiredResource("/test/sapi/myData.dat")
val fis = new java.io.FileInputStream(file.toURL.getFile)
val input = new InputSourceDataInputStream(fis)
dp.parse(input, new NullInfosetOutputter())

assertEquals(6, dbg.nodes)
assertTrue(dbg.inited)
assertTrue(dbg.finished)
}
}
@@ -122,7 +122,7 @@ class TestScalaAPI {
val pf = c.compileFile(schemaFile)
val dp1 = pf.onPath("/")
val dp = reserializeDataProcessor(dp1)
.withDebugger(debugger)
.withDebuggerRunner(debugger)
.withDebugging(true)
.withValidationMode(ValidationMode.Off)

@@ -181,7 +181,7 @@ class TestScalaAPI {
val savedParser = Channels.newChannel(is)
val compiler = Daffodil.compiler()
val parser = compiler.reload(savedParser)
.withDebugger(debugger)
.withDebuggerRunner(debugger)
.withDebugging(true)
.withValidationMode(ValidationMode.Off)
val file = getResource("/test/sapi/myData.dat")
@@ -641,7 +641,7 @@ class TestScalaAPI {
val pf = c.compileFile(schemaFile)
val dp1 = pf.onPath("/")
val dp = reserializeDataProcessor(dp1)
.withDebugger(debugger)
.withDebuggerRunner(debugger)
.withDebugging(true)
.withValidationMode(ValidationMode.Off)

@@ -688,7 +688,7 @@ class TestScalaAPI {
val dp1 = pf.onPath("/")
val dp = reserializeDataProcessor(dp1)
.withExternalVariables(extVarsFile)
.withDebugger(debugger)
.withDebuggerRunner(debugger)
.withDebugging(true)
.withValidationMode(ValidationMode.Off)

@@ -729,7 +729,7 @@ class TestScalaAPI {
val dp1 = pf.onPath("/")
val dp = reserializeDataProcessor(dp1)
.withExternalVariables(extVarFile)
.withDebugger(debugger)
.withDebuggerRunner(debugger)
.withDebugging(true)
.withValidationMode(ValidationMode.Off)

@@ -779,7 +779,7 @@ class TestScalaAPI {
val schemaFile = getResource("/test/sapi/mySchema1.dfdl.xsd")
val pf = c.compileFile(schemaFile)
val dp = pf.onPath("/")
.withDebugger(debugger)
.withDebuggerRunner(debugger)
.withDebugging(true)
// Serialize the parser to memory, then deserialize for parsing.
val os = new ByteArrayOutputStream()
@@ -816,7 +816,7 @@ class TestScalaAPI {
val pf = c.compileFile(schemaFile)
val dp1 = pf.onPath("/")
val dp = reserializeDataProcessor(dp1)
.withDebugger(debugger)
.withDebuggerRunner(debugger)
.withDebugging(true)

val file = getResource("/test/sapi/myInfosetBroken.xml")
@@ -1098,7 +1098,7 @@ class TestScalaAPI {
val pf = c.compileFile(schemaFile)
val dp1 = pf.onPath("/")
val dp = reserializeDataProcessor(dp1)
.withDebugger(debugger)
.withDebuggerRunner(debugger)
.withDebugging(true)

val file = getResource("/test/sapi/myInfosetBroken.xml")

0 comments on commit 7faeb04

Please sign in to comment.