org.geoserver.rest.catalog.StyleControllerTest.java Source code

Java tutorial

Introduction

Here is the source code for org.geoserver.rest.catalog.StyleControllerTest.java

Source

/* (c) 2017 Open Source Geospatial Foundation - all rights reserved
 * This code is licensed under the GPL 2.0 license, available at the root
 * application directory.
 */
package org.geoserver.rest.catalog;

import net.sf.json.JSON;
import net.sf.json.JSONObject;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.custommonkey.xmlunit.XMLUnit;
import org.custommonkey.xmlunit.XpathEngine;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.CatalogFacade;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.PropertyStyleHandler;
import org.geoserver.catalog.SLDHandler;
import org.geoserver.catalog.StyleInfo;
import org.geoserver.catalog.Styles;
import org.geoserver.data.test.SystemTestData;
import org.geoserver.data.test.TestData;
import org.geoserver.platform.GeoServerResourceLoader;
import org.geoserver.platform.resource.Resource;
import org.geoserver.rest.RestBaseController;
import org.geotools.data.DataUtilities;
import org.geotools.styling.Style;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.URL;
import java.util.List;
import java.util.Properties;

import static org.custommonkey.xmlunit.XMLAssert.assertXpathEvaluatesTo;
import static org.custommonkey.xmlunit.XMLAssert.assertXpathExists;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.Matchers.endsWith;
import static org.junit.Assert.*;

/**
 * Just ripped these tests from the existing rest test
 */
public class StyleControllerTest extends CatalogRESTTestSupport {

    @Before
    public void removeStyles() throws IOException {
        removeStyle("gs", "foo");
        removeStyle(null, "foo");
    }

    @Before
    public void addPondsStyle() throws IOException {
        getTestData().addStyle(SystemTestData.PONDS.getLocalPart(), getCatalog());
    }

    @Before
    public void restoreLayers() throws IOException {
        revertLayer(SystemTestData.BASIC_POLYGONS);
    }

    @Test
    public void testGetAllAsXML() throws Exception {
        Document dom = getAsDOM(RestBaseController.ROOT_PATH + "/styles.xml");

        List<StyleInfo> styles = catalog.getStyles();
        assertXpathEvaluatesTo("" + styles.size(), "count(//style)", dom);
    }

    @Test
    public void testGetAllASJSON() throws Exception {
        JSON json = getAsJSON(RestBaseController.ROOT_PATH + "/styles.json");

        List<StyleInfo> styles = catalog.getStyles();
        assertEquals(styles.size(), ((JSONObject) json).getJSONObject("styles").getJSONArray("style").size());
    }

    @Test
    public void testGetAllAsHTML() throws Exception {
        Document dom = getAsDOM(RestBaseController.ROOT_PATH + "/styles.html");
        print(dom);

        List<StyleInfo> styles = catalog.getStylesByWorkspace(CatalogFacade.NO_WORKSPACE);
        NodeList links = xp.getMatchingNodes("//html:a", dom);

        for (int i = 0; i < styles.size(); i++) {
            StyleInfo s = styles.get(i);
            Element link = (Element) links.item(i);

            final String href = link.getAttribute("href");
            assertTrue("Expected href to bed with " + s.getName() + ".html but was " + href,
                    href.endsWith(s.getName() + ".html"));
        }
    }

    @Test
    public void testGetAllFromWorkspace() throws Exception {
        Document dom = getAsDOM(RestBaseController.ROOT_PATH + "/workspaces/gs/styles.xml");
        assertEquals("styles", dom.getDocumentElement().getNodeName());

        assertXpathEvaluatesTo("0", "count(//style)", dom);

        addStyleToWorkspace("foo");

        dom = getAsDOM(RestBaseController.ROOT_PATH + "/workspaces/gs/styles.xml");
        assertEquals("styles", dom.getDocumentElement().getNodeName());

        assertXpathEvaluatesTo("1", "count(//style)", dom);
        assertXpathExists("//style/name[text() = 'foo']", dom);
    }

    void addStyleToWorkspace(String name) {
        Catalog cat = getCatalog();
        StyleInfo s = cat.getFactory().createStyle();
        s.setName(name);
        s.setFilename(name + ".sld");
        s.setWorkspace(cat.getWorkspaceByName("gs"));
        cat.add(s);
    }

    @Test
    public void testGetAsXML() throws Exception {
        Document dom = getAsDOM(RestBaseController.ROOT_PATH + "/styles/Ponds.xml");

        assertEquals("style", dom.getDocumentElement().getNodeName());
        assertXpathEvaluatesTo("Ponds", "/style/name", dom);
        assertXpathEvaluatesTo("Ponds.sld", "/style/filename", dom);
    }

    @Test
    public void testGetAsJSON() throws Exception {
        JSON json = getAsJSON(RestBaseController.ROOT_PATH + "/styles/Ponds.json");

        JSONObject style = ((JSONObject) json).getJSONObject("style");
        assertEquals("Ponds", style.get("name"));
        assertEquals("Ponds.sld", style.get("filename"));
    }

    @Test
    public void testGetWrongStyle() throws Exception {
        // Parameters for the request
        String ws = "gs";
        String style = "foooooo";
        // Request path
        String requestPath = RestBaseController.ROOT_PATH + "/styles/" + style + ".html";
        String requestPath2 = RestBaseController.ROOT_PATH + "/workspaces/" + ws + "/styles/" + style + ".html";
        // Exception path
        String exception = "No such style: " + style;
        String exception2 = "No such style " + style + " in workspace " + ws;

        // CASE 1: No workspace set

        // First request should thrown an exception
        MockHttpServletResponse response = getAsServletResponse(requestPath);
        assertEquals(404, response.getStatus());
        assertTrue(response.getContentAsString().contains(exception));

        // Same request with ?quietOnNotFound should not throw an exception
        response = getAsServletResponse(requestPath + "?quietOnNotFound=true");
        assertEquals(404, response.getStatus());
        assertFalse(response.getContentAsString().contains(exception));
        // No exception thrown
        assertTrue(response.getContentAsString().isEmpty());

        // CASE 2: workspace set

        // First request should thrown an exception
        response = getAsServletResponse(requestPath2);
        assertEquals(404, response.getStatus());
        assertTrue(response.getContentAsString().contains(exception2));

        // Same request with ?quietOnNotFound should not throw an exception
        response = getAsServletResponse(requestPath2 + "?quietOnNotFound=true");
        assertEquals(404, response.getStatus());
        assertFalse(response.getContentAsString().contains(exception2));
        // No exception thrown
        assertTrue(response.getContentAsString().isEmpty());
    }

    @Test
    public void testGetAsSLD() throws Exception {
        Document dom = getAsDOM(RestBaseController.ROOT_PATH + "/styles/Ponds.sld");

        assertEquals("StyledLayerDescriptor", dom.getDocumentElement().getNodeName());
    }

    @Test
    public void testGetFromWorkspace() throws Exception {
        MockHttpServletResponse resp = getAsServletResponse(
                RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo.xml");
        assertEquals(404, resp.getStatus());

        addStyleToWorkspace("foo");

        resp = getAsServletResponse(RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo.xml");
        assertEquals(200, resp.getStatus());

        Document dom = getAsDOM(RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo.xml");
        assertXpathEvaluatesTo("foo", "/style/name", dom);
        assertXpathEvaluatesTo("gs", "/style/workspace/name", dom);
    }

    String newSLDXML() {
        return "<sld:StyledLayerDescriptor xmlns:sld='http://www.opengis.net/sld'>" + "<sld:NamedLayer>"
                + "<sld:Name>foo</sld:Name>" + "<sld:UserStyle>" + "<sld:Name>foo</sld:Name>"
                + "<sld:FeatureTypeStyle>" + "<sld:Name>foo</sld:Name>" + "</sld:FeatureTypeStyle>"
                + "</sld:UserStyle>" + "</sld:NamedLayer>" + "</sld:StyledLayerDescriptor>";
    }

    @Test
    public void testPostAsSLD() throws Exception {
        String xml = newSLDXML();

        MockHttpServletResponse response = postAsServletResponse(RestBaseController.ROOT_PATH + "/styles", xml,
                SLDHandler.MIMETYPE_10);
        assertEquals(201, response.getStatus());
        assertNotNull(response.getHeader("Location"));
        assertTrue(response.getHeader("Location").endsWith("/styles/foo"));

        assertNotNull(catalog.getStyleByName("foo"));
    }

    @Test
    public void testPostExternalEntityAsSLD() throws Exception {
        String xml = IOUtils.toString(TestData.class.getResource("externalEntities.sld"), "UTF-8");

        MockHttpServletResponse response = postAsServletResponse(RestBaseController.ROOT_PATH + "/styles", xml,
                SLDHandler.MIMETYPE_10);
        assertEquals(500, response.getStatus());
        String message = response.getContentAsString();
        assertThat(message, containsString("Entity resolution disallowed"));
        assertThat(message, containsString("/this/file/does/not/exist"));
    }

    @Test
    public void testPostAsSLDToWorkspace() throws Exception {
        assertNull(catalog.getStyleByName("gs", "foo"));

        String xml = newSLDXML();

        MockHttpServletResponse response = postAsServletResponse(
                RestBaseController.ROOT_PATH + "/workspaces/gs/styles", xml, SLDHandler.MIMETYPE_10);
        assertEquals(201, response.getStatus());
        assertNotNull(response.getHeader("Location"));
        assertTrue(response.getHeader("Location").endsWith("/workspaces/gs/styles/foo"));

        assertNotNull(catalog.getStyleByName("gs", "foo"));

        GeoServerResourceLoader rl = getResourceLoader();
        assertNotNull(rl.find("workspaces", "gs", "styles", "foo.sld"));
    }

    @Test
    public void testPostAsSLDWithName() throws Exception {
        String xml = newSLDXML();

        MockHttpServletResponse response = postAsServletResponse(RestBaseController.ROOT_PATH + "/styles?name=bar",
                xml, SLDHandler.MIMETYPE_10);
        assertEquals(201, response.getStatus());
        assertNotNull(response.getHeader("Location"));
        assertTrue(response.getHeader("Location").endsWith("/styles/bar"));

        assertNotNull(catalog.getStyleByName("bar"));
    }

    @Test
    public void testStyleWithSpaceInName() throws Exception {
        String xml = newSLDXML();

        MockHttpServletResponse response = postAsServletResponse(
                RestBaseController.ROOT_PATH + "/styles?name=Default%20Styler", xml, SLDHandler.MIMETYPE_10);
        assertEquals(201, response.getStatus());
        assertNotNull(response.getHeader("Location"));
        assertThat(response.getHeader("Location"), endsWith("/styles/Default%20Styler"));

        assertNotNull(catalog.getStyleByName("Default Styler"));

        // now delete it, using a + instead of %20, the old code supported it
        response = deleteAsServletResponse(RestBaseController.ROOT_PATH + "/styles/Default+Styler");
        assertEquals(200, response.getStatus());
    }

    @Test
    public void testPostToWorkspace() throws Exception {
        Catalog cat = getCatalog();
        assertNull(cat.getStyleByName("gs", "foo"));

        String xml = "<style>" + "<name>foo</name>" + "<filename>foo.sld</filename>" + "</style>";
        MockHttpServletResponse response = postAsServletResponse(
                RestBaseController.ROOT_PATH + "/workspaces/gs/styles", xml);
        assertEquals(201, response.getStatus());
        assertNotNull(cat.getStyleByName("gs", "foo"));
    }

    @Test
    public void testPut() throws Exception {
        StyleInfo style = catalog.getStyleByName("Ponds");
        assertEquals("Ponds.sld", style.getFilename());

        String xml = "<style>" + "<name>Ponds</name>" + "<filename>Forests.sld</filename>" + "</style>";

        MockHttpServletResponse response = putAsServletResponse(RestBaseController.ROOT_PATH + "/styles/Ponds",
                xml.getBytes(), "text/xml");
        assertEquals(200, response.getStatus());

        style = catalog.getStyleByName("Ponds");
        assertEquals("Forests.sld", style.getFilename());
    }

    @Test
    public void testPutAsSLD() throws Exception {
        String xml = newSLDXML();

        MockHttpServletResponse response = putAsServletResponse(RestBaseController.ROOT_PATH + "/styles/Ponds", xml,
                SLDHandler.MIMETYPE_10);
        assertEquals(200, response.getStatus());

        Style s = catalog.getStyleByName("Ponds").getStyle();
        ByteArrayOutputStream out = new ByteArrayOutputStream();

        SLDHandler handler = new SLDHandler();
        handler.encode(Styles.sld(s), SLDHandler.VERSION_10, false, out);
        xml = new String(out.toByteArray());
        assertTrue(xml.contains("<sld:Name>foo</sld:Name>"));
    }

    @Test
    public void testPutAsSLDWithExtension() throws Exception {
        String xml = newSLDXML();

        MockHttpServletResponse response = putAsServletResponse(RestBaseController.ROOT_PATH + "/styles/Ponds.sld",
                xml, SLDHandler.MIMETYPE_10);
        assertEquals(200, response.getStatus());

        Style s = catalog.getStyleByName("Ponds").getStyle();
        ByteArrayOutputStream out = new ByteArrayOutputStream();

        SLDHandler handler = new SLDHandler();
        handler.encode(Styles.sld(s), SLDHandler.VERSION_10, false, out);
        xml = new String(out.toByteArray());
        assertTrue(xml.contains("<sld:Name>foo</sld:Name>"));
    }

    @Test
    public void testRawPutAsSLD() throws Exception {
        String xml = newSLDXML();

        MockHttpServletResponse response = putAsServletResponse(
                RestBaseController.ROOT_PATH + "/styles/Ponds?raw=true", xml, SLDHandler.MIMETYPE_10);
        assertEquals(200, response.getStatus());

        Style s = catalog.getStyleByName("Ponds").getStyle();
        ByteArrayOutputStream out = new ByteArrayOutputStream();

        SLDHandler handler = new SLDHandler();
        handler.encode(Styles.sld(s), SLDHandler.VERSION_10, false, out);
        xml = new String(out.toByteArray());
        assertTrue(xml.contains("<sld:Name>foo</sld:Name>"));
    }

    @Test
    public void testRawPutAsInvalidSLD() throws Exception {
        String xml = "This is not valid SLD";

        MockHttpServletResponse response = putAsServletResponse(
                RestBaseController.ROOT_PATH + "/styles/Ponds?raw=true", xml, SLDHandler.MIMETYPE_10);
        assertEquals(200, response.getStatus());

        StyleInfo styleInfo = catalog.getStyleByName("Ponds");
        String fileName = styleInfo.getFilename();

        GeoServerResourceLoader resources = getGeoServer().getCatalog().getResourceLoader();

        Resource resource = resources.get("styles/" + fileName);
        String content = new String(resource.getContents());

        assertFalse("replaced", content.contains("<sld:Name>foo</sld:Name>"));
        assertTrue("replaced", content.contains("not valid"));
    }

    @Test
    public void testPutToWorkspace() throws Exception {
        testPostToWorkspace();

        Catalog cat = getCatalog();
        assertEquals("foo.sld", cat.getStyleByName("gs", "foo").getFilename());

        String xml = "<style>" + "<filename>bar.sld</filename>" + "</style>";

        MockHttpServletResponse response = putAsServletResponse(
                RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo", xml, "application/xml");
        assertEquals(200, response.getStatus());
        assertEquals("bar.sld", cat.getStyleByName("gs", "foo").getFilename());
    }

    @Test
    public void testPutToWorkspaceChangeWorkspace() throws Exception {
        testPostToWorkspace();

        String xml = "<style>" + "<workspace>cite</workspace>" + "</style>";

        MockHttpServletResponse response = putAsServletResponse(
                RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo", xml, "application/xml");
        assertEquals(403, response.getStatus());
    }

    @Test
    public void testStyleNotFoundGloballyWhenInWorkspace() throws Exception {
        testPostToWorkspace();

        Catalog cat = getCatalog();
        assertEquals("foo.sld", cat.getStyleByName("gs", "foo").getFilename());

        String xml = "<style>" + "<filename>bar.sld</filename>" + "</style>";

        MockHttpServletResponse response = putAsServletResponse(
                RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo", xml, "application/xml");
        assertEquals(200, response.getStatus());
        response = putAsServletResponse(RestBaseController.ROOT_PATH + "/styles/gs:foo", xml, "application/xml");
        assertEquals(500, response.getStatus());
    }

    @Test
    public void testDelete() throws Exception {
        String xml = "<style>" + "<name>dummy</name>" + "<filename>dummy.sld</filename>" + "</style>";
        post(RestBaseController.ROOT_PATH + "/styles", xml, "text/xml");
        assertNotNull(catalog.getStyleByName("dummy"));

        MockHttpServletResponse response = deleteAsServletResponse(RestBaseController.ROOT_PATH + "/styles/dummy");
        assertEquals(200, response.getStatus());

        assertNull(catalog.getStyleByName("dummy"));
    }

    @Test
    public void testDeleteWithLayerReference() throws Exception {
        assertNotNull(catalog.getStyleByName("Ponds"));

        MockHttpServletResponse response = deleteAsServletResponse(RestBaseController.ROOT_PATH + "/styles/Ponds");
        assertEquals(403, response.getStatus());

        assertNotNull(catalog.getStyleByName("Ponds"));
    }

    @Test
    public void testDeleteWithLayerReferenceAndRecurse() throws Exception {
        assertNotNull(catalog.getStyleByName("Ponds"));

        MockHttpServletResponse response = deleteAsServletResponse(
                RestBaseController.ROOT_PATH + "/styles/Ponds?recurse=true");
        assertEquals(200, response.getStatus());

        assertNull(catalog.getStyleByName("Ponds"));
    }

    @Test
    public void testDeleteWithoutPurge() throws Exception {
        String xml = newSLDXML();

        MockHttpServletResponse response = postAsServletResponse(RestBaseController.ROOT_PATH + "/styles", xml,
                SLDHandler.MIMETYPE_10);
        assertNotNull(catalog.getStyleByName("foo"));

        //ensure the style not deleted on disk
        assertTrue(new File(getDataDirectory().findStyleDir(), "foo.sld").exists());

        response = deleteAsServletResponse(RestBaseController.ROOT_PATH + "/styles/foo");
        assertEquals(200, response.getStatus());

        //ensure the style deleted on disk but backed up
        assertFalse(new File(getDataDirectory().findStyleDir(), "foo.sld").exists());
        assertTrue(new File(getDataDirectory().findStyleDir(), "foo.sld.bak").exists());
    }

    @Test
    public void testDeleteWithPurge() throws Exception {
        String xml = newSLDXML();

        MockHttpServletResponse response = postAsServletResponse(RestBaseController.ROOT_PATH + "/styles", xml,
                SLDHandler.MIMETYPE_10);
        assertNotNull(catalog.getStyleByName("foo"));

        //ensure the style not deleted on disk
        assertTrue(new File(getDataDirectory().findStyleDir(), "foo.sld").exists());

        response = deleteAsServletResponse(RestBaseController.ROOT_PATH + "/styles/foo?purge=true");
        assertEquals(200, response.getStatus());

        //ensure the style not deleted on disk
        assertFalse(new File(getDataDirectory().findStyleDir(), "foo.sld").exists());
    }

    @Test
    public void testDeleteFromWorkspace() throws Exception {
        testPostToWorkspace();

        Catalog cat = getCatalog();
        assertNotNull(cat.getStyleByName("gs", "foo"));

        MockHttpServletResponse response = deleteAsServletResponse(
                RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo.xml");
        assertEquals(200, response.getStatus());

        assertNull(cat.getStyleByName("gs", "foo"));
    }

    @Test
    public void testDeleteFromWorkspaceWithPurge() throws Exception {
        testPostAsSLDToWorkspace();

        Catalog cat = getCatalog();
        assertNotNull(cat.getStyleByName("gs", "foo"));

        GeoServerResourceLoader rl = getResourceLoader();
        assertNotNull(rl.find("workspaces", "gs", "styles", "foo.sld"));

        MockHttpServletResponse response = deleteAsServletResponse(
                RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo?purge=true");
        assertEquals(200, response.getStatus());

        assertNull(cat.getStyleByName("gs", "foo"));
        assertNull(rl.find("workspaces", "gs", "styles", "foo.sld"));
    }

    @Test
    public void testGetAllByLayer() throws Exception {
        Document dom = getAsDOM(RestBaseController.ROOT_PATH + "/layers/cite:BasicPolygons/styles.xml");
        LayerInfo layer = catalog.getLayerByName("cite:BasicPolygons");

        assertXpathEvaluatesTo(layer.getStyles().size() + "", "count(//style)", dom);
    }

    @Test
    public void testPostByLayer() throws Exception {

        LayerInfo l = catalog.getLayerByName("cite:BasicPolygons");
        int nstyles = l.getStyles().size();

        String xml = "<style>" + "<name>Ponds</name>" + "</style>";
        MockHttpServletResponse response = postAsServletResponse(
                RestBaseController.ROOT_PATH + "/layers/cite:BasicPolygons/styles", xml, "text/xml");
        assertEquals(201, response.getStatus());

        LayerInfo l2 = catalog.getLayerByName("cite:BasicPolygons");
        assertEquals(nstyles + 1, l2.getStyles().size());

        assertTrue(l2.getStyles().contains(catalog.getStyleByName("Ponds")));
    }

    @Test
    public void testPostByLayerWithDefault() throws Exception {
        getTestData().addVectorLayer(SystemTestData.BASIC_POLYGONS, getCatalog());
        LayerInfo l = catalog.getLayerByName("cite:BasicPolygons");
        int nstyles = l.getStyles().size();

        String xml = "<style>" + "<name>Ponds</name>" + "</style>";
        MockHttpServletResponse response = postAsServletResponse(
                RestBaseController.ROOT_PATH + "/layers/cite:BasicPolygons/styles?default=true", xml, "text/xml");
        assertEquals(201, response.getStatus());

        LayerInfo l2 = catalog.getLayerByName("cite:BasicPolygons");
        assertEquals(nstyles + 1, l2.getStyles().size());
        assertEquals(catalog.getStyleByName("Ponds"), l2.getDefaultStyle());
    }

    @Test
    public void testPostByLayerExistingWithDefault() throws Exception {
        getTestData().addVectorLayer(SystemTestData.BASIC_POLYGONS, getCatalog());
        testPostByLayer();

        LayerInfo l = catalog.getLayerByName("cite:BasicPolygons");
        int nstyles = l.getStyles().size();

        String xml = "<style>" + "<name>Ponds</name>" + "</style>";
        MockHttpServletResponse response = postAsServletResponse(
                RestBaseController.ROOT_PATH + "/layers/cite:BasicPolygons/styles?default=true", xml, "text/xml");
        assertEquals(201, response.getStatus());

        LayerInfo l2 = catalog.getLayerByName("cite:BasicPolygons");
        assertEquals(nstyles, l2.getStyles().size());
        assertEquals(catalog.getStyleByName("Ponds"), l2.getDefaultStyle());
    }

    @Test
    @Ignore
    public void testPostAsPSL() throws Exception {
        Properties props = new Properties();
        props.put("type", "point");
        props.put("color", "ff0000");

        StringWriter out = new StringWriter();
        props.store(out, "comment!");

        MockHttpServletResponse response = postAsServletResponse(RestBaseController.ROOT_PATH + "/styles?name=foo",
                out.toString(), PropertyStyleHandler.MIMETYPE);
        assertEquals(201, response.getStatus());
        assertNotNull(response.getHeader("Location"));
        assertTrue(response.getHeader("Location").endsWith("/styles/foo"));

        assertNotNull(catalog.getStyleByName("foo"));

        Resource style = getDataDirectory().style(getCatalog().getStyleByName("foo"));
        InputStream in = style.in();

        props = new Properties();
        try {
            props.load(in);
            assertEquals("point", props.getProperty("type"));
        } finally {
            in.close();
        }

        in = style.in();
        try {
            out = new StringWriter();
            IOUtils.copy(in, out);
            assertFalse(out.toString().startsWith("#comment!"));
        } finally {
            in.close();
        }
    }

    @Test
    @Ignore
    public void testPostAsPSLRaw() throws Exception {
        Properties props = new Properties();
        props.put("type", "point");
        props.put("color", "ff0000");

        StringWriter out = new StringWriter();
        props.store(out, "comment!");

        MockHttpServletResponse response = postAsServletResponse(
                RestBaseController.ROOT_PATH + "/styles?name=foo&raw=true", out.toString(),
                PropertyStyleHandler.MIMETYPE);
        assertEquals(201, response.getStatus());
        assertNotNull(response.getHeader("Location"));
        assertTrue(response.getHeader("Location").endsWith("/styles/foo"));

        // check style on disk to ensure the exact contents was preserved
        Resource style = getDataDirectory().style(getCatalog().getStyleByName("foo"));
        try (InputStream in = style.in()) {
            out = new StringWriter();
            IOUtils.copy(in, out);
            assertTrue(out.toString().startsWith("#comment!"));
        }
    }

    @Test
    @Ignore
    public void testGetAsPSL() throws Exception {
        Properties props = new Properties();
        props.load(get(RestBaseController.ROOT_PATH + "/styles/Ponds.properties"));

        assertEquals("polygon", props.getProperty("type"));
    }

    @Test
    @Ignore
    public void testPutAsPSL() throws Exception {
        testPostAsPSL();

        Properties props = new Properties();
        props.put("type", "line");
        props.put("color", "00ff00");

        StringWriter out = new StringWriter();
        props.store(out, "comment!");

        MockHttpServletResponse response = putAsServletResponse(RestBaseController.ROOT_PATH + "/styles/foo",
                out.toString(), PropertyStyleHandler.MIMETYPE);
        assertEquals(200, response.getStatus());

        Resource style = getDataDirectory().style(getCatalog().getStyleByName("foo"));
        InputStream in = style.in();
        try {
            props = new Properties();
            props.load(in);
            assertEquals("line", props.getProperty("type"));
        } finally {
            in.close();
        }

        in = style.in();
        try {
            out = new StringWriter();
            IOUtils.copy(in, out);
            assertFalse(out.toString().startsWith("#comment!"));
        } finally {
            in.close();
        }
    }

    @Test
    @Ignore
    public void testPutAsPSLRaw() throws Exception {
        testPostAsPSL();

        Properties props = new Properties();
        props.put("type", "line");
        props.put("color", "00ff00");

        StringWriter out = new StringWriter();
        props.store(out, "comment!");

        MockHttpServletResponse response = putAsServletResponse(
                RestBaseController.ROOT_PATH + "/styles/foo?raw=true", out.toString(),
                PropertyStyleHandler.MIMETYPE);
        assertEquals(200, response.getStatus());

        Resource style = getDataDirectory().style(getCatalog().getStyleByName("foo"));
        InputStream in = style.in();
        try {
            props = new Properties();
            props.load(in);
            assertEquals("line", props.getProperty("type"));
        } finally {
            in.close();
        }

        in = style.in();
        try {
            out = new StringWriter();
            IOUtils.copy(in, out);
            assertTrue(out.toString().startsWith("#comment!"));
        } finally {
            in.close();
        }
    }

    @Test
    public void testPostAsSE() throws Exception {
        String xml = "<StyledLayerDescriptor xmlns=\"http://www.opengis.net/sld\" "
                + "       xmlns:se=\"http://www.opengis.net/se\" version=\"1.1.0\"> " + " <NamedLayer> "
                + "  <UserStyle> " + "   <se:Name>UserSelection</se:Name> " + "   <se:FeatureTypeStyle> "
                + "    <se:Rule> " + "     <se:PolygonSymbolizer> " + "      <se:Fill> "
                + "       <se:SvgParameter name=\"fill\">#FF0000</se:SvgParameter> " + "      </se:Fill> "
                + "     </se:PolygonSymbolizer> " + "    </se:Rule> " + "   </se:FeatureTypeStyle> "
                + "  </UserStyle> " + " </NamedLayer> " + "</StyledLayerDescriptor>";

        MockHttpServletResponse response = postAsServletResponse(RestBaseController.ROOT_PATH + "/styles?name=foo",
                xml, SLDHandler.MIMETYPE_11);
        assertEquals(201, response.getStatus());
        assertNotNull(response.getHeader("Location"));
        assertTrue(response.getHeader("Location").endsWith("/styles/foo"));

        StyleInfo style = catalog.getStyleByName("foo");
        assertNotNull(style);

        assertEquals("sld", style.getFormat());
        assertEquals(SLDHandler.VERSION_11, style.getFormatVersion());
    }

    @Test
    public void testPostToWorkspaceSLDPackage() throws Exception {
        Catalog cat = getCatalog();
        assertNull(cat.getStyleByName("gs", "foo"));

        URL zip = getClass().getResource("test-data/foo.zip");
        byte[] bytes = FileUtils.readFileToByteArray(DataUtilities.urlToFile(zip));

        MockHttpServletResponse response = postAsServletResponse(
                RestBaseController.ROOT_PATH + "/workspaces/gs/styles", bytes, "application/zip");
        assertEquals(201, response.getStatus());
        assertNotNull(cat.getStyleByName("gs", "foo"));

        Document d = getAsDOM(RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo.sld");

        assertEquals("StyledLayerDescriptor", d.getDocumentElement().getNodeName());
        XpathEngine engine = XMLUnit.newXpathEngine();
        NodeList list = engine.getMatchingNodes(
                "//sld:StyledLayerDescriptor/sld:NamedLayer/sld:UserStyle/sld:FeatureTypeStyle/sld:Rule/sld:PointSymbolizer/sld:Graphic/sld:ExternalGraphic/sld:OnlineResource",
                d);
        assertEquals(1, list.getLength());
        Element onlineResource = (Element) list.item(0);
        assertEquals("gear.png", onlineResource.getAttribute("xlink:href"));
        assertNotNull(getCatalog().getResourceLoader().find("workspaces/gs/styles/gear.png"));
        assertNotNull(getCatalog().getResourceLoader().find("workspaces/gs/styles/foo.sld"));
    }

    @Test
    public void testPostWithExternalEntities() throws Exception {
        URL zip = getClass().getResource("test-data/externalEntities.zip");
        byte[] bytes = FileUtils.readFileToByteArray(DataUtilities.urlToFile(zip));

        MockHttpServletResponse response = postAsServletResponse(
                RestBaseController.ROOT_PATH + "/workspaces/gs/styles", bytes, "application/zip");
        // expecting a failure with explanation
        assertEquals(400, response.getStatus());
        final String content = response.getContentAsString();
        assertThat(content, containsString("Entity resolution disallowed"));
        assertThat(content, containsString("/this/file/does/not/exist"));
    }

    @Test
    public void testPutToWorkspaceSLDPackage() throws Exception {
        testPostAsSLDToWorkspace();

        Catalog cat = getCatalog();
        assertNotNull(cat.getStyleByName("gs", "foo"));

        URL zip = getClass().getResource("test-data/foo.zip");
        byte[] bytes = FileUtils.readFileToByteArray(DataUtilities.urlToFile(zip));

        MockHttpServletResponse response = putAsServletResponse(
                RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo", bytes, "application/zip");
        assertEquals(200, response.getStatus());
        assertNotNull(cat.getStyleByName("gs", "foo"));

        Document d = getAsDOM(RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo.sld");

        assertEquals("StyledLayerDescriptor", d.getDocumentElement().getNodeName());
        XpathEngine engine = XMLUnit.newXpathEngine();
        NodeList list = engine.getMatchingNodes(
                "//sld:StyledLayerDescriptor/sld:NamedLayer/sld:UserStyle/sld:FeatureTypeStyle/sld:Rule/sld:PointSymbolizer/sld:Graphic/sld:ExternalGraphic/sld:OnlineResource",
                d);
        assertEquals(1, list.getLength());
        Element onlineResource = (Element) list.item(0);
        assertEquals("gear.png", onlineResource.getAttribute("xlink:href"));
        assertNotNull(getCatalog().getResourceLoader().find("workspaces/gs/styles/gear.png"));
        assertNotNull(getCatalog().getResourceLoader().find("workspaces/gs/styles/foo.sld"));
    }

    @Test
    public void testPostSLDPackage() throws Exception {
        Catalog cat = getCatalog();
        assertNull(cat.getStyleByName("foo"));

        URL zip = getClass().getResource("test-data/foo.zip");
        byte[] bytes = FileUtils.readFileToByteArray(DataUtilities.urlToFile(zip));

        MockHttpServletResponse response = postAsServletResponse(RestBaseController.ROOT_PATH + "/styles", bytes,
                "application/zip");
        assertEquals(201, response.getStatus());
        assertNotNull(cat.getStyleByName("foo"));

        Document d = getAsDOM(RestBaseController.ROOT_PATH + "/styles/foo.sld");

        assertEquals("StyledLayerDescriptor", d.getDocumentElement().getNodeName());
        XpathEngine engine = XMLUnit.newXpathEngine();
        NodeList list = engine.getMatchingNodes(
                "//sld:StyledLayerDescriptor/sld:NamedLayer/sld:UserStyle/sld:FeatureTypeStyle/sld:Rule/sld:PointSymbolizer/sld:Graphic/sld:ExternalGraphic/sld:OnlineResource",
                d);
        assertEquals(1, list.getLength());
        Element onlineResource = (Element) list.item(0);
        assertEquals("gear.png", onlineResource.getAttribute("xlink:href"));
        assertNotNull(getCatalog().getResourceLoader().find("styles/gear.png"));
        assertNotNull(getCatalog().getResourceLoader().find("styles/foo.sld"));
    }

    @Test
    public void testPutSLDPackage() throws Exception {
        testPostAsSLD();

        Catalog cat = getCatalog();
        assertNotNull(cat.getStyleByName("foo"));

        URL zip = getClass().getResource("test-data/foo.zip");
        byte[] bytes = FileUtils.readFileToByteArray(DataUtilities.urlToFile(zip));

        //@TODO i had to change this from foo.zip to just foo. see the long comments below
        MockHttpServletResponse response = putAsServletResponse(RestBaseController.ROOT_PATH + "/styles/foo", bytes,
                "application/zip");
        assertEquals(200, response.getStatus());
        assertNotNull(cat.getStyleByName("foo"));

        Document d = getAsDOM(RestBaseController.ROOT_PATH + "/styles/foo.sld");

        assertEquals("StyledLayerDescriptor", d.getDocumentElement().getNodeName());
        XpathEngine engine = XMLUnit.newXpathEngine();
        NodeList list = engine.getMatchingNodes(
                "//sld:StyledLayerDescriptor/sld:NamedLayer/sld:UserStyle/sld:FeatureTypeStyle/sld:Rule/sld:PointSymbolizer/sld:Graphic/sld:ExternalGraphic/sld:OnlineResource",
                d);
        assertEquals(1, list.getLength());
        Element onlineResource = (Element) list.item(0);
        assertEquals("gear.png", onlineResource.getAttribute("xlink:href"));
        assertNotNull(getCatalog().getResourceLoader().find("styles/gear.png"));
        assertNotNull(getCatalog().getResourceLoader().find("styles/foo.sld"));
    }

    /**
     * TODO I had to put this here BECAUSE:
     *
     * - The testPutSLDPackage test uses a *.zip URL
     * - BUT, put style does not support ZIP responses
     * - Spring interprets the .zip extension on the path as being a request for a zip response
     * - This fails, because there is no actual handler for a zip response on a style endpoint
     * - Unfortunately Spring only considers one of the Accept header or the path
     * - So the handler is never found
     *
     * this leaves us with a few options
     *
     * 1) Configure spring to prefer the accept header over the path. This would:
     *
     *   - Force future clients who depended on put/posting to zip endpoints to make sure their
     *     Accept header is correct.
     *   - Maybe more importantly it could potentially break other end points that depend on preferring
     *     the path extension.
     *
     * 2) Continue letting Spring prefer the path (which is really the right behavior for a REST api)
     *
     *   - Future clients would not be able to use an endpoint like .zip
     *   - But this is more REST-y
     *
     * 3) Write our own content negotiation strategy that allows for both.
     *
     *   - This is a pain in the ass.
     *   - Potentially difficult to recreate all default behavior + behavior needed to fix this test
     *     case
     *
     * @param path
     * @param body
     * @param contentType
     * @return
     * @throws Exception
     */
    protected MockHttpServletResponse putAsServletResponse(String path, byte[] body, String contentType,
            String accepts) throws Exception {

        MockHttpServletRequest request = createRequest(path);
        request.setMethod("PUT");
        request.setContentType(contentType);
        request.setContent(body);
        request.addHeader("Accept", accepts);
        request.addHeader("Content-type", contentType);

        return dispatch(request);
    }
}