/* *************************************************************************************** * Copyright (C) 2006 EsperTech, Inc. All rights reserved. * * http://www.espertech.com/esper * * http://www.espertech.com * * ---------------------------------------------------------------------------------- * * The software in this package is published under the terms of the GPL license * * a copy of which has been included with this distribution in the license.txt file. * *************************************************************************************** */ package com.espertech.esper.event.util; import com.espertech.esper.client.EventBean; import com.espertech.esper.client.EventType; import com.espertech.esper.client.util.EventPropertyRenderer; import com.espertech.esper.client.util.EventPropertyRendererContext; import com.espertech.esper.client.util.JSONEventRenderer; import com.espertech.esper.client.util.JSONRenderingOptions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Array; import java.util.Iterator; import java.util.Map; import java.util.Stack; /** * Render for the JSON format. */ public class JSONRendererImpl implements JSONEventRenderer { private static final Logger log = LoggerFactory.getLogger(JSONRendererImpl.class); private final static String NEWLINE = System.getProperty("line.separator"); private final static String COMMA_DELIMITER_NEWLINE = "," + NEWLINE; private final RendererMeta meta; private final RendererMetaOptions rendererOptions; /** * Ctor. * * @param eventType type of event(s) * @param options rendering options */ public JSONRendererImpl(EventType eventType, JSONRenderingOptions options) { EventPropertyRenderer propertyRenderer = null; EventPropertyRendererContext propertyRendererContext = null; if (options.getRenderer() != null) { propertyRenderer = options.getRenderer(); propertyRendererContext = new EventPropertyRendererContext(eventType, true); } rendererOptions = new RendererMetaOptions(options.isPreventLooping(), false, propertyRenderer, propertyRendererContext); meta = new RendererMeta(eventType, new Stack<EventTypePropertyPair>(), rendererOptions); } public String render(String title, EventBean theEvent) { StringBuilder buf = new StringBuilder(); buf.append('{'); buf.append(NEWLINE); ident(buf, 1); buf.append('\"'); buf.append(title); buf.append("\": {"); buf.append(NEWLINE); recursiveRender(theEvent, buf, 2, meta, rendererOptions); ident(buf, 1); buf.append('}'); buf.append(NEWLINE); buf.append('}'); buf.append(NEWLINE); return buf.toString(); } public String render(EventBean theEvent) { StringBuilder buf = new StringBuilder(); buf.append('{'); recursiveRender(theEvent, buf, 2, meta, rendererOptions); buf.append('}'); return buf.toString(); } private static void ident(StringBuilder buf, int level) { for (int i = 0; i < level; i++) { indentChar(buf); } } private static void indentChar(StringBuilder buf) { buf.append(' '); buf.append(' '); } private static void recursiveRender(EventBean theEvent, StringBuilder buf, int level, RendererMeta meta, RendererMetaOptions rendererOptions) { String delimiter = ""; // simple properties GetterPair[] simpleProps = meta.getSimpleProperties(); if (rendererOptions.getRenderer() == null) { for (GetterPair simpleProp : simpleProps) { Object value = simpleProp.getGetter().get(theEvent); writeDelimitedIndentedProp(buf, delimiter, level, simpleProp.getName()); simpleProp.getOutput().render(value, buf); delimiter = COMMA_DELIMITER_NEWLINE; } } else { EventPropertyRendererContext context = rendererOptions.getRendererContext(); context.setStringBuilderAndReset(buf); for (GetterPair simpleProp : simpleProps) { Object value = simpleProp.getGetter().get(theEvent); writeDelimitedIndentedProp(buf, delimiter, level, simpleProp.getName()); context.setDefaultRenderer(simpleProp.getOutput()); context.setPropertyName(simpleProp.getName()); context.setPropertyValue(value); rendererOptions.getRenderer().render(context); delimiter = COMMA_DELIMITER_NEWLINE; } } GetterPair[] indexProps = meta.getIndexProperties(); for (GetterPair indexProp : indexProps) { Object value = indexProp.getGetter().get(theEvent); writeDelimitedIndentedProp(buf, delimiter, level, indexProp.getName()); if (value == null) { buf.append("null"); } else { if (!value.getClass().isArray()) { buf.append("[]"); } else { buf.append('['); String arrayDelimiter = ""; if (rendererOptions.getRenderer() == null) { for (int i = 0; i < Array.getLength(value); i++) { Object arrayItem = Array.get(value, i); buf.append(arrayDelimiter); indexProp.getOutput().render(arrayItem, buf); arrayDelimiter = ", "; } } else { EventPropertyRendererContext context = rendererOptions.getRendererContext(); context.setStringBuilderAndReset(buf); for (int i = 0; i < Array.getLength(value); i++) { Object arrayItem = Array.get(value, i); buf.append(arrayDelimiter); context.setPropertyName(indexProp.getName()); context.setPropertyValue(arrayItem); context.setIndexedPropertyIndex(i); context.setDefaultRenderer(indexProp.getOutput()); rendererOptions.getRenderer().render(context); arrayDelimiter = ", "; } } buf.append(']'); } } delimiter = COMMA_DELIMITER_NEWLINE; } GetterPair[] mappedProps = meta.getMappedProperties(); for (GetterPair mappedProp : mappedProps) { Object value = mappedProp.getGetter().get(theEvent); if ((value != null) && (!(value instanceof Map))) { log.warn("Property '" + mappedProp.getName() + "' expected to return Map and returned " + value.getClass() + " instead"); continue; } writeDelimitedIndentedProp(buf, delimiter, level, mappedProp.getName()); if (value == null) { buf.append("null"); buf.append(NEWLINE); } else { Map<String, Object> map = (Map<String, Object>) value; if (map.isEmpty()) { buf.append("{}"); buf.append(NEWLINE); } else { buf.append('{'); buf.append(NEWLINE); String localDelimiter = ""; Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator(); for (; it.hasNext(); ) { Map.Entry<String, Object> entry = it.next(); if (entry.getKey() == null) { continue; } buf.append(localDelimiter); ident(buf, level + 1); buf.append('\"'); buf.append(entry.getKey()); buf.append("\": "); if (entry.getValue() == null) { buf.append("null"); } else { OutputValueRenderer outRenderer = OutputValueRendererFactory.getOutputValueRenderer(entry.getValue().getClass(), rendererOptions); if (rendererOptions.getRenderer() == null) { outRenderer.render(entry.getValue(), buf); } else { EventPropertyRendererContext context = rendererOptions.getRendererContext(); context.setStringBuilderAndReset(buf); context.setPropertyName(mappedProp.getName()); context.setPropertyValue(entry.getValue()); context.setMappedPropertyKey(entry.getKey()); context.setDefaultRenderer(outRenderer); rendererOptions.getRenderer().render(context); } } localDelimiter = COMMA_DELIMITER_NEWLINE; } buf.append(NEWLINE); ident(buf, level); buf.append('}'); } } delimiter = COMMA_DELIMITER_NEWLINE; } NestedGetterPair[] nestedProps = meta.getNestedProperties(); for (NestedGetterPair nestedProp : nestedProps) { Object value = nestedProp.getGetter().getFragment(theEvent); writeDelimitedIndentedProp(buf, delimiter, level, nestedProp.getName()); if (value == null) { buf.append("null"); } else if (!nestedProp.isArray()) { if (!(value instanceof EventBean)) { log.warn("Property '" + nestedProp.getName() + "' expected to return EventBean and returned " + value.getClass() + " instead"); buf.append("null"); continue; } EventBean nestedEventBean = (EventBean) value; buf.append('{'); buf.append(NEWLINE); recursiveRender(nestedEventBean, buf, level + 1, nestedProp.getMetadata(), rendererOptions); ident(buf, level); buf.append('}'); } else { if (!(value instanceof EventBean[])) { log.warn("Property '" + nestedProp.getName() + "' expected to return EventBean[] and returned " + value.getClass() + " instead"); buf.append("null"); continue; } StringBuilder arrayDelimiterBuf = new StringBuilder(); arrayDelimiterBuf.append(','); arrayDelimiterBuf.append(NEWLINE); ident(arrayDelimiterBuf, level + 1); EventBean[] nestedEventArray = (EventBean[]) value; String arrayDelimiter = ""; buf.append('['); for (int i = 0; i < nestedEventArray.length; i++) { EventBean arrayItem = nestedEventArray[i]; buf.append(arrayDelimiter); arrayDelimiter = arrayDelimiterBuf.toString(); buf.append('{'); buf.append(NEWLINE); recursiveRender(arrayItem, buf, level + 2, nestedProp.getMetadata(), rendererOptions); ident(buf, level + 1); buf.append('}'); } buf.append(']'); } delimiter = COMMA_DELIMITER_NEWLINE; } buf.append(NEWLINE); } private static void writeDelimitedIndentedProp(StringBuilder buf, String delimiter, int level, String name) { buf.append(delimiter); ident(buf, level); buf.append('\"'); buf.append(name); buf.append("\": "); } }