Java tutorial
/* * Copyright 2009-2013 by The Regents of the University of California * Licensed 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 from * * 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 edu.uci.ics.asterix.result; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringWriter; import java.nio.charset.Charset; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.http.ParseException; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import edu.uci.ics.asterix.api.common.SessionConfig; import edu.uci.ics.asterix.api.common.SessionConfig.OutputFormat; import edu.uci.ics.asterix.api.http.servlet.APIServlet; import edu.uci.ics.asterix.om.types.ARecordType; import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException; import edu.uci.ics.hyracks.api.comm.IFrame; import edu.uci.ics.hyracks.api.comm.IFrameTupleAccessor; import edu.uci.ics.hyracks.api.comm.VSizeFrame; import edu.uci.ics.hyracks.api.exceptions.HyracksDataException; import edu.uci.ics.hyracks.control.nc.resources.memory.FrameManager; import edu.uci.ics.hyracks.dataflow.common.comm.util.ByteBufferInputStream; public class ResultUtils { private static final Charset UTF_8 = Charset.forName("UTF-8"); static Map<Character, String> HTML_ENTITIES = new HashMap<Character, String>(); static { HTML_ENTITIES.put('"', """); HTML_ENTITIES.put('&', "&"); HTML_ENTITIES.put('<', "<"); HTML_ENTITIES.put('>', ">"); } public static String escapeHTML(String s) { for (Character c : HTML_ENTITIES.keySet()) { if (s.indexOf(c) >= 0) { s = s.replace(c.toString(), HTML_ENTITIES.get(c)); } } return s; } public static void displayCSVHeader(ARecordType recordType, SessionConfig conf) { // If HTML-ifying, we have to output this here before the header - // pretty ugly if (conf.is(SessionConfig.FORMAT_HTML)) { conf.out().println("<h4>Results:</h4>"); conf.out().println("<pre>"); } String[] fieldNames = recordType.getFieldNames(); boolean notfirst = false; for (String name : fieldNames) { if (notfirst) { conf.out().print(','); } notfirst = true; conf.out().print('"'); conf.out().print(name.replace("\"", "\"\"")); conf.out().print('"'); } conf.out().print("\r\n"); } public static FrameManager resultDisplayFrameMgr = new FrameManager(ResultReader.FRAME_SIZE); public static void displayResults(ResultReader resultReader, SessionConfig conf) throws HyracksDataException { IFrameTupleAccessor fta = resultReader.getFrameTupleAccessor(); IFrame frame = new VSizeFrame(resultDisplayFrameMgr); int bytesRead = resultReader.read(frame); ByteBufferInputStream bbis = new ByteBufferInputStream(); // Whether we need to separate top-level ADM instances with commas boolean need_commas = true; // Whether this is the first instance being output boolean notfirst = false; // If we're outputting CSV with a header, the HTML header was already // output by displayCSVHeader(), so skip it here if (conf.is(SessionConfig.FORMAT_HTML) && !(conf.fmt() == OutputFormat.CSV && conf.is(SessionConfig.FORMAT_CSV_HEADER))) { conf.out().println("<h4>Results:</h4>"); conf.out().println("<pre>"); } switch (conf.fmt()) { case CSV: need_commas = false; break; case JSON: case ADM: // Conveniently, JSON and ADM have the same syntax for an // "ordered list", and our representation of the result of a // statement is an ordered list of instances. conf.out().print("[ "); break; } if (bytesRead > 0) { do { try { fta.reset(frame.getBuffer()); int last = fta.getTupleCount(); String result; for (int tIndex = 0; tIndex < last; tIndex++) { int start = fta.getTupleStartOffset(tIndex); int length = fta.getTupleEndOffset(tIndex) - start; bbis.setByteBuffer(frame.getBuffer(), start); byte[] recordBytes = new byte[length]; int numread = bbis.read(recordBytes, 0, length); if (conf.fmt() == OutputFormat.CSV) { if ((numread > 0) && (recordBytes[numread - 1] == '\n')) { numread--; } } result = new String(recordBytes, 0, numread, UTF_8); if (need_commas && notfirst) { conf.out().print(", "); } notfirst = true; conf.out().print(result); if (conf.fmt() == OutputFormat.CSV) { conf.out().print("\r\n"); } } frame.getBuffer().clear(); } finally { try { bbis.close(); } catch (IOException e) { throw new HyracksDataException(e); } } } while (resultReader.read(frame) > 0); } conf.out().flush(); switch (conf.fmt()) { case JSON: case ADM: conf.out().println(" ]"); break; case CSV: // Nothing to do break; } if (conf.is(SessionConfig.FORMAT_HTML)) { conf.out().println("</pre>"); } } public static JSONObject getErrorResponse(int errorCode, String errorMessage, String errorSummary, String errorStackTrace) { JSONObject errorResp = new JSONObject(); JSONArray errorArray = new JSONArray(); errorArray.put(errorCode); errorArray.put(errorMessage); try { errorResp.put("error-code", errorArray); if (!errorSummary.equals("")) errorResp.put("summary", errorSummary); if (!errorStackTrace.equals("")) errorResp.put("stacktrace", errorStackTrace); } catch (JSONException e) { // TODO(madhusudancs): Figure out what to do when JSONException occurs while building the results. } return errorResp; } public static void webUIErrorHandler(PrintWriter out, Exception e) { String errorTemplate = readTemplateFile("/webui/errortemplate.html", "%s\n%s\n%s"); String errorOutput = String.format(errorTemplate, escapeHTML(extractErrorMessage(e)), escapeHTML(extractErrorSummary(e)), escapeHTML(extractFullStackTrace(e))); out.println(errorOutput); } public static void webUIParseExceptionHandler(PrintWriter out, Throwable e, String query) { String errorTemplate = readTemplateFile("/webui/errortemplate_message.html", "<pre class=\"error\">%s\n</pre>"); String errorOutput = String.format(errorTemplate, buildParseExceptionMessage(e, query)); out.println(errorOutput); } public static void apiErrorHandler(PrintWriter out, Exception e) { int errorCode = 99; if (e instanceof ParseException) { errorCode = 2; } else if (e instanceof AlgebricksException) { errorCode = 3; } else if (e instanceof HyracksDataException) { errorCode = 4; } JSONObject errorResp = ResultUtils.getErrorResponse(errorCode, extractErrorMessage(e), extractErrorSummary(e), extractFullStackTrace(e)); out.write(errorResp.toString()); } public static String buildParseExceptionMessage(Throwable e, String query) { StringBuilder errorMessage = new StringBuilder(); String message = e.getMessage(); message = message.replace("<", "<"); message = message.replace(">", ">"); errorMessage.append("SyntaxError: " + message + "\n"); int pos = message.indexOf("line"); if (pos > 0) { Pattern p = Pattern.compile("\\d+"); Matcher m = p.matcher(message); if (m.find(pos)) { int lineNo = Integer.parseInt(message.substring(m.start(), m.end())); String[] lines = query.split("\n"); if (lineNo > lines.length) { errorMessage.append("===> <BLANK LINE> \n"); } else { String line = lines[lineNo - 1]; errorMessage.append("==> " + line); } } } return errorMessage.toString(); } private static Throwable getRootCause(Throwable cause) { Throwable nextCause = cause.getCause(); while (nextCause != null) { cause = nextCause; nextCause = cause.getCause(); } return cause; } /** * Extract the message in the root cause of the stack trace: * * @param e * @return error message string. */ private static String extractErrorMessage(Throwable e) { Throwable cause = getRootCause(e); String fullyQualifiedExceptionClassName = cause.getClass().getName(); String[] hierarchySplits = fullyQualifiedExceptionClassName.split("\\."); //try returning the class without package qualification String exceptionClassName = hierarchySplits[hierarchySplits.length - 1]; String localizedMessage = cause.getLocalizedMessage(); if (localizedMessage == null) { localizedMessage = "Internal error. Please check instance logs for further details."; } return localizedMessage + " [" + exceptionClassName + "]"; } /** * Extract the meaningful part of a stack trace: * a. the causes in the stack trace hierarchy * b. the top exception for each cause * * @param e * @return the contacted message containing a and b. */ private static String extractErrorSummary(Throwable e) { StringBuilder errorMessageBuilder = new StringBuilder(); Throwable cause = e; errorMessageBuilder.append(cause.getLocalizedMessage()); while (cause != null) { StackTraceElement[] stackTraceElements = cause.getStackTrace(); errorMessageBuilder .append(stackTraceElements.length > 0 ? "\n caused by: " + stackTraceElements[0] : ""); cause = cause.getCause(); } return errorMessageBuilder.toString(); } /** * Extract the full stack trace: * * @param e * @return the string containing the full stack trace of the error. */ private static String extractFullStackTrace(Throwable e) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); e.printStackTrace(printWriter); return stringWriter.toString(); } /** * Read the template file which is stored as a resource and return its content. If the file does not exist or is * not readable return the default template string. * * @param path * The path to the resource template file * @param defaultTemplate * The default template string if the template file does not exist or is not readable * @return The template string to be used to render the output. */ private static String readTemplateFile(String path, String defaultTemplate) { String errorTemplate = defaultTemplate; try { String resourcePath = "/webui/errortemplate_message.html"; InputStream is = APIServlet.class.getResourceAsStream(resourcePath); InputStreamReader isr = new InputStreamReader(is); StringBuilder sb = new StringBuilder(); BufferedReader br = new BufferedReader(isr); String line = br.readLine(); while (line != null) { sb.append(line); line = br.readLine(); } errorTemplate = sb.toString(); } catch (IOException ioe) { // If there is an IOException reading the error template html file, default value of error template is used. } return errorTemplate; } }