org.openbravo.test.webservice.BaseWSTest.java Source code

Java tutorial

Introduction

Here is the source code for org.openbravo.test.webservice.BaseWSTest.java

Source

/*
 *************************************************************************
 * The contents of this file are subject to the Openbravo  Public  License
 * Version  1.1  (the  "License"),  being   the  Mozilla   Public  License
 * Version 1.1  with a permitted attribution clause; you may not  use this
 * file except in compliance with the License. You  may  obtain  a copy of
 * the License at http://www.openbravo.com/legal/license.html 
 * Software distributed under the License  is  distributed  on  an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific  language  governing  rights  and  limitations
 * under the License. 
 * The Original Code is Openbravo ERP. 
 * The Initial Developer of the Original Code is Openbravo SLU 
 * All portions are Copyright (C) 2008-2014 Openbravo SLU 
 * All Rights Reserved. 
 * Contributor(s):  ______________________________________.
 ************************************************************************
 */

package org.openbravo.test.webservice;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.util.Properties;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.SchemaFactory;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.io.SAXReader;
import org.openbravo.base.exception.OBException;
import org.openbravo.base.session.OBPropertiesProvider;
import org.openbravo.dal.xml.XMLUtil;
import org.openbravo.test.base.OBBaseTest;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;

/**
 * Base class for webservice tests. Provides several methods to do HTTP REST requests.
 * 
 * @author mtaal
 */

public class BaseWSTest extends OBBaseTest {

    private static final Logger log = Logger.getLogger(BaseWSTest.class);
    private static final String CONTEXT_PROPERTY = "context.url";
    private static String OB_URL = null;
    protected static final String LOGIN = "Openbravo";
    protected static final String PWD = "openbravo";

    private String xmlSchema = null;

    /**
     * Executes a DELETE HTTP request, the wsPart is appended to the {@link #getOpenbravoURL()}.
     * 
     * @param wsPart
     *          the actual webservice part of the url, is appended to the openbravo url (
     *          {@link #getOpenbravoURL()}), includes any query parameters
     * @param expectedResponse
     *          the expected HTTP response code
     */
    protected void doDirectDeleteRequest(String wsPart, int expectedResponse) {
        try {
            final HttpURLConnection hc = createConnection(wsPart, "DELETE");
            hc.connect();
            assertEquals(expectedResponse, hc.getResponseCode());
            assertTrue("Content type not set in delete response", hc.getContentType() != null);
            // disabled, see here: https://issues.openbravo.com/view.php?id=10236
            // assertTrue("Content encoding not set in delete response", hc.getContentEncoding() != null);
        } catch (final Exception e) {
            throw new OBException(e);
        }
    }

    /**
     * Execute a REST webservice HTTP request which posts/puts content and returns a XML result. The
     * content is validated against the XML schema retrieved using the /ws/dal/schema webservice call.
     * 
     * @param wsPart
     *          the actual webservice part of the url, is appended to the openbravo url (
     *          {@link #getOpenbravoURL()}), includes any query parameters
     * @param content
     *          the content (XML) to post or put
     * @param expectedResponse
     *          the expected HTTP response code
     * @param expectedContent
     *          the system check that the returned content contains this expectedContent
     * @param method
     *          POST or PUT
     * @return the result from the rest request (i.e. the content of the response), most of the time
     *         an xml string
     */
    protected String doContentRequest(String wsPart, String content, int expectedResponse, String expectedContent,
            String method) {
        return doContentRequest(wsPart, content, expectedResponse, expectedContent, method, true);
    }

