/* * Copyright (c) 2010, SQL Power Group Inc. * * This file is part of Power*Architect. * * Power*Architect is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Power*Architect is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package ca.sqlpower.enterprise; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import org.apache.http.HttpResponse; import org.apache.http.client.ResponseHandler; import org.apache.log4j.Logger; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONTokener; import org.springframework.security.AccessDeniedException; import ca.sqlpower.dao.FriendlyRuntimeSPPersistenceException; import ca.sqlpower.dao.FriendlySPPersistenceException; import ca.sqlpower.dao.SPPersistenceException; public class JSONResponseHandler implements ResponseHandler<JSONMessage> { private static final Logger logger = Logger.getLogger(JSONResponseHandler.class); /* * Unsuccessful responses should have information sent in a header, * either as "unsuccessfulResponse" or "exceptionStackTrace" */ public JSONMessage handleResponse(HttpResponse response) { try { int status = response.getStatusLine().getStatusCode(); if (status == 401) { throw new AccessDeniedException("Access Denied"); } BufferedReader reader = new BufferedReader( new InputStreamReader(response.getEntity().getContent())); return handleResponse(reader, status); } catch (AccessDeniedException e) { throw e; } catch (RuntimeException ex) { throw ex; } catch (Exception ex) { throw new RuntimeException(ex); } } public JSONMessage handleResponse(String json, int status) { return handleResponse(new StringReader(json), status); } public JSONMessage handleResponse(Reader reader, int status) { if (status == 404) { throw new RuntimeException("Server resource is not available."); } if (status == 403) { throw new AccessDeniedException("Insufficient priviledges"); } JSONTokener tokener = new JSONTokener(reader); try { JSONObject message; try { message = (JSONObject) tokener.nextValue(); } catch (ClassCastException ex) { StringBuffer sb = new StringBuffer(); sb.append("Internal server error. Server responded with the following.\n"); try { int charAsInt = reader.read(); while (charAsInt != -1) { sb.append((char) charAsInt); charAsInt = reader.read(); } logger.error(sb.toString()); } catch (IOException e) { logger.error("Failed to parse the root exception. The following was received " + sb.toString()); } throw new RuntimeException("Server error " + status + ". See logs or server logs for more details."); } // Does the response contain data? If so, return it. Communication // with the resource has been successful. if (message.getString("responseKind").equals("data")) { return new JSONMessage(message.getString("data"), status); } else { // Has the request been unsuccessful? if (message.getString("responseKind").equals("unsuccessful")) { return new JSONMessage(message.getString("data"), status); } else { // Does the response contain an exception? If so, reconstruct, and then // re-throw it. There has been an exception on the server. if (message.getString("responseKind").equals("exceptionStackTrace")) { JSONArray stackTraceStrings = new JSONArray(message.getString("data")); StringBuffer stackTraceMessage = new StringBuffer(); if (stackTraceStrings.length() > 0) { String firstLine = stackTraceStrings.getString(0); String userMessage = null; if (firstLine.contains(FriendlyRuntimeSPPersistenceException.class.getName())) { userMessage = firstLine.substring(firstLine.indexOf(FriendlyRuntimeSPPersistenceException.class.getName()) + FriendlyRuntimeSPPersistenceException.class.getName().length() + 2); } else if (firstLine.contains(FriendlySPPersistenceException.class.getName())) { userMessage = firstLine.substring(firstLine.indexOf(FriendlySPPersistenceException.class.getName()) + FriendlySPPersistenceException.class.getName().length() + 2); } if (userMessage != null) { for (int i = 0; i < stackTraceStrings.length(); i++) { stackTraceMessage.append("\n").append(stackTraceStrings.get(i)); } logger.info(stackTraceMessage.toString()); throw new FriendlyRuntimeSPPersistenceException(userMessage); } } for (int i = 0; i < stackTraceStrings.length(); i++) { stackTraceMessage.append("\n").append(stackTraceStrings.get(i)); } throw new SPPersistenceException(null, stackTraceMessage.toString()); } else { // This exception represents a(n epic) client-server miscommunication throw new Exception("Unable to parse response "); } } } } catch (JSONException ex) { StringBuffer sb = new StringBuffer(); sb.append("Internal server error. Server responded with the following.\n"); try { int charAsInt = reader.read(); while (charAsInt != -1) { sb.append(charAsInt); charAsInt = reader.read(); } logger.error(sb.toString()); } catch (IOException e) { logger.error("Failed to parse the root exception. The following was received " + sb.toString()); } throw new RuntimeException("Server error. See logs or server logs for more details."); } catch (RuntimeException ex) { throw ex; } catch (Exception ex) { String message = ex.getMessage(); if (message.contains("\n")) { String[] messages = message.split("\n"); for (String serverMsg : messages) { if (serverMsg.trim().length() > 0) { message = serverMsg.trim(); break; } } } throw new RuntimeException("Server returned status " + status + "\n" + message, ex); } } }