blob: 0c37d236273b45250da710b73a4cf61e6b4588c8 [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.drill.exec.vector.accessor.impl;
import java.io.PrintStream;
import java.util.ArrayDeque;
import java.util.Deque;
/**
* Prints a complex object structure in a quasi-JSON format for use
* in debugging. Generally only used in an ad-hoc fashion during
* debugging sessions; never in production.
*/
public class HierarchicalPrinter implements HierarchicalFormatter {
public enum State { OBJECT, OBJECT_ATTRIB, ARRAY, OBJECT_ELEMENT }
private static class ObjState {
private State state = State.OBJECT;
private String attrib;
private int index = -1;
private int extensions;
public ObjState(int extensions) {
this.extensions = extensions;
}
}
private final PrintStream out;
private Deque<ObjState> stack = new ArrayDeque<ObjState>();
private int pendingExtensions = 0;
private ObjState curObject;
private int level;
public HierarchicalPrinter() {
out = System.out;
}
@Override
public void extend() {
pendingExtensions++;
}
@Override
public HierarchicalFormatter startObject(Object obj) {
if (curObject != null) {
stack.push(curObject);
switch (curObject.state) {
case OBJECT_ATTRIB:
startAttrib(curObject.attrib);
curObject.attrib = null;
curObject.state = State.OBJECT;
break;
case OBJECT:
startAttrib("missing-attrib");
curObject.state = State.OBJECT;
break;
case OBJECT_ELEMENT:
startElement(curObject.index);
curObject.state = State.ARRAY;
curObject.index = -1;
break;
default:
assert false;
}
}
printObjIdentity(obj);
out.println(" {");
level++;
curObject = new ObjState(pendingExtensions);
pendingExtensions = 0;
return this;
}
private void printObjIdentity(Object value) {
out.print(value.getClass().getSimpleName());
out.print( " (");
out.print(System.identityHashCode(value) % 1000);
out.print(")");
}
private void startElement(int index) {
indent();
out.print("[");
out.print(index);
out.print("] = ");
}
private void startAttrib(String label) {
indent();
out.print(label);
out.print(" = ");
}
@Override
public HierarchicalFormatter attribute(String label) {
curObject.attrib = label;
curObject.state = State.OBJECT_ATTRIB;
return this;
}
@Override
public HierarchicalFormatter attribute(String label, Object value) {
attribPrefix();
startAttrib(label);
printValue(value);
out.println();
return this;
}
private void attribPrefix() {
switch (curObject.state) {
case OBJECT_ATTRIB:
startAttrib(curObject.attrib);
out.println("<Unknown> {}");
break;
case OBJECT:
break;
default:
assert false;
}
}
@Override
public HierarchicalFormatter attributeIdentity(String label, Object obj) {
attribPrefix();
startAttrib(label);
objIdentity(obj);
out.println();
return this;
}
private void objIdentity(Object obj) {
if (obj == null) {
out.print("null");
} else {
printObjIdentity(obj);
}
}
private void printValue(Object value) {
if (value == null) {
out.print("null");
} else if (value instanceof String) {
out.print("\"");
out.print(value);
out.print("\"");
} else {
out.print(value.toString());
}
}
@Override
public HierarchicalFormatter endObject() {
if (level == 0) {
out.println( "} // Mismatch!");
return this;
}
if (curObject.extensions == 0) {
level--;
indent();
out.println("}");
if (level == 0) {
curObject = null;
} else {
curObject = stack.pop();
}
} else {
curObject.extensions--;
}
return this;
}
private void indent() {
for (int i = 0; i < level; i++) {
out.print(" ");
}
}
@Override
public HierarchicalFormatter attributeArray(String label) {
startAttrib(label);
out.println("[");
level++;
curObject.state = State.ARRAY;
return this;
}
@Override
public HierarchicalFormatter element(int index, Object value) {
startElement(index);
printValue(value);
out.println();
return this;
}
@Override
public HierarchicalFormatter element(int index) {
curObject.index = index;
curObject.state = State.OBJECT_ELEMENT;
return this;
}
@Override
public HierarchicalFormatter elementIdentity(int index, Object obj) {
startElement(index);
objIdentity(obj);
out.println();
return this;
}
@Override
public HierarchicalFormatter endArray() {
level--;
indent();
out.println("]");
curObject.state = State.OBJECT;
return this;
}
}