org.dataone.proto.trove.mn.http.client.HttpExceptionHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.dataone.proto.trove.mn.http.client.HttpExceptionHandler.java

Source

/*
 * This work was created by participants in the DataONE project, and is
 * jointly copyrighted by participating institutions in DataONE. For
 * more information on DataONE, see our web site at http://dataone.org.
 * 
 * Copyright 2014
 * 
 * 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 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.dataone.proto.trove.mn.http.client;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.StringWriter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpException;
import org.apache.http.HttpResponse;
import org.dataone.proto.trove.net.ErrorElements;
import org.dataone.service.exceptions.AuthenticationTimeout;
import org.dataone.service.exceptions.IdentifierNotUnique;
import org.dataone.service.exceptions.InsufficientResources;
import org.dataone.service.exceptions.InvalidCredentials;
import org.dataone.service.exceptions.InvalidRequest;
import org.dataone.service.exceptions.InvalidSystemMetadata;
import org.dataone.service.exceptions.InvalidToken;
import org.dataone.service.exceptions.NotAuthorized;
import org.dataone.service.exceptions.NotFound;
import org.dataone.service.exceptions.NotImplemented;
import org.dataone.service.exceptions.ServiceFailure;
import org.dataone.service.exceptions.UnsupportedMetadataType;
import org.dataone.service.exceptions.UnsupportedType;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

/**
 * Really good code.
 *
 * @author rnafh
 */
public class HttpExceptionHandler {

    /**
     *
     * @param response
     * @throws NotFound
     * @throws InvalidToken
     * @throws ServiceFailure
     * @throws NotAuthorized
     * @throws NotFound
     * @throws IdentifierNotUnique
     * @throws UnsupportedType
     * @throws InsufficientResources
     * @throws InvalidSystemMetadata
     * @throws NotImplemented
     * @throws InvalidCredentials
     * @throws InvalidRequest
     * @throws IOException
     * @throws AuthenticationTimeout
     * @throws UnsupportedMetadataType
     * @throws HttpException
     */
    public static void deserializeAndThrowException(HttpResponse response)
            throws NotFound, InvalidToken, ServiceFailure, NotAuthorized, NotFound, IdentifierNotUnique,
            UnsupportedType, InsufficientResources, InvalidSystemMetadata, NotImplemented, InvalidCredentials,
            InvalidRequest, IOException, AuthenticationTimeout, UnsupportedMetadataType, HttpException {

        // use content-type to determine what format the response is
        Header[] h = response.getHeaders("content-type");
        String contentType = null;
        if (h.length == 1) {
            contentType = h[0].getValue();
        } else {
            throw new IOException("Should not get more than one content-type returned");
        }

        ErrorElements ee = null;
        if (contentType.contains("xml")) {
            ee = deserializeXml(response);
        } else if (contentType.contains("html")) {
            ee = deserializeHtml(response);
        } else if (contentType.contains("json")) {
            ee = deserializeJson(response);
        } else if (contentType.contains("csv")) {
            ee = deserializeCsv(response);
        } else if (contentType.contains("text/plain")) {
            ee = deserializeTextPlain(response);
        } else // attempt the default...
        {
            ee = deserializeXml(response);
        }

        String exceptionName = ee.getName();
        if (exceptionName == null) {
            throw new HttpException(response.getStatusLine().getReasonPhrase() + ": " + ee.getDescription());
        }

        // last updated 27-Jan-2011
        if (ee.getName().equals("AuthenticationTimeout")) {
            throw new AuthenticationTimeout(ee.getDetailCode(), ee.getDescription());
        } else if (ee.getName().equals("IdentifierNotUnique")) {
            throw new IdentifierNotUnique(ee.getDetailCode(), ee.getDescription());
        } else if (ee.getName().equals("InsufficientResources")) {
            throw new InsufficientResources(ee.getDetailCode(), ee.getDescription());
        } else if (ee.getName().equals("InvalidCredentials")) {
            throw new InvalidCredentials(ee.getDetailCode(), ee.getDescription());
        } else if (ee.getName().equals("InvalidRequest")) {
            throw new InvalidRequest(ee.getDetailCode(), ee.getDescription());
        } else if (exceptionName.equals("InvalidSystemMetadata")) {
            throw new InvalidSystemMetadata("1180", ee.getDescription());
        } else if (ee.getName().equals("InvalidToken")) {
            throw new InvalidToken(ee.getDetailCode(), ee.getDescription());
        } else if (ee.getName().equals("NotAuthorized")) {
            throw new NotAuthorized(ee.getDetailCode(), ee.getDescription());
        } else if (ee.getName().equals("NotFound")) {
            throw new NotFound(ee.getDetailCode(), ee.getDescription());
        } else if (ee.getName().equals("NotImplemented")) {
            throw new NotImplemented(ee.getDetailCode(), ee.getDescription());
        } else if (ee.getName().equals("ServiceFailure")) {
            throw new ServiceFailure(ee.getDetailCode(), ee.getDescription());
        } else if (ee.getName().equals("UnsupportedMetadataType")) {
            throw new UnsupportedMetadataType(ee.getDetailCode(), ee.getDescription());
        } else if (ee.getName().equals("UnsupportedType")) {
            throw new UnsupportedType(ee.getDetailCode(), ee.getDescription());
        } else {
            throw new ServiceFailure(ee.getDetailCode(), ee.getDescription());
        }
    }

    private static ErrorElements deserializeHtml(HttpResponse response) throws IllegalStateException, IOException {
        ErrorElements ee = new ErrorElements();
        ee.setCode(response.getStatusLine().getStatusCode());
        //       ee.setDetailCode(detailCode);
        if (response.getEntity() != null) {
            String body = IOUtils.toString(response.getEntity().getContent());
            ee.setDescription("parser for deserializing HTML not written yet.  Providing message body:\n" + body);
        }
        return ee;
    }

