}
}
}
}
JSONObject json = jsonOutput ? new JSONObject() : null;
// If this is an operator then we need to call the plan generation on the
// conf and then the children
if (work instanceof Operator) {
Operator<? extends OperatorDesc> operator =
(Operator<? extends OperatorDesc>) work;
if (operator.getConf() != null) {
String appender = isLogical ? " (" + operator.getOperatorId() + ")" : "";
JSONObject jsonOut = outputPlan(operator.getConf(), out, extended,
jsonOutput, jsonOutput ? 0 : indent, appender);
if (jsonOutput) {
json = jsonOut;
}
}
if (!visitedOps.contains(operator) || !isLogical) {
visitedOps.add(operator);
if (operator.getChildOperators() != null) {
int cindent = jsonOutput ? 0 : indent + 2;
for (Operator<? extends OperatorDesc> op : operator.getChildOperators()) {
JSONObject jsonOut = outputPlan(op, out, extended, jsonOutput, cindent);
if (jsonOutput) {
((JSONObject)json.get(JSONObject.getNames(json)[0])).accumulate("children", jsonOut);
}
}
}
}
if (jsonOutput) {
return json;
}
return null;
}
// We look at all methods that generate values for explain
Method[] methods = work.getClass().getMethods();
Arrays.sort(methods, new MethodComparator());
for (Method m : methods) {
int prop_indents = jsonOutput ? 0 : indent + 2;
note = m.getAnnotation(Explain.class);
if (note instanceof Explain) {
Explain xpl_note = (Explain) note;
if (extended || xpl_note.normalExplain()) {
Object val = null;
try {
val = m.invoke(work);
}
catch (InvocationTargetException ex) {
// Ignore the exception, this may be caused by external jars
val = null;
}
if (val == null) {
continue;
}
String header = null;
boolean skipHeader = xpl_note.skipHeader();
boolean emptyHeader = false;
if (!xpl_note.displayName().equals("")) {
header = indentString(prop_indents) + xpl_note.displayName() + ":";
}
else {
emptyHeader = true;
prop_indents = indent;
header = indentString(prop_indents);
}
// Try the output as a primitive object
if (isPrintable(val)) {
if (out != null && shouldPrint(xpl_note, val)) {
if (!skipHeader) {
out.printf("%s ", header);
}
out.println(val);
}
if (jsonOutput && shouldPrint(xpl_note, val)) {
json.put(header, val.toString());
}
continue;
}
int ind = 0;
if (!jsonOutput) {
if (!skipHeader) {
ind = prop_indents + 2;
} else {
ind = indent;
}
}
// Try this as a map
try {
// Go through the map and print out the stuff
Map<?, ?> mp = (Map<?, ?>) val;
if (out != null && !skipHeader && mp != null && !mp.isEmpty()) {
out.print(header);
}
JSONObject jsonOut = outputMap(mp, !skipHeader && !emptyHeader, out, extended, jsonOutput, ind);
if (jsonOutput && !mp.isEmpty()) {
json.put(header, jsonOut);
}
continue;
}
catch (ClassCastException ce) {
// Ignore - all this means is that this is not a map
}
// Try this as a list
try {
List l;
try {
l = (List) val;
} catch (ClassCastException e) {
Set s = (Set) val;
l = new LinkedList();
l.addAll(s);
}
if (out != null && !skipHeader && l != null && !l.isEmpty()) {
out.print(header);
}
JSONArray jsonOut = outputList(l, out, !skipHeader && !emptyHeader, extended, jsonOutput, ind);
if (jsonOutput && !l.isEmpty()) {
json.put(header, jsonOut);
}
continue;
}
catch (ClassCastException ce) {
// Ignore
}
// Finally check if it is serializable
try {
Serializable s = (Serializable) val;
if (!skipHeader && out != null) {
out.println(header);
}
JSONObject jsonOut = outputPlan(s, out, extended, jsonOutput, ind);
if (jsonOutput) {
if (!skipHeader) {
json.put(header, jsonOut);
} else {
for(String k: JSONObject.getNames(jsonOut)) {
json.put(k, jsonOut.get(k));
}
}
}
continue;
}
catch (ClassCastException ce) {
// Ignore
}
}
}
}
if (jsonOutput) {
if (keyJSONObject != null) {
JSONObject ret = new JSONObject();
ret.put(keyJSONObject, json);
return ret;
}
return json;
}