/* * ************************************************************************************* * 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.epl.parse; import com.espertech.esper.collection.Pair; import com.espertech.esper.epl.generated.EsperEPL2Ast; import org.antlr.runtime.tree.Tree; import java.io.ByteArrayOutputStream; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * Walker to annotation stuctures. */ public class ASTJsonHelper { /** * Walk an annotation root name or child node (nested annotations). * @param node annotation walk node * @return annotation descriptor * @throws com.espertech.esper.epl.parse.ASTWalkException if the walk failed */ public static Object walk(Tree node) throws ASTWalkException { if (node.getType() == EsperEPL2Ast.JSON_OBJECT) { return walkObject(node); } if (node.getType() == EsperEPL2Ast.JSON_ARRAY) { return walkArray(node); } if (node.getType() == EsperEPL2Ast.STRING_TYPE) { return extractString(node.getText()); } return ASTConstantHelper.parse(node); } private static String extractString(String text) { StringBuffer sb = new StringBuffer(text); int startPoint = 1; for (;;) { int slashIndex = sb.indexOf("\\", startPoint); if (slashIndex == -1) { break; } char escapeType = sb.charAt(slashIndex + 1); switch (escapeType) { case'u': String unicode = extractUnicode(sb, slashIndex); sb.replace(slashIndex, slashIndex + 6, unicode); // backspace break; // back to the loop // note: Java's character escapes match JSON's, which is why it looks like we're replacing // "\b" with "\b". We're actually replacing 2 characters (slash-b) with one (backspace). case 'b': sb.replace(slashIndex, slashIndex + 2, "\b"); break; case 't': sb.replace(slashIndex, slashIndex + 2, "\t"); break; case 'n': sb.replace(slashIndex, slashIndex + 2, "\n"); break; case 'f': sb.replace(slashIndex, slashIndex + 2, "\f"); break; case 'r': sb.replace(slashIndex, slashIndex + 2, "\r"); break; case '\'': sb.replace(slashIndex, slashIndex + 2, "\'"); break; case '\"': sb.replace(slashIndex, slashIndex + 2, "\""); break; case '\\': sb.replace(slashIndex, slashIndex + 2, "\\"); break; case '/': sb.replace(slashIndex, slashIndex + 2, "/"); break; default: break; } startPoint = slashIndex+1; } sb.deleteCharAt(0); sb.deleteCharAt(sb.length() - 1); return sb.toString(); } private static String extractUnicode(StringBuffer sb, int slashIndex) { String result; String code = sb.substring(slashIndex + 2, slashIndex + 6); int charNum = Integer.parseInt(code, 16); // hex to integer try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); OutputStreamWriter osw = new OutputStreamWriter(baos, "UTF-8"); osw.write(charNum); osw.flush(); result = baos.toString("UTF-8"); // Thanks to Silvester Pozarnik for the tip about adding "UTF-8" here } catch (Exception e) { throw new ASTWalkException("Failed to obtain for unicode '" + charNum + "'"); } return result; } private static Map<String, Object> walkObject(Tree node) { Map<String, Object> map = new LinkedHashMap<String, Object>(); for (int i = 0; i < node.getChildCount(); i++) { Tree child = node.getChild(i); if (child.getType() != EsperEPL2Ast.JSON_FIELD) { throw new IllegalStateException("Unexpected node type " + child.getType() + " at text " + child.getText()); } Pair<String, Object> value = walkJSONField(child); map.put(value.getFirst(), value.getSecond()); } return map; } private static List<Object> walkArray(Tree node) { List<Object> list = new ArrayList<Object>(); for (int i = 0; i < node.getChildCount(); i++) { Object value = walk(node.getChild(i)); list.add(value); } return list; } private static Pair<String, Object> walkJSONField(Tree node) { String name; if (node.getChild(0).getType() == EsperEPL2Ast.STRING_TYPE || node.getChild(0).getType() == EsperEPL2Ast.STRING_LITERAL || node.getChild(0).getType() == EsperEPL2Ast.QUOTED_STRING_LITERAL) { name = extractString(node.getChild(0).getText()); } else { name = node.getChild(0).getText(); } Object value = walk(node.getChild(1)); return new Pair<String, Object>(name, value); } }