    private static ErrorElements deserializeJson(HttpResponse response) throws IllegalStateException, IOException {
        ErrorElements ee = new ErrorElements();

        ee.setCode(response.getStatusLine().getStatusCode());
        //       ee.setDetailCode(detailCode);
        if (response.getEntity() != null) {
            String body = IOUtils.toString(response.getEntity().getContent());
            ee.setDescription("parser for deserializing JSON not written yet.  Providing message body:\n" + body);
        }
        return ee;
    }

    private static ErrorElements deserializeCsv(HttpResponse response) throws IllegalStateException, IOException {
        ErrorElements ee = new ErrorElements();
        ee.setCode(response.getStatusLine().getStatusCode());
        //       ee.setDetailCode(detailCode);
        if (response.getEntity() != null) {
            String body = IOUtils.toString(response.getEntity().getContent());
            ee.setDescription("parser for deserializing CSV not written yet.  Providing message body:\n" + body);
        }
        return ee;
    }

    private static ErrorElements deserializeTextPlain(HttpResponse response)
            throws IllegalStateException, IOException {
        ErrorElements ee = new ErrorElements();
        ee.setCode(response.getStatusLine().getStatusCode());
        //       ee.setDetailCode(detailCode);
        if (response.getEntity() != null) {
            String body = IOUtils.toString(response.getEntity().getContent());
            ee.setDescription("parser for deserializing CSV not written yet.  Providing message body:\n" + body);
        }
        return ee;
    }

    private static ErrorElements deserializeXml(HttpResponse response) throws IllegalStateException, IOException //    throws NotFound, InvalidToken, ServiceFailure, NotAuthorized,
    //    NotFound, IdentifierNotUnique, UnsupportedType,
    //    InsufficientResources, InvalidSystemMetadata, NotImplemented,
    //    InvalidCredentials, InvalidRequest, IOException {
    {
        ErrorElements ee = new ErrorElements();

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        Document doc;

        int httpCode = response.getStatusLine().getStatusCode();
        if (response.getEntity() != null) {
            BufferedInputStream bErrorStream = new BufferedInputStream(response.getEntity().getContent());
            bErrorStream.mark(5000); // good for resetting up to 5000 bytes

            String detailCode = null;
            String description = null;
            String name = null;
            int errorCode = -1;
            try {
                DocumentBuilder db = dbf.newDocumentBuilder();
                doc = db.parse(bErrorStream);
                Element root = doc.getDocumentElement();
                root.normalize();
                if (root.getNodeName().equalsIgnoreCase("error")) {
                    if (root.hasAttribute("errorCode")) {
                        try {
                            errorCode = Integer.getInteger(root.getAttribute("errorCode"));
                        } catch (NumberFormatException nfe) {
                            System.out.println("errorCode unexpectedly not able to parse to int,"
                                    + " using http status for creating exception");
                            errorCode = httpCode;
                        }
                    }
                    if (errorCode != httpCode) //            throw new ServiceFailure("1000","errorCode in message body doesn't match httpStatus");
                    {
                        System.out.println("errorCode in message body doesn't match httpStatus,"
                                + " using errorCode for creating exception");
                    }
                    if (root.hasAttribute("detailCode")) {
                        detailCode = root.getAttribute("detailCode");
                    } else {
                        detailCode = "detail code is Not Set!";
                    }
                    if (root.hasAttribute("name")) {
                        name = root.getAttribute("name");
                    } else {
                        name = "Exception";
                    }
                    Node child = root.getFirstChild();
                    do {
                        if (child.getNodeType() == Node.ELEMENT_NODE) {
                            if (child.getNodeName().equalsIgnoreCase("description")) {
                                Element element = (Element) child;
                                description = element.getTextContent();
                                break;
                            }
                        }
                    } while ((child = child.getNextSibling()) != null);
                } else {
                    description = domToString(doc);
                    detailCode = "detail code was never Set!";
                }
            } catch (TransformerException e) {
                description = deserializeNonXMLErrorStream(bErrorStream, e);
            } catch (SAXException e) {
                description = deserializeNonXMLErrorStream(bErrorStream, e);
            } catch (IOException e) {
                description = deserializeNonXMLErrorStream(bErrorStream, e);
            } catch (ParserConfigurationException e) {
                description = deserializeNonXMLErrorStream(bErrorStream, e);
            }

            ee.setCode(errorCode);
            ee.setName(name);
            ee.setDetailCode(detailCode);
            ee.setDescription(description);
        }
        return ee;
    }

    /*
     * helper method for deserializeAndThrowException.  Used for problems parsing errorStream as XML
     */
    private static String deserializeNonXMLErrorStream(BufferedInputStream errorStream, Exception e) {
        String errorString = null;
        try {
            errorStream.reset();
            errorString = e.getMessage() + "\n" + IOUtils.toString(errorStream);
        } catch (IOException e1) {
            errorString = "errorStream could not be reset/reread";
        }
        return errorString;
    }

    private static String domToString(Document document)
            throws ParserConfigurationException, TransformerConfigurationException, TransformerException {
        DocumentBuilder documentBuilder = null;
        Transformer transformer = null;
        StringWriter strWtr = new StringWriter();

        documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();

        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        transformer = transformerFactory.newTransformer();
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
        transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //xml, html, text
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
        String result = null;
        if (document != null) {
            StreamResult strResult = new StreamResult(strWtr);
            transformer.transform(new DOMSource(document.getDocumentElement()), strResult);
            result = strResult.getWriter().toString();
        }
        return result;
    }
}