| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 at |
| * |
| * 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 org.apache.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.asterix.api.common.SessionConfig; |
| import org.apache.asterix.api.http.servlet.APIServlet; |
| import org.apache.asterix.om.types.ARecordType; |
| import org.apache.http.ParseException; |
| import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; |
| import org.apache.hyracks.api.exceptions.HyracksDataException; |
| import org.json.JSONArray; |
| import org.json.JSONException; |
| import org.json.JSONObject; |
| |
| public class ResultUtils { |
| 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 class Stats { |
| public long count; |
| public long size; |
| } |
| |
| 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 displayResults(ResultReader resultReader, SessionConfig conf, Stats stats, |
| ARecordType recordType) throws HyracksDataException { |
| new ResultPrinter(conf, stats, recordType).print(resultReader); |
| } |
| |
| public static void displayResults(String record, SessionConfig conf, Stats stats, ARecordType recordType) |
| throws HyracksDataException { |
| new ResultPrinter(conf, stats, recordType).print(record); |
| } |
| |
| 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 (!"".equals(errorSummary)) { |
| errorResp.put("summary", errorSummary); |
| } else { |
| //parse exception |
| errorResp.put("summary", errorMessage); |
| } |
| 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("Error: " + 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. |
| */ |
| public 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; |
| } |
| } |