Package org.geoserver.test

Source Code of org.geoserver.test.GeoServerAbstractTestSupport$GeoServerMockServletInputStream

package org.geoserver.test;

import static org.custommonkey.xmlunit.XMLAssert.*;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.ServletContext;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
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.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import net.sf.json.JSON;
import net.sf.json.JSONSerializer;

import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.NamespaceInfo;
import org.geoserver.config.GeoServer;
import org.geoserver.config.GeoServerDataDirectory;
import org.geoserver.config.GeoServerLoader;
import org.geoserver.data.test.TestData;
import org.geoserver.logging.LoggingUtils;
import org.geoserver.ows.util.ResponseUtils;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.platform.GeoServerResourceLoader;
import org.geotools.data.FeatureSource;
import org.geotools.factory.Hints;
import org.geotools.referencing.CRS;
import org.geotools.util.logging.Log4JLoggerFactory;
import org.geotools.util.logging.Logging;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.HandlerInterceptor;
import org.vfny.geoserver.global.GeoserverDataDirectory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import com.mockrunner.mock.web.MockHttpServletRequest;
import com.mockrunner.mock.web.MockHttpServletResponse;
import com.mockrunner.mock.web.MockHttpSession;
import com.mockrunner.mock.web.MockServletConfig;
import com.mockrunner.mock.web.MockServletContext;
import com.mockrunner.mock.web.MockServletOutputStream;

/**
* Base test class for GeoServer unit tests.
* <p>
* This test case provides a spring application context which loads the
* application contexts from all modules on the classpath.
* </p>
* <p>
* Subclasses should provide a data directory location, that will be inserted
* in the mock servlet context for GeoServer to pick up
* </p>
* @author Justin Deoliveira, The Open Planning Project, jdeolive@openplans.org
* @author Andrea Aime, The Open Planning Project
*/
public abstract class GeoServerAbstractTestSupport extends OneTimeSetupTest {
    /**
     * Common logger for test cases
     */
    protected static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geoserver.test");
   
    /**
     * Application context
     */
    protected static GeoServerTestApplicationContext applicationContext;

    protected static TestData testData;
   
    /**
     * Returns a test data instance
     *
     * @return
     */
    protected abstract TestData buildTestData() throws Exception;
   
    public TestData getTestData() {
        return testData;
    }

    /**
     * Override runTest so that the test will be skipped if the TestData is not
     * available
     */
    protected void runTest() throws Throwable {
        if (getTestData().isTestDataAvailable()) {
            super.runTest();
        } else {
            LOGGER.warning("Skipping " + getClass() + "." + getName()
                    + " since test data is not available");
        }
    }

    /**
     * If subclasses override they *must* call super.setUp() first.
     */
    @Override
    protected void oneTimeSetUp() throws Exception {
        // do we need to reset the referencing subsystem and reorient it with lon/lat order?
        if (System.getProperty("org.geotools.referencing.forceXY") == null
                || !"http".equals(Hints.getSystemDefault(Hints.FORCE_AXIS_ORDER_HONORING))) {
            System.setProperty("org.geotools.referencing.forceXY", "true");
            Hints.putSystemDefault(Hints.FORCE_AXIS_ORDER_HONORING, "http");
            CRS.reset("all");
        }
       
        // set up test data
        testData = buildTestData();
        testData.setUp();

        // setup quiet logging (we need to to this here because Data
        // is loaded before GoeServer has a chance to setup logging for good)
        try {
            Logging.ALL.setLoggerFactory(Log4JLoggerFactory.getInstance());
        } catch (Exception e) {
            LOGGER.log(Level.SEVERE, "Could not configure log4j logging redirection", e);
        }
        System.setProperty(LoggingUtils.RELINQUISH_LOG4J_CONTROL, "true");
        GeoServerResourceLoader loader = new GeoServerResourceLoader(testData.getDataDirectoryRoot());
        LoggingUtils.configureGeoServerLogging(loader, getClass().getResourceAsStream(getLogConfiguration()), false, true, null);

        //HACK: once we port tests to the new data directory, remove this
        GeoServerLoader.setLegacy( useLegacyDataDirectory() );

        // if we have data, create a mock servlet context and start up the spring configuration
        if (testData.isTestDataAvailable()) {
            MockServletContext servletContext = new MockServletContext();
            servletContext.setInitParameter("GEOSERVER_DATA_DIR", testData.getDataDirectoryRoot()
                    .getPath());
            servletContext.setInitParameter("serviceStrategy", "PARTIAL-BUFFER2");

            applicationContext = new GeoServerTestApplicationContext(getSpringContextLocations(),
                    servletContext);
            applicationContext.refresh();

            // set the parameter after a refresh because it appears a refresh
            // wipes
            // out all parameters
            servletContext.setAttribute(
                    WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
                    applicationContext);
        }
    }
   
    /**
     * Flag which controls the mock data directory setup.
     * <p>
     * If true is returned, the legacy structure is presevered on sstartup, and no
     * conversion to the new data directory structure happens.
     * </p>
     *
     */
    protected boolean useLegacyDataDirectory() {
        return true;
    }
   
    /**
     * Returns the spring context locations to be used in order to build the GeoServer Spring
     * context. Subclasses might want to provide extra locations in order to test extension points.
     * @return
     */
    protected String[] getSpringContextLocations() {
        return new String[] {
                "classpath*:/applicationContext.xml",
                "classpath*:/applicationSecurityContext.xml"
            };
    }

    /**
     * Returns the logging configuration path. The default value is "/TEST_LOGGING.properties", which
     * is a pretty quiet configuration. Should you need more verbose logging override this method
     * in subclasses and choose a different configuration, for example "/DEFAULT_LOGGING.properties".
     * @return
     */
    protected String getLogConfiguration() {
        return "/TEST_LOGGING.properties";
    }

    /**
     * Returns a default services.xml file with WMS, WFS and WCS enabled. Subclasses may
     * need to override this in order to test extra services or specific configurations
     * @return
     */
    protected URL getServicesFile() {
        return GeoServerAbstractTestSupport.class.getResource("services.xml");
    }

    /**
     * Subclasses may override this method to force memory cleaning before the
     * test data dir is cleaned up. This is necessary on windows if coverages are used in the
     * test, since readers might still be around in the heap as garbage without having
     * been disposed of
     * @return
     */
    protected boolean isMemoryCleanRequired() {
        return false;
    }

    /**
     * If subclasses overide they *must* call super.tearDown() first.
     */
    @Override
    protected void oneTimeTearDown() throws Exception {
        if(getTestData().isTestDataAvailable()) {
            try {
                // kill the context
                applicationContext.destroy();
               
                // kill static caches
                new GeoServerExtensions().setApplicationContext(null);
       
                // some tests do need a kick on the GC to fully clean up
                if(isMemoryCleanRequired()) {
                    System.gc();
                    System.runFinalization();
                }
               
                if(getTestData() != null) {
                    // this cleans up the data directory static loader, if we don't the next test
                    // will keep on running on the current data dir
                    GeoserverDataDirectory.destroy();
                    getTestData().tearDown();
                }
            } finally {
                applicationContext = null;
                testData = null;
            }
        }
    }
    
    /**
     * Reloads the catalog and configuration from disk.
     * <p>
     * This method can be used by subclasses from a test method after they have
     * changed the configuration on disk.
     * </p>
     */
    protected void reloadCatalogAndConfiguration() throws Exception {
        GeoServerLoader loader = GeoServerExtensions.bean( GeoServerLoader.class , applicationContext );
        loader.reload();
    }
   
    /**
     * Accessor for global catalog instance from the test application context.
     */
    protected Catalog getCatalog() {
        return (Catalog) applicationContext.getBean("catalog");
    }

    /**
     * Accessor for global geoserver instance from the test application context.
     */
    protected GeoServer getGeoServer() {
        return (GeoServer) applicationContext.getBean("geoServer");
    }
   
    /**
     * Accessor for global resource loader instance from the test application context.
     */
    protected GeoServerResourceLoader getResourceLoader() {
        return (GeoServerResourceLoader) applicationContext.getBean( "resourceLoader" );
    }
   
    protected GeoServerDataDirectory getDataDirectory() {
        return new GeoServerDataDirectory(getResourceLoader());
    }

    /**
     * Loads a feature source from the catalog.
     *
     * @param typeName The qualified type name of the feature source.
     */
    @SuppressWarnings("unchecked")
    protected FeatureSource<SimpleFeatureType, SimpleFeature> getFeatureSource(QName typeName)
            throws IOException {
        // TODO: expand test support to DataAccess FeatureSource
        FeatureTypeInfo ft = getFeatureTypeInfo(typeName);
        return (FeatureSource<SimpleFeatureType, SimpleFeature>) ft.getFeatureSource(null, null);
    }

    /**
     * Get the FeatureTypeInfo for a featuretype to allow configuration tweaks for tests.
     *
     * @param typename the QName for the type
     */
    protected FeatureTypeInfo getFeatureTypeInfo(QName typename){
        return getCatalog().getFeatureTypeByName( typename.getNamespaceURI(), typename.getLocalPart() );
    }

    /**
     * Get the FeatureTypeInfo for a featuretype by the layername that would be used in a request.
     *
     * @param typename the layer name for the type
     */
    protected FeatureTypeInfo getFeatureTypeInfo(String typename){
        return getFeatureTypeInfo(resolveLayerName(typename));
    }

    /**
     * Get the QName for a layer specified by the layername that would be used in a request.
     * @param typename the layer name for the type
     */
    protected QName resolveLayerName(String typename){
        int i = typename.indexOf(":");
        String prefix = typename.substring(0, i);
        String name = typename.substring(i + 1);
        NamespaceInfo ns = getCatalog().getNamespaceByPrefix(prefix);
        QName qname = new QName(ns.getURI(), name, ns.getPrefix());
        return qname;
    }

    /**
     * @deprecated use {@link #getLayerId(QName)}.
     */
    public final String layerId(QName layerName) {
        return getLayerId( layerName );
    }
   
    /**
     * Given a qualified layer name returns a string in the form "prefix:localPart" if prefix
     * is available, "localPart" if prefix is null
     * @param layerName
     * @return
     */
    public String getLayerId(QName layerName) {
        if(layerName.getPrefix() != null)
            return layerName.getPrefix() + ":" + layerName.getLocalPart();
        else
            return layerName.getLocalPart();
    }

    /**
     * Convenience method for subclasses to create mock http servlet requests.
     * <p>
     * Examples of using this method are:
     * <pre>
     * <code>
     *   createRequest( "wfs?request=GetCapabilities" );  //get
     *   createRequest( "wfs" ); //post
     * </code>
     * </pre>
     * </p>
     * @param path The path for the request and optional the query string.
     * @return
     */
    protected MockHttpServletRequest createRequest(String path) {
        MockHttpServletRequest request = new GeoServerMockHttpServletRequest();

        request.setScheme("http");
        request.setServerName("localhost");
        request.setContextPath("/geoserver");
        request.setRequestURI(ResponseUtils.stripQueryString(ResponseUtils.appendPath(
                    "/geoserver/", path)));
        request.setRequestURL(ResponseUtils.appendPath("http://localhost/geoserver", path ) );
        request.setQueryString(ResponseUtils.getQueryString(path));
        request.setRemoteAddr("127.0.0.1");
        request.setServletPath(ResponseUtils.makePathAbsolute( ResponseUtils.stripRemainingPath(path)) );
        request.setPathInfo(ResponseUtils.makePathAbsolute( ResponseUtils.stripBeginningPath( path)));
       
        kvp(request, path);

        MockHttpSession session = new MockHttpSession();
        session.setupServletContext(new MockServletContext());
        request.setSession(session);

        request.setUserPrincipal(null);

        return request;
    }

    /**
     * Convenience method for subclasses to create mock http servlet requests.
     * <p>
     * Examples of using this method are:
     * <pre>
     * <code>
     *   Map kvp = new HashMap();
     *   kvp.put( "service", "wfs" );
     *   kvp.put( "request", "GetCapabilities" );
     *  
     *   createRequest( "wfs", kvp );
     * </code>
     * </pre>
     * </p>
     * @param path The path for the request, minus any query string parameters.
     * @param kvp The key value pairs to be put in teh query string.
     *
     */
    protected MockHttpServletRequest createRequest( String path, Map kvp ) {
        StringBuffer q = new StringBuffer();
        for ( Iterator e = kvp.entrySet().iterator(); e.hasNext(); ) {
            Map.Entry entry = (Map.Entry) e.next();
            q.append( entry.getKey() ).append("=").append( entry.getValue() );
            q.append( "&" );
        }
        q.setLength(q.length()-1);
       
        return createRequest( ResponseUtils.appendQueryString(path, q.toString() ) );
    }
   
    /**
     * Executes an ows request using the GET method.
     *
     * @param path The porition of the request after hte context,
     *      example: 'wms?request=GetMap&version=1.1.1&..."
     *
     * @return An input stream which is the result of the request.
     *
     * @throws Exception
     */
    protected InputStream get( String path ) throws Exception {
        MockHttpServletResponse response = getAsServletResponse(path);
        return new ByteArrayInputStream( response.getOutputStreamContent().getBytes() );
    }
   
    /**
     * Executes an ows request using the GET method.
     *
     * @param path The porition of the request after hte context,
     *      example: 'wms?request=GetMap&version=1.1.1&..."
     *
     * @return the mock servlet response
     *
     * @throws Exception
     */
    protected MockHttpServletResponse getAsServletResponse( String path ) throws Exception {
        MockHttpServletRequest request = createRequest( path );
        request.setMethod( "GET" );
        request.setBodyContent(new byte[]{});
       
        return dispatch( request );
    }
       
    /**
     * Executes an ows request using the POST method with key value pairs
     * form encoded.
     *
     * @param path The porition of the request after hte context,
     *      example: 'wms?request=GetMap&version=1.1.1&..."
     *
     * @return An input stream which is the result of the request.
     *
     * @throws Exception
     */
    protected InputStream post( String path ) throws Exception {
        MockHttpServletRequest request = createRequest( path );
        request.setMethod( "POST" );
        request.setContentType( "application/x-www-form-urlencoded" );
        request.setBodyContent(new byte[]{});
       
        MockHttpServletResponse response = dispatch( request );
        return new ByteArrayInputStream( response.getOutputStreamContent().getBytes() );
    }

    /**
     * Executes a request with an empty body using the PUT method.
     *
     * @param path the portion of the request after the context, for example:
     *      "api/datastores.xml"
     *
     * @throws Exception
     */
    protected InputStream put(String path) throws Exception{
        return put(path, "");
    }

    /**
     * Executes a request with a default mimetype using the PUT method.
     *
     * @param path the portion of the request after the context, for example:
     *      "api/datastores.xml"
     * @param body the content to send as the body of the request
     *
     * @throws Exception
     */
    protected InputStream put(String path, String body) throws Exception{
        return put(path, body, "text/plain");
    }

    /**
     * Executes a request using the PUT method.
     *
     * @param path the portion of the request after the context, for example:
     *      "api/datastores.xml"
     * @param body the content to send as the body of the request
     * @param contentType the mime-type to set for the request being sent
     *
     * @throws Exception
     */
    protected InputStream put(String path, String body, String contentType) throws Exception {
        return put( path, body.getBytes(), contentType );
    }

    /**
     * Executes a request using the PUT method.
     *
     * @param path the portion of the request after the context, for example:
     *      "api/datastores.xml"
     * @param body the content to send as the body of the request
     * @param contentType the mime-type to set for the request being sent
     *
     * @throws Exception
     */
    protected InputStream put(String path, byte[] body, String contentType) throws Exception {
        MockHttpServletResponse response = putAsServletResponse(path, body, contentType);
        return new ByteArrayInputStream(response.getOutputStreamContent().getBytes());
    }
   
    protected MockHttpServletResponse putAsServletResponse(String path) throws Exception {
        return putAsServletResponse(path, new byte[]{}, "text/plain");
    }
   
    protected MockHttpServletResponse putAsServletResponse(String path, String body, String contentType )
    throws Exception {
        return putAsServletResponse(path, body != null ? body.getBytes() : (byte[]) null, contentType);
    }
   
    protected MockHttpServletResponse putAsServletResponse(String path, byte[] body, String contentType )
        throws Exception {
       
        MockHttpServletRequest request = createRequest(path);
        request.setMethod("PUT");
        request.setContentType(contentType);
        request.setBodyContent(body);
        request.setHeader( "Content-type", contentType );

        return dispatch(request);
    }
   
    /**
     * Executes an ows request using the POST method.
     * <p>
     *
     * </p>
     * @param path The porition of the request after the context ( no query string ),
     *      example: 'wms'.
     *
     * @return An input stream which is the result of the request.
     *
     * @throws Exception
     */
    protected InputStream post( String path , String xml ) throws Exception {
        MockHttpServletResponse response = postAsServletResponse(path, xml);
        return new ByteArrayInputStream(response.getOutputStreamContent().getBytes());
    }

    /**
     * Executes an ows request using the POST method, with xml as body content.
     *
     *
     * @param path
     *            The porition of the request after the context ( no query
     *            string ), example: 'wms'.
     * @param xml The body content.
     *
     * @return the servlet response
     *
     * @throws Exception
     */
    protected MockHttpServletResponse postAsServletResponse(String path, String xml)
            throws Exception {
       
        return postAsServletResponse(path, xml, "application/xml");
    }

    /**
     * Extracts the true binary stream out of the response. The usual way (going
     * thru {@link MockHttpServletResponse#getOutputStreamContent()}) mangles
     * bytes if the content is not made of chars.
     *
     * @param response
     * @return
     */
    protected ByteArrayInputStream getBinaryInputStream(MockHttpServletResponse response) {
        try {
            MockServletOutputStream os = (MockServletOutputStream) response.getOutputStream();
            final Field field = os.getClass().getDeclaredField("buffer");
            field.setAccessible(true);
            ByteArrayOutputStream bos = (ByteArrayOutputStream) field.get(os);
            return new ByteArrayInputStream(bos.toByteArray());
        } catch (Exception e) {
            throw new RuntimeException("Whoops, did you change the MockRunner version? "
                    + "If so, you might want to change this method too");
        }
    }
           
           
    /**
     * Executes an ows request using the POST method.
     *
     * @param path
     *            The porition of the request after the context ( no query
     *            string ), example: 'wms'.
     *
     * @param body
     *            the body of the request
     * @param contentType
     *            the mimetype to set for the request
     *
     * @return An input stream which is the result of the request.
     *
     * @throws Exception
     */
    protected InputStream post(String path, String body, String contentType) throws Exception{
        MockHttpServletResponse response = postAsServletResponse(path, body, contentType);
        return new ByteArrayInputStream(response.getOutputStreamContent().getBytes());
    }
   
    protected MockHttpServletResponse postAsServletResponse(String path, String body, String contentType) throws Exception {
        MockHttpServletRequest request = createRequest(path);
        request.setMethod("POST");
        request.setContentType(contentType);
        request.setBodyContent(body);
        request.setHeader("Content-type",  contentType );

        return dispatch(request);
    }
   
    /**
     * Execultes a request using the DELETE method.
     *
     * @param path The path of the request.
     *
     * @return The http status code.
     */
    protected MockHttpServletResponse deleteAsServletResponse(String path) throws Exception {
        MockHttpServletRequest request = createRequest(path);
        request.setMethod("DELETE");
       
        return dispatch(request);
    }
   
    /**
     * Executes an ows request using the GET method and returns the result as an
     * xml document.
     *
     * @param path The portion of the request after the context,
     *      example: 'wms?request=GetMap&version=1.1.1&..."
     * @param the list of validation errors encountered during document parsing (validation
     *        will be activated only if this list is non null)
     *
     * @return A result of the request parsed into a dom.
     *
     * @throws Exception
     */
    protected Document getAsDOM(final String path)
            throws Exception {
        return getAsDOM(path, true);
    }
   
    /**
     * Executes a request using the GET method and parses the result as a json object.
     *
     * @param path The path to request.
     * 
     * @return The result parsed as json.
     */
    protected JSON getAsJSON(final String path) throws Exception {
        BufferedReader in = new BufferedReader( new InputStreamReader ( get( path ) ) );
        StringBuffer json = new StringBuffer();
        String line = null;
        while( ( line = in.readLine() ) != null ) {
            json.append( line );
        }
        in.close();
       
        return JSONSerializer.toJSON( json.toString() );
    }

    /**
     * Executes an ows request using the GET method and returns the result as an xml document.
     *
     * @param path
     *                The portion of the request after the context, example:
     *                'wms?request=GetMap&version=1.1.1&..."
     * @param skipDTD
     *                if true, will avoid loading and validating against the response document
     *                schema or DTD
     *
     * @return A result of the request parsed into a dom.
     *
     * @throws Exception
     */
    protected Document getAsDOM(final String path, final boolean skipDTD)
    throws Exception {
        return dom(get(path), skipDTD);
    }
   
    /**
     * Executes an ows request using the POST method with key value pairs
     * form encoded, returning the result as a dom.
     *
     * @param path The porition of the request after hte context,
     *      example: 'wms?request=GetMap&version=1.1.1&..."
     * @param the list of validation errors encountered during document parsing (validation
     *        will be activated only if this list is non null)    
     *
     * @return An input stream which is the result of the request.
     *
     * @throws Exception
     */
    protected Document postAsDOM( String path ) throws Exception {
        return postAsDOM(path, (List<Exception>) null);
    }
   
    /**
     * Executes an ows request using the POST method with key value pairs
     * form encoded, returning the result as a dom.
     *
     * @param path The porition of the request after hte context,
     *      example: 'wms?request=GetMap&version=1.1.1&..."
     *
     * @return An input stream which is the result of the request.
     *
     * @throws Exception
     */
    protected Document postAsDOM( String path, List<Exception> validationErrors ) throws Exception {
        return dom( post( path ));
    }
   
    /**
     * Executes an ows request using the POST method and returns the result as an
     * xml document.
     * <p>
     *
     * </p>
     * @param path The porition of the request after the context ( no query string ),
     *      example: 'wms'.
     *
     * @return An input stream which is the result of the request.
     *
     * @throws Exception
     */
    protected Document postAsDOM( String path, String xml ) throws Exception {
            return postAsDOM(path, xml, null);
    }
   
    /**
     * Executes an ows request using the POST method and returns the result as an
     * xml document.
     * <p>
     *
     * </p>
     * @param path The porition of the request after the context ( no query string ),
     *      example: 'wms'.
     *
     * @return An input stream which is the result of the request.
     *
     * @throws Exception
     */
    protected Document postAsDOM( String path, String xml, List<Exception> validationErrors ) throws Exception {
            return dom( post( path, xml ));
    }
   
    protected String getAsString(String path) throws Exception {
        return string(get(path));
    }
   
    /**
     * Parses a stream into a dom.
     */
    protected Document dom(InputStream is) throws ParserConfigurationException, SAXException, IOException {
        return dom(is, true);
    }
   
    /**
     * Parses a stream into a dom.
     * @param input
     * @param skipDTD If true, will skip loading and validating against the associated DTD
     */
    protected Document dom(InputStream input, boolean skipDTD) throws ParserConfigurationException, SAXException, IOException {
        if(skipDTD) {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware( true );
            factory.setValidating( false );
          
            DocumentBuilder builder = factory.newDocumentBuilder();
            builder.setEntityResolver(new EmptyResolver());
            Document dom = builder.parse( input );
   
            return dom;
        } else {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(true);
            DocumentBuilder builder = factory.newDocumentBuilder();
            return builder.parse(input);
        }
    }
   
    /**
     * Resolves everything to an empty xml document, useful for skipping errors due to missing
     * dtds and the like
     * @author Andrea Aime - TOPP
     */
    static class EmptyResolver implements org.xml.sax.EntityResolver {
        public InputSource resolveEntity(String publicId, String systemId)
                throws org.xml.sax.SAXException, IOException {
            StringReader reader = new StringReader(
                    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
            InputSource source = new InputSource(reader);
            source.setPublicId(publicId);
            source.setSystemId(systemId);

            return source;
        }
    }
           
    protected void checkValidationErorrs(Document dom, String schemaLocation) throws SAXException, IOException {
        final SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = factory.newSchema(new File(schemaLocation));
        checkValidationErrors(dom, schema);
    }

    /**
     * Given a dom and a schema, checks that the dom validates against the schema
     * of the validation errors instead
     * @param validationErrors
     * @throws IOException
     * @throws SAXException
     */
    protected void checkValidationErrors(Document dom, Schema schema) throws SAXException, IOException {
        final Validator validator = schema.newValidator();
        final List<Exception> validationErrors = new ArrayList<Exception>();
        validator.setErrorHandler(new ErrorHandler() {
           
            public void warning(SAXParseException exception) throws SAXException {
                System.out.println(exception.getMessage());
            }

            public void fatalError(SAXParseException exception) throws SAXException {
                validationErrors.add(exception);
            }

            public void error(SAXParseException exception) throws SAXException {
                validationErrors.add(exception);
            }

          });
        validator.validate(new DOMSource(dom));
        if (validationErrors != null && validationErrors.size() > 0) {
            StringBuilder sb = new StringBuilder();
            for (Exception ve : validationErrors) {
                sb.append(ve.getMessage()).append("\n");
            }
            fail(sb.toString());
        }
    }
   
    /**
     * Performs basic checks on an OWS 1.0 exception, to ensure it's well formed
     */
    protected void checkOws10Exception(Document dom) throws Exception {
        checkOws10Exception(dom,null);
    }
    /**
     * Performs basic checks on an OWS 1.0 exception, to ensure it's well formed
     * and ensuring that a particular exceptionCode is used.
     */
    protected void checkOws10Exception(Document dom, String exceptionCode) throws Exception {
        Element root = dom.getDocumentElement();
        assertEquals("ows:ExceptionReport", root.getNodeName() );
        assertEquals( "1.0.0", root.getAttribute( "version") );
        assertEquals("http://www.opengis.net/ows", root.getAttribute( "xmlns:ows"));
        assertEquals( 1, dom.getElementsByTagName( "ows:Exception").getLength() );
       
        if ( exceptionCode != null ) {
            Element ex = (Element) dom.getElementsByTagName( "ows:Exception").item(0);
            assertEquals( exceptionCode, ex.getAttribute( "exceptionCode") );
        }
    }
   
    /**
     * Performs basic checks on an OWS 1.1 exception, to ensure it's well formed
     */
    protected void checkOws11Exception(Document dom) throws Exception {
        checkOws11Exception(dom,null);
    }
    /**
     * Performs basic checks on an OWS 1.1 exception, to ensure it's well formed
     * and ensuring that a particular exceptionCode is used.
     */
    protected void checkOws11Exception(Document dom, String exceptionCode) throws Exception {
        Element root = dom.getDocumentElement();
        assertEquals("ows:ExceptionReport", root.getNodeName() );
        assertEquals( "1.1.0", root.getAttribute( "version") );
        assertEquals("http://www.opengis.net/ows/1.1", root.getAttribute( "xmlns:ows"));
       
        if ( exceptionCode != null ) {
            assertEquals( 1, dom.getElementsByTagName( "ows:Exception").getLength() );
            Element ex = (Element) dom.getElementsByTagName( "ows:Exception").item(0);
            assertEquals( exceptionCode, ex.getAttribute( "exceptionCode") );
        }
    }
       
   
    /**
     * Parses a stream into a String
     */
    protected String string(InputStream input) throws Exception {
        BufferedReader reader = null;
        StringBuffer sb = new StringBuffer();
        char[] buf = new char[8192];
        try {
            reader = new BufferedReader(new InputStreamReader(input));
            String line = null;
            while((line = reader.readLine()) != null)
                sb.append(line);
        } finally {
            if(reader != null)
                reader.close();
        }
        return sb.toString();
    }
   
    /**
     * Utility method to print out a dom.
     */
    protected void print( Document dom ) throws Exception {
        TransformerFactory txFactory = TransformerFactory.newInstance();
        try {
            txFactory.setAttribute("{http://xml.apache.org/xalan}indent-number", new Integer(2));
        } catch(Exception e) {
            // some
        }
       
        Transformer tx = txFactory.newTransformer();
        tx.setOutputProperty(OutputKeys.METHOD,"xml");
        tx.setOutputProperty( OutputKeys.INDENT, "yes" );
         
        tx.transform( new DOMSource( dom ), new StreamResult(new OutputStreamWriter(System.out, "utf-8") ));
    }

    /**
     * Utility method to print out the contents of an input stream.
     */
    protected void print( InputStream in ) throws Exception {
        BufferedReader r = new BufferedReader( new InputStreamReader( in ) );
        String line = null;
        while( (line = r.readLine()) != null ) {
            System.out.println( line );
        }
    }
   
    /**
     * Utility method to print out the contents of a json object.
     */
    protected void print( JSON json ) {
        System.out.println(json.toString(2));
    }
   
    /**
     * Convenience method for element.getElementsByTagName() to return the
     * first element in the resulting node list.
     */
    protected Element getFirstElementByTagName( Element element, String name ) {
        NodeList elements = element.getElementsByTagName(name);
        if ( elements.getLength() > 0 ) {
            return (Element) elements.item(0);
        }
       
        return null;
    }
   
    /**
     * Convenience method for element.getElementsByTagName() to return the
     * first element in the resulting node list.
     */
    protected Element getFirstElementByTagName( Document dom, String name ) {
        return getFirstElementByTagName( dom.getDocumentElement(), name );
    }
   
    /*
     * Helper method to create the kvp params from the query string.
     */
    private void kvp(MockHttpServletRequest request, String path) {
        int index = path.indexOf('?');

        if (index == -1) {
            return;
        }

        String queryString = path.substring(index + 1);
        StringTokenizer st = new StringTokenizer(queryString, "&");

        while (st.hasMoreTokens()) {
            String token = st.nextToken();
            String[] keyValuePair = token.split("=");
           
            //check for any special characters
            if ( keyValuePair.length > 1 ) {
                //replace any equals or & characters
              try {
                // if this one does not work first check if the url encoded content is really
                // properly encoded. I had good success with this: http://meyerweb.com/eric/tools/dencoder/
                keyValuePair[1] = URLDecoder.decode(keyValuePair[1], "ISO-8859-1");
              } catch(UnsupportedEncodingException e) {
                throw new RuntimeException("Totally unexpected... is your JVM busted?", e);
              }
               
            }
            request.setupAddParameter(keyValuePair[0], keyValuePair.length > 1 ?  keyValuePair[1]: "");
        }
    }

    private MockHttpServletResponse dispatch( HttpServletRequest request ) throws Exception {
        MockHttpServletResponse response = new MockHttpServletResponse() {
            public void setCharacterEncoding( String encoding ) {
                   
            }
        };

        dispatch(request, response);
        return response;
    }
    private void dispatch(HttpServletRequest request, HttpServletResponse response) throws Exception{
        //create an instance of the spring dispatcher
        ServletContext context = applicationContext.getServletContext();
       
        MockServletConfig config = new MockServletConfig();
        config.setServletContext(context);
        config.setServletName("dispatcher");
       
        DispatcherServlet dispatcher = new DispatcherServlet();
       
        dispatcher.setContextConfigLocation(GeoServerAbstractTestSupport.class.getResource("dispatcher-servlet.xml").toString());
        dispatcher.init(config);
       
       
        //look up the handler
//        Dispatcher dispatcher =
//                (Dispatcher) applicationContext.getBean( "dispatcher" );
        //dispatcher.setApplicationContext( getGeoServer().getApplicationContext() );
       
        //excute the pre handler step
        Collection interceptors =
            GeoServerExtensions.extensions(HandlerInterceptor.class, applicationContext );
        for ( Iterator i = interceptors.iterator(); i.hasNext(); ) {
            HandlerInterceptor interceptor = (HandlerInterceptor) i.next();
            interceptor.preHandle( request, response, dispatcher );
        }
       
        //execute
        //dispatcher.handleRequest( request, response );
        dispatcher.service(request, response);
       
        //execute the post handler step
        for ( Iterator i = interceptors.iterator(); i.hasNext(); ) {
            HandlerInterceptor interceptor = (HandlerInterceptor) i.next();
            interceptor.postHandle( request, response, dispatcher, null );
        }
    }

    /**
     * Assert that a GET request to a path will have a particular status code for the response.
     * @param code the number of the HTTP status code that is expected
     * @param path the path to which a GET request should be made, without the protocol, server and servlet context.
     * For example, to make a request to "http://localhost:8080/geoserver/ows" the path would be "ows"
     *
     * @throws Exception on test failure
     */
    protected void assertStatusCodeForGet(int code, String path) throws Exception{
        assertStatusCodeForRequest(code, "GET", path, "", "");
    }

    /**
     * Assert that a POST request to a path will have a particular status code for the response.
     * @param code the number of the HTTP status code that is expected
     * @param path the path to which a POST request should be made, without the protocol, server and servlet context.
     * For example, to make a request to "http://localhost:8080/geoserver/ows" the path would be "ows"
     * @param body the body to send with the request. May be empty, but must not be null.
     * @param type the mimetype to report for the body
     *
     * @throws Exception on test failure
     */
    protected void assertStatusCodeForPost(int code, String path, String body, String type) throws Exception {
        assertStatusCodeForRequest(code, "POST", path, body, type);
    }

    /**
     * Assert that a PUT request to a path will have a particular status code for the response.
     * @param code the number of the HTTP status code that is expected
     * @param path the path to which a PUT request should be made, without the protocol, server and servlet context.
     * For example, to make a request to "http://localhost:8080/geoserver/ows" the path would be "ows"
     * @param body the body to send with the request. May be empty, but must not be null.
     * @param type the mimetype to report for the body
     *
     * @throws Exception on test failure
     */
    protected void assertStatusCodeForPut(int code, String path, String body, String type) throws Exception {
        assertStatusCodeForRequest(code, "PUT", path, body, type);
    }

    /**
     * Assert that an HTTP request will have a particular status code for the response.
     * @param code the number of the HTTP status code that is expected
     * @param method the HTTP method for the request (eg, GET, PUT)
     * @param path the path for the request, excluding the protocol, server, port, and servlet context.
     * For example, to make a request to "http://localhost:8080/geoserver/ows" the path would be "ows"
     * @param body the body for the request.  May be empty, but must not be null.
     * @param type the mimetype for the request.
     */
    protected void assertStatusCodeForRequest(int code, String method, String path, String body, String type) throws Exception {
        MockHttpServletRequest request = createRequest(path);
        request.setMethod(method);
        request.setBodyContent(body);
        request.setContentType(type);

        CodeExpectingHttpServletResponse response = new CodeExpectingHttpServletResponse(new MockHttpServletResponse());
        dispatch(request, response);
        assertEquals(code, response.getErrorCode());
    }

    public static class GeoServerMockHttpServletRequest extends MockHttpServletRequest {
        private byte[] myBody;
       
        @Override
        public void setBodyContent(byte[] body) {
            myBody = body;
        }
       
        @Override
        public void setBodyContent(String body) {
            myBody = body.getBytes();
        }
       
        public ServletInputStream getInputStream(){
            return new GeoServerMockServletInputStream(myBody);
        }
    }

    private static class GeoServerMockServletInputStream extends ServletInputStream {
        private byte[] myBody;
        private int myOffset = 0;
        private int myMark = -1;

        public GeoServerMockServletInputStream(byte[] body){
            myBody = body;
        }
       
        public int available() {
            return myBody.length - myOffset;
        }

        public void close(){}

        public void mark(int readLimit){
            myMark = myOffset;
        }
       
        public void reset() {
            if (myMark < 0 || myMark >= myBody.length){
                throw new IllegalStateException("Can't reset when no mark was set.");
            }
           
            myOffset = myMark;
        }

        public boolean markSupported(){ return true; }

            public int read(){
                byte[] b = new byte[1];
                return read(b, 0, 1) == -1 ? -1 : b[0];
            }

        public int read(byte[] b){
            return read(b, 0, b.length);
        }

        public int read(byte[] b, int offset, int length){
            int realOffset = offset + myOffset;
            int i;

            if ( realOffset >= myBody.length ) {
                return -1;
            }
            for (i = 0; (i < length) && (i + myOffset < myBody.length); i++){
                b[offset + i] = myBody[myOffset + i];
            }

            myOffset += i;

            return i;
        }

        public int readLine(byte[] b, int offset, int length){
            int realOffset = offset + myOffset;
            int i;

            for (i = 0; (i < length) && (i + myOffset < myBody.length); i++){
                b[offset + i] = myBody[myOffset + i];
                if (myBody[myOffset + i] == '\n') break;
            }

            myOffset += i;

            return i;
        }
    }
}
TOP

Related Classes of org.geoserver.test.GeoServerAbstractTestSupport$GeoServerMockServletInputStream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.