/* * ************************************************************************************* * Copyright (C) 2008 EsperTech, Inc. All rights reserved. * * http://esper.codehaus.org * * 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.XMLEventRenderer; import com.espertech.esper.client.util.XMLRenderingOptions; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.lang.reflect.Array; import java.util.Iterator; import java.util.Map; import java.util.Stack; /** * Renderer for XML-formatted properties. */ public class XMLRendererImpl implements XMLEventRenderer { private static final Log log = LogFactory.getLog(XMLRendererImpl.class); private final static String NEWLINE = System.getProperty("line.separator"); private final RendererMeta meta; private final XMLRenderingOptions options; private final RendererMetaOptions rendererMetaOptions; /** * Ctor. * @param eventType type of event to render * @param options rendering options */ public XMLRendererImpl(EventType eventType, XMLRenderingOptions options) { EventPropertyRenderer propertyRenderer = null; EventPropertyRendererContext propertyRendererContext = null; if (options.getRenderer() != null) { propertyRenderer = options.getRenderer(); propertyRendererContext = new EventPropertyRendererContext(eventType, false); } rendererMetaOptions = new RendererMetaOptions(options.isPreventLooping(), true, propertyRenderer, propertyRendererContext); meta = new RendererMeta(eventType, new Stack<EventTypePropertyPair>(), rendererMetaOptions); this.options = options; } public String render(String rootElementName, EventBean theEvent) { if (options.isDefaultAsAttribute()) { return renderAttributeXML(rootElementName, theEvent); } return renderElementXML(rootElementName, theEvent); } private String renderElementXML(String rootElementName, EventBean theEvent) { StringBuilder buf = new StringBuilder(); buf.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); buf.append(NEWLINE); buf.append('<'); buf.append(rootElementName); buf.append('>'); buf.append(NEWLINE); recursiveRender(theEvent, buf, 1, meta, rendererMetaOptions); buf.append("</"); buf.append(getFirstWord(rootElementName)); buf.append('>'); return buf.toString(); } private String renderAttributeXML(String rootElementName, EventBean theEvent) { StringBuilder buf = new StringBuilder(); buf.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); buf.append(NEWLINE); buf.append('<'); buf.append(rootElementName); renderAttributes(theEvent, buf, meta); String inner = renderAttElements(theEvent, 1, meta); if ((inner == null) || (inner.trim().length() == 0)) { buf.append("/>"); buf.append(NEWLINE); } else { buf.append(">"); buf.append(NEWLINE); buf.append(inner); buf.append("</"); buf.append(getFirstWord(rootElementName)); buf.append('>'); } return buf.toString(); } private String renderAttElements(EventBean theEvent, int level, RendererMeta meta) { StringBuilder buf = new StringBuilder(); GetterPair[] indexProps = meta.getIndexProperties(); for (GetterPair indexProp : indexProps) { Object value = indexProp.getGetter().get(theEvent); if (value == null) { continue; } if (!value.getClass().isArray()) { log.warn("Property '" + indexProp.getName() + "' returned a non-array object"); continue; } for (int i = 0; i < Array.getLength(value); i++) { Object arrayItem = Array.get(value, i); if (arrayItem == null) { continue; } ident(buf, level); buf.append('<'); buf.append(indexProp.getName()); buf.append('>'); if (rendererMetaOptions.getRenderer() == null) { indexProp.getOutput().render(arrayItem, buf); } else { EventPropertyRendererContext context = rendererMetaOptions.getRendererContext(); context.setStringBuilderAndReset(buf); context.setPropertyName(indexProp.getName()); context.setPropertyValue(arrayItem); context.setIndexedPropertyIndex(i); context.setDefaultRenderer(indexProp.getOutput()); rendererMetaOptions.getRenderer().render(context); } buf.append("</"); buf.append(indexProp.getName()); buf.append('>'); buf.append(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; } ident(buf, level); buf.append('<'); buf.append(mappedProp.getName()); if (value != null) { Map<String, Object> map = (Map<String, Object>) value; if (!map.isEmpty()) { Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator(); for (;it.hasNext();) { Map.Entry<String, Object> entry = it.next(); if ((entry.getKey() == null) || (entry.getValue() == null)) { continue; } buf.append(" "); buf.append(entry.getKey()); buf.append("=\""); OutputValueRenderer outputValueRenderer = OutputValueRendererFactory.getOutputValueRenderer(entry.getValue().getClass(), rendererMetaOptions); if (rendererMetaOptions.getRenderer() == null) { outputValueRenderer.render(entry.getValue(), buf); } else { EventPropertyRendererContext context = rendererMetaOptions.getRendererContext(); context.setStringBuilderAndReset(buf); context.setPropertyName(mappedProp.getName()); context.setPropertyValue(entry.getValue()); context.setMappedPropertyKey(entry.getKey()); context.setDefaultRenderer(outputValueRenderer); rendererMetaOptions.getRenderer().render(context); } buf.append("\""); } } } buf.append("/>"); buf.append(NEWLINE); } NestedGetterPair[] nestedProps = meta.getNestedProperties(); for (NestedGetterPair nestedProp : nestedProps) { Object value = nestedProp.getGetter().getFragment(theEvent); if (value == null) { continue; } 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; renderAttInner(buf, level, nestedEventBean, nestedProp); } else { if (!(value instanceof EventBean[])) { log.warn("Property '" + nestedProp.getName() + "' expected to return EventBean[] and returned " + value.getClass() + " instead"); buf.append("null"); continue; } EventBean[] nestedEventArray = (EventBean[]) value; for (int i = 0; i < nestedEventArray.length; i++) { EventBean arrayItem = nestedEventArray[i]; renderAttInner(buf, level, arrayItem, nestedProp); } } } return buf.toString(); } private void renderAttributes(EventBean theEvent, StringBuilder buf, RendererMeta meta) { String delimiter = " "; GetterPair[] simpleProps = meta.getSimpleProperties(); for (GetterPair simpleProp : simpleProps) { Object value = simpleProp.getGetter().get(theEvent); if (value == null) { continue; } buf.append(delimiter); buf.append(simpleProp.getName()); buf.append("=\""); if (rendererMetaOptions.getRenderer() == null) { simpleProp.getOutput().render(value, buf); } else { EventPropertyRendererContext context = rendererMetaOptions.getRendererContext(); context.setStringBuilderAndReset(buf); context.setPropertyName(simpleProp.getName()); context.setPropertyValue(value); context.setDefaultRenderer(simpleProp.getOutput()); rendererMetaOptions.getRenderer().render(context); } buf.append('"'); } } 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 rendererMetaOptions) { GetterPair[] simpleProps = meta.getSimpleProperties(); for (GetterPair simpleProp : simpleProps) { Object value = simpleProp.getGetter().get(theEvent); if (value == null) { continue; } ident(buf, level); buf.append('<'); buf.append(simpleProp.getName()); buf.append('>'); if (rendererMetaOptions.getRenderer() == null) { simpleProp.getOutput().render(value, buf); } else { EventPropertyRendererContext context = rendererMetaOptions.getRendererContext(); context.setStringBuilderAndReset(buf); context.setPropertyName(simpleProp.getName()); context.setPropertyValue(value); context.setDefaultRenderer(simpleProp.getOutput()); rendererMetaOptions.getRenderer().render(context); } buf.append("</"); buf.append(simpleProp.getName()); buf.append('>'); buf.append(NEWLINE); } GetterPair[] indexProps = meta.getIndexProperties(); for (GetterPair indexProp : indexProps) { Object value = indexProp.getGetter().get(theEvent); if (value == null) { continue; } if (!value.getClass().isArray()) { log.warn("Property '" + indexProp.getName() + "' returned a non-array object"); continue; } for (int i = 0; i < Array.getLength(value); i++) { Object arrayItem = Array.get(value, i); if (arrayItem == null) { continue; } ident(buf, level); buf.append('<'); buf.append(indexProp.getName()); buf.append('>'); if (rendererMetaOptions.getRenderer() == null) { indexProp.getOutput().render(arrayItem, buf); } else { EventPropertyRendererContext context = rendererMetaOptions.getRendererContext(); context.setStringBuilderAndReset(buf); context.setPropertyName(indexProp.getName()); context.setPropertyValue(arrayItem); context.setIndexedPropertyIndex(i); context.setDefaultRenderer(indexProp.getOutput()); rendererMetaOptions.getRenderer().render(context); } buf.append("</"); buf.append(indexProp.getName()); buf.append('>'); buf.append(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; } ident(buf, level); buf.append('<'); buf.append(mappedProp.getName()); buf.append('>'); buf.append(NEWLINE); if (value != null) { Map<String, Object> map = (Map<String, Object>) value; if (!map.isEmpty()) { 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) { OutputValueRenderer outputValueRenderer = OutputValueRendererFactory.getOutputValueRenderer(entry.getValue().getClass(), rendererMetaOptions); if (rendererMetaOptions.getRenderer() == null) { outputValueRenderer.render(entry.getValue(), buf); } else { EventPropertyRendererContext context = rendererMetaOptions.getRendererContext(); context.setStringBuilderAndReset(buf); context.setPropertyName(mappedProp.getName()); context.setPropertyValue(entry.getValue()); context.setMappedPropertyKey(entry.getKey()); context.setDefaultRenderer(outputValueRenderer); rendererMetaOptions.getRenderer().render(context); } } buf.append('<'); buf.append(entry.getKey()); buf.append('>'); localDelimiter = NEWLINE; } } } buf.append(NEWLINE); ident(buf, level); buf.append("</"); buf.append(mappedProp.getName()); buf.append('>'); buf.append(NEWLINE); } NestedGetterPair[] nestedProps = meta.getNestedProperties(); for (NestedGetterPair nestedProp : nestedProps) { Object value = nestedProp.getGetter().getFragment(theEvent); if (value == null) { continue; } 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; } renderElementFragment((EventBean) value, buf, level, nestedProp, rendererMetaOptions); } else { if (!(value instanceof EventBean[])) { log.warn("Property '" + nestedProp.getName() + "' expected to return EventBean[] and returned " + value.getClass() + " instead"); buf.append("null"); continue; } EventBean[] nestedEventArray = (EventBean[]) value; for (int i = 0; i < nestedEventArray.length; i++) { EventBean arrayItem = nestedEventArray[i]; if (arrayItem == null) { continue; } renderElementFragment(arrayItem, buf, level, nestedProp, rendererMetaOptions); } } } } private static void renderElementFragment(EventBean eventBean, StringBuilder buf, int level, NestedGetterPair nestedProp, RendererMetaOptions rendererMetaOptions) { ident(buf, level); buf.append('<'); buf.append(nestedProp.getName()); buf.append('>'); buf.append(NEWLINE); recursiveRender(eventBean, buf, level + 1, nestedProp.getMetadata(), rendererMetaOptions); ident(buf, level); buf.append("</"); buf.append(nestedProp.getName()); buf.append('>'); buf.append(NEWLINE); } private void renderAttInner(StringBuilder buf, int level, EventBean nestedEventBean, NestedGetterPair nestedProp) { ident(buf, level); buf.append('<'); buf.append(nestedProp.getName()); renderAttributes(nestedEventBean, buf, nestedProp.getMetadata()); String inner = renderAttElements(nestedEventBean, level + 1, nestedProp.getMetadata()); if ((inner == null) || (inner.trim().length() == 0)) { buf.append("/>"); buf.append(NEWLINE); } else { buf.append(">"); buf.append(NEWLINE); buf.append(inner); ident(buf, level); buf.append("</"); buf.append(nestedProp.getName()); buf.append('>'); buf.append(NEWLINE); } } private String getFirstWord(String rootElementName) { if ((rootElementName == null) || (rootElementName.trim().length() == 0)) { return rootElementName; } int index = rootElementName.indexOf(' '); if (index < 0) { return rootElementName; } return rootElementName.substring(0, index); } }