    /**
     * Execute a REST webservice HTTP request which posts/puts content and returns a result. If
     * validateXML parameter is <code>true</code>, the content is validated against the XML schema
     * retrieved using the /ws/dal/schema webservice call.
     * 
     * @param wsPart
     *          the actual webservice part of the url, is appended to the openbravo url (
     *          {@link #getOpenbravoURL()}), includes any query parameters
     * @param content
     *          the content (XML) to post or put
     * @param expectedResponse
     *          the expected HTTP response code
     * @param expectedContent
     *          the system check that the returned content contains this expectedContent
     * @param method
     *          POST or PUT
     * @param validateXML
     *          should response be validated as XML
     * @return the result from the rest request (i.e. the content of the response), most of the time
     *         an xml string
     */
    protected String doContentRequest(String wsPart, String content, int expectedResponse, String expectedContent,
            String method, boolean validateXML) {
        try {
            final HttpURLConnection hc = createConnection(wsPart, method);
            final OutputStream os = hc.getOutputStream();
            os.write(content.getBytes("UTF-8"));
            os.flush();
            os.close();
            hc.connect();

            assertEquals(expectedResponse, hc.getResponseCode());

            if (expectedResponse == 500) {
                // no content available anyway
                return "";
            }

            String retContent;

            if (validateXML) {
                final SAXReader sr = new SAXReader();
                final InputStream is = hc.getInputStream();
                final Document doc = sr.read(is);
                retContent = XMLUtil.getInstance().toString(doc);
                validateXML(retContent);
            } else {
                StringWriter writer = new StringWriter();
                IOUtils.copy(hc.getInputStream(), writer, "utf-8");
                retContent = writer.toString();
            }

            if (retContent.indexOf(expectedContent) == -1) {
                log.debug(retContent);
                fail("WS response does not contain: [" + expectedContent + "]\nActual result:\n" + retContent);
            }

            return retContent;
        } catch (final Exception e) {
            throw new OBException(e);
        }
    }

    /**
     * Convenience method to get a value of a specific XML element without parsing the whole xml
     * 
     * @param content
     *          the xml
     * @param tag
     *          the element name
     * @return the value
     */
    protected String getTagValue(String content, String tag) {
        final int index1 = content.indexOf("<" + tag + ">") + ("<" + tag + ">").length();
        if (index1 == -1) {
            return "";
        }
        final int index2 = content.indexOf("</" + tag + ">");
        if (index2 == -1) {
            return "";
        }
        return content.substring(index1, index2);
    }

    /**
     * Executes a GET request and validates the return against the schema. The content is validated
     * against the XML schema retrieved using the /ws/dal/schema webservice call.
     * 
     * @param wsPart
     *          the actual webservice part of the url, is appended to the openbravo url (
     *          {@link #getOpenbravoURL()}), includes any query parameters
     * @param testContent
     *          the system check that the returned content contains this testContent. if null is
     *          passed for this parameter then this check is not done.
     * @param responseCode
     *          the expected HTTP response code
     * @return the content returned from the GET request
     */
    protected String doTestGetRequest(String wsPart, String testContent, int responseCode) {
        return doTestGetRequest(wsPart, testContent, responseCode, true);
    }

    protected String doTestGetRequest(String wsPart, String testContent, int responseCode, boolean validate) {
        return doTestGetRequest(wsPart, testContent, responseCode, validate, true);
    }

    /**
     * Executes a GET request. The content is validated against the XML schema retrieved using the
     * /ws/dal/schema webservice call.
     * 
     * @param wsPart
     *          the actual webservice part of the url, is appended to the openbravo url (
     *          {@link #getOpenbravoURL()}), includes any query parameters
     * @param testContent
     *          the system check that the returned content contains this testContent. if null is
     *          passed for this parameter then this check is not done.
     * @param responseCode
     *          the expected HTTP response code
     * @param validate
     *          if true then the response content is validated against the Openbravo XML Schema
     * @param logException
     *          indicates whether in case of Exception it should be logged, this param should be false
     *          when Exception is expected in order not to pollute the log
     * @return the content returned from the GET request
     */
    protected String doTestGetRequest(String wsPart, String testContent, int responseCode, boolean validate,
            boolean logException) {
        try {
            final HttpURLConnection hc = createConnection(wsPart, "GET");
            hc.connect();
            final SAXReader sr = new SAXReader();
            final InputStream is = hc.getInputStream();
            final StringBuilder sb = new StringBuilder();
            BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line).append("\n");
            }
            try {
                final Document doc = sr.read(new StringReader(sb.toString()));
                final String content = XMLUtil.getInstance().toString(doc);
                if (testContent != null && content.indexOf(testContent) == -1) {
                    log.debug(content);
                    fail();
                }
                assertEquals(responseCode, hc.getResponseCode());
                is.close();
                // do not validate the xml schema itself, this results in infinite loops
                if (validate) {
                    validateXML(content);
                }
                return content;
            } catch (Exception e) {
                log.debug(sb.toString());
                throw e;
            }
        } catch (final Exception e) {
            throw new OBException("Exception when executing ws: " + wsPart, e, logException);
        }
    }

    /**
     * Creates a HTTP connection.
     * 
     * @param wsPart
     * @param method
     *          POST, PUT, GET or DELETE
     * @return the created connection
     * @throws Exception
     */
    protected HttpURLConnection createConnection(String wsPart, String method) throws Exception {
        Authenticator.setDefault(new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(LOGIN, PWD.toCharArray());
            }
        });
        log.debug(method + ": " + getOpenbravoURL() + wsPart);
        final URL url = new URL(getOpenbravoURL() + wsPart);
        final HttpURLConnection hc = (HttpURLConnection) url.openConnection();
        hc.setRequestMethod(method);
        hc.setAllowUserInteraction(false);
        hc.setDefaultUseCaches(false);
        hc.setDoOutput(true);
        hc.setDoInput(true);
        hc.setInstanceFollowRedirects(true);
        hc.setUseCaches(false);
        hc.setRequestProperty("Content-Type", "text/xml");
        return hc;
    }

    /**
     * Returns the url of the Openbravo instance. The default value is: {@link #OB_URL}
     * 
     * @return the url of the Openbravo instance.
     */
    protected String getOpenbravoURL() {
        if (OB_URL != null) {
            return OB_URL;
        }
        Properties props = OBPropertiesProvider.getInstance().getOpenbravoProperties();
        OB_URL = props.getProperty(CONTEXT_PROPERTY);
        if (StringUtils.isEmpty(OB_URL)) {
            throw new OBException(CONTEXT_PROPERTY + " is not set in Openbravo.properties");
        }
        log.debug("got OB context: " + OB_URL);

        return OB_URL;
    }

    /**
     * Returns the login used to login for the webservice. The default value is {@link #LOGIN}.
     * 
     * @return the login name used to login for the webservice
     */
    protected String getLogin() {
        return LOGIN;
    }

    /**
     * Returns the password used to login into the webservice server. The default value is
     * {@link #PWD}.
     * 
     * @return the password used to login into the webservice, the default is {@link #PWD}
     */
    protected String getPassword() {
        return PWD;
    }

    /**
     * Validates the xml against the generated schema.
     * 
     * @param xml
     *          the xml to validate
     */
    protected void validateXML(String xml) {
        final Reader schemaReader = new StringReader(getXMLSchema());
        final Reader xmlReader = new StringReader(xml);
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            factory.setValidating(false);
            factory.setNamespaceAware(true);

            SchemaFactory schemaFactory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");

            factory.setSchema(schemaFactory.newSchema(new Source[] { new StreamSource(schemaReader) }));

            SAXParser parser = factory.newSAXParser();

            XMLReader reader = parser.getXMLReader();
            reader.setErrorHandler(new SimpleErrorHandler());
            reader.parse(new InputSource(xmlReader));
        } catch (Exception e) {
            throw new OBException(e);
        }

    }

    private String getXMLSchema() {
        if (xmlSchema != null) {
            return xmlSchema;
        }

        xmlSchema = doTestGetRequest("/ws/dal/schema", "<xs:element name=\"Openbravo\">", 200, false);
        return xmlSchema;
    }

    public class SimpleErrorHandler implements ErrorHandler {
        public void warning(SAXParseException e) throws SAXException {
        }

        public void error(SAXParseException e) throws SAXException {
            throw e;
        }

        public void fatalError(SAXParseException e) throws SAXException {
            throw e;
        }
    }

}