diff --git a/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java b/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java index 35bddec..f31c4fd 100644 --- a/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java +++ b/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java @@ -29,6 +29,7 @@ import it.geosolutions.geoserver.rest.decoder.RESTCoverageStore; import it.geosolutions.geoserver.rest.decoder.utils.NameLinkElem; import it.geosolutions.geoserver.rest.encoder.GSBackupEncoder; import it.geosolutions.geoserver.rest.encoder.GSLayerEncoder; +import it.geosolutions.geoserver.rest.encoder.GSLayerGroupEncoder; import it.geosolutions.geoserver.rest.encoder.GSNamespaceEncoder; import it.geosolutions.geoserver.rest.encoder.GSResourceEncoder; import it.geosolutions.geoserver.rest.encoder.GSResourceEncoder.ProjectionPolicy; @@ -2150,12 +2151,20 @@ public class GeoServerRESTPublisher { /** * Remove a layer group. * + * @param workspace the layer group workspace. * @param name the layer group name. * @return true if succeeded. - */ - public boolean removeLayerGroup(String name) { + */ + public boolean removeLayerGroup(String workspace, String name) { + String url = restURL + "/rest"; + if (workspace == null) { + url += "/layergroups/" + name; + } else { + url += "/workspaces/" + workspace + "/layergroups/" + name; + } + try { - URL deleteUrl = new URL(restURL + "/rest/layergroups/" + name); + URL deleteUrl = new URL(url); boolean deleted = HTTPUtils.delete(deleteUrl.toExternalForm(), gsuser, gspass); if (!deleted) { if (LOGGER.isWarnEnabled()) @@ -2170,7 +2179,17 @@ public class GeoServerRESTPublisher { if (LOGGER.isErrorEnabled()) LOGGER.error(ex.getLocalizedMessage(), ex); return false; - } + } + } + + /** + * Remove a layer group. + * + * @param name the layer group name. + * @return true if succeeded. + */ + public boolean removeLayerGroup(String name) { + return removeLayerGroup(null, name); } /** @@ -2334,6 +2353,89 @@ public class GeoServerRESTPublisher { return sendResult != null; } + /** + * Create a new LayerGroup using the specified encoder + * + * @param name name of the layer group + * @param group group encoder + * @return true if operation was successful + */ + public boolean createLayerGroup(String name, GSLayerGroupEncoder group) { + return createLayerGroup(null, name, group); + } + + /** + * Create a new LayerGroup using the specified encoder + * + * @param workspace name of the workspace + * @param name name of the layer group + * @param group group encoder + * @return true if operation was successful + */ + public boolean createLayerGroup(String workspace, String name, GSLayerGroupEncoder group) { + String url = restURL + "/rest"; + if (workspace == null) { + url += "/layergroups/"; + } else { + group.setWorkspace(workspace); + url += "/workspaces/" + workspace + "/layergroups/"; + } + + group.setName(name); + + String sendResult = HTTPUtils.postXml(url, group.toString(), gsuser, gspass); + if (sendResult != null) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("LayerGroup successfully configured: " + name); + } + } else { + if (LOGGER.isWarnEnabled()) + LOGGER.warn("Error configuring LayerGroup " + name + " (" + sendResult + ")"); + } + + return sendResult != null; + } + + /** + * Update a LayerGroup using the specified encoder + * + * @param name name of the layer group + * @param group group encoder + * @return true if operation was successful + */ + public boolean configureLayerGroup(String name, GSLayerGroupEncoder group) { + return configureLayerGroup(null, name, group); + } + + /** + * Update a LayerGroup using the specified encoder + * + * @param workspace name of the workspace + * @param name name of the layer group + * @param group group encoder + * @return true if operation was successful + */ + public boolean configureLayerGroup(String workspace, String name, GSLayerGroupEncoder group) { + String url = restURL + "/rest"; + if (workspace == null) { + url += "/layergroups/" + name; + } else { + url += "/workspaces/" + workspace + "/layergroups/" + name; + } + + String sendResult = HTTPUtils.putXml(url, group.toString(), gsuser, gspass); + if (sendResult != null) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("LayerGroup successfully configured: " + name); + } + } else { + if (LOGGER.isWarnEnabled()) + LOGGER.warn("Error configuring LayerGroup " + name + " (" + sendResult + ")"); + } + + return sendResult != null; + } + /** * Configure an existent coverage in a given workspace and coverage store * diff --git a/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTReader.java b/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTReader.java index 2266a08..0cf9846 100644 --- a/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTReader.java +++ b/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTReader.java @@ -395,6 +395,12 @@ public class GeoServerRESTReader { //=== LAYERGROUPS //========================================================================== + /** + * Get summary info about all LayerGroups in the given workspace. + * + * @param workspace name of the workspace + * @return summary info about LayerGroups as a {@link RESTLayerGroupList} + */ public RESTLayerGroupList getLayerGroups(String workspace) { String url; if (workspace == null) { @@ -409,6 +415,13 @@ public class GeoServerRESTReader { return RESTLayerGroupList.build(load(url)); } + /** + * Get detailed info about a given LayerGroup. + * + * @param workspace name of the workspace + * @param name the name of the LayerGroup + * @return LayerGroup details as a {@link RESTLayerGroup} + */ public RESTLayerGroup getLayerGroup(String workspace, String name) { String url; if (workspace == null) { diff --git a/src/main/java/it/geosolutions/geoserver/rest/decoder/RESTLayerGroup.java b/src/main/java/it/geosolutions/geoserver/rest/decoder/RESTLayerGroup.java index 8ce3f95..a538c62 100644 --- a/src/main/java/it/geosolutions/geoserver/rest/decoder/RESTLayerGroup.java +++ b/src/main/java/it/geosolutions/geoserver/rest/decoder/RESTLayerGroup.java @@ -104,6 +104,14 @@ public class RESTLayerGroup { return rootElem.getChildText("mode"); } + public String getTitle() { + return rootElem.getChildText("title"); + } + + public String getAbstract() { + return rootElem.getChildText("abstractTxt"); + } + public String getRootLayer() { Element rootLayer = rootElem.getChild("rootLayer"); if (rootLayer != null) { diff --git a/src/main/java/it/geosolutions/geoserver/rest/encoder/GSLayerGroupEncoder.java b/src/main/java/it/geosolutions/geoserver/rest/encoder/GSLayerGroupEncoder.java new file mode 100755 index 0000000..09fb03c --- /dev/null +++ b/src/main/java/it/geosolutions/geoserver/rest/encoder/GSLayerGroupEncoder.java @@ -0,0 +1,123 @@ +/* + * GeoServer-Manager - Simple Manager Library for GeoServer + * + * Copyright (C) 2013 GeoSolutions S.A.S. + * http://www.geo-solutions.it + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package it.geosolutions.geoserver.rest.encoder; + +import it.geosolutions.geoserver.rest.encoder.utils.PropertyXMLEncoder; + +import org.jdom.Element; + +/** + * LayerGroup encoder for GeoServer < 2.3 + * + * @author Davide Savazzi (geo-solutions.it) + */ +public class GSLayerGroupEncoder extends PropertyXMLEncoder { + + protected Element nameElem; + protected Element workspaceElem; + protected Element boundsElem; + protected Element publishablesElem; + protected Element stylesElem; + + + public GSLayerGroupEncoder() { + super("layerGroup"); + } + + + public void setWorkspace(String workspace) { + workspaceElem = elem("workspace", elem("name", workspace)); + } + + public void setName(String name) { + nameElem = elem("name", name); + } + + public void addLayer(String layer) { + addLayer(layer, null); + } + + public void addLayer(String layer, String styleName) { + initPublishables("layers"); + + publishablesElem.addContent(elem("layer", elem("name", layer))); + + Element style = new Element("style"); + stylesElem.addContent(style); + if (styleName != null) { + style.addContent(elem("name", styleName)); + } + } + + public void setBounds(String crs, double minx, double maxx, double miny, double maxy) { + boundsElem = elem("bounds", + elem("minx", Double.toString(minx)), + elem("maxx", Double.toString(maxx)), + elem("miny", Double.toString(miny)), + elem("maxy", Double.toString(maxy)), + elem("crs", "class", "projected").setText(crs)); + } + + protected void initPublishables(String publishablesTag) { + if (publishablesElem == null) { + publishablesElem = new Element(publishablesTag); + } + + if (stylesElem == null) { + stylesElem = new Element("styles"); + } + } + + protected void addToRoot(Element ... elements) { + for (Element e : elements) { + if (e != null) { + getRoot().addContent(e); + } + } + } + + protected Element elem(String tag, String attributeName, String attributeValue) { + return new Element(tag).setAttribute(attributeName, attributeValue); + } + + protected Element elem(String tag, String text) { + return new Element(tag).setText(text); + } + + protected Element elem(String tag, Element ... children) { + Element parent = new Element(tag); + for (Element child : children) { + parent.addContent(child); + } + return parent; + } + + @Override + public String toString() { + addToRoot(nameElem, workspaceElem, boundsElem, publishablesElem, stylesElem); + return super.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/it/geosolutions/geoserver/rest/encoder/GSLayerGroupEncoder23.java b/src/main/java/it/geosolutions/geoserver/rest/encoder/GSLayerGroupEncoder23.java new file mode 100755 index 0000000..248ca30 --- /dev/null +++ b/src/main/java/it/geosolutions/geoserver/rest/encoder/GSLayerGroupEncoder23.java @@ -0,0 +1,110 @@ +/* + * GeoServer-Manager - Simple Manager Library for GeoServer + * + * Copyright (C) 2013 GeoSolutions S.A.S. + * http://www.geo-solutions.it + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package it.geosolutions.geoserver.rest.encoder; + +import java.util.HashSet; +import java.util.Set; + +import org.jdom.Element; + +/** + * LayerGroup encoder for GeoServer >= 2.3 + * + * @author Davide Savazzi (geo-solutions.it) + */ +public class GSLayerGroupEncoder23 extends GSLayerGroupEncoder { + + public static final String MODE_SINGLE = "SINGLE"; + public static final String MODE_NAMED = "NAMED"; + public static final String MODE_CONTAINER = "CONTAINER"; + public static final String MODE_EO = "EO"; + private static final Set modes; + static { + modes = new HashSet(); + modes.add(MODE_SINGLE); + modes.add(MODE_NAMED); + modes.add(MODE_CONTAINER); + modes.add(MODE_EO); + } + + private Element titleElem; + private Element abstractElem; + private Element modeElem; + private Element rootLayerElem; + private Element rootLayerStyleElem; + + public void setTitle(String title) { + titleElem = elem("title", title); + } + + public void setAbstract(String abstractTxt) { + abstractElem = elem("abstractTxt", abstractTxt); + } + + public void setMode(String mode) { + if (!modes.contains(mode)) { + throw new IllegalArgumentException("Invalid mode: " + mode); + } + + modeElem = elem("mode", mode); + } + + public void setRootLayer(String layer, String style) { + rootLayerElem = elem("rootLayer", elem("name", layer)); + rootLayerStyleElem = elem("rootLayerStyle", elem("name", style)); + } + + @Override + public void addLayer(String layer, String styleName) { + initPublishables("publishables"); + + publishablesElem.addContent( + new Element("published").setAttribute("type", "layer").addContent( + elem("name", layer))); + + Element style = new Element("style"); + stylesElem.addContent(style); + if (styleName != null) { + style.addContent(elem("name", styleName)); + } + } + + public void addLayerGroup(String group) { + initPublishables("publishables"); + + publishablesElem.addContent( + new Element("published").setAttribute("type", "layerGroup").addContent( + elem("name", group))); + + stylesElem.addContent(new Element("style")); + } + + @Override + public String toString() { + addToRoot(titleElem, abstractElem, modeElem, rootLayerElem, rootLayerStyleElem); + return super.toString(); + } +} \ No newline at end of file diff --git a/src/test/java/it/geosolutions/geoserver/rest/encoder/GSLayerGroupEncoderTest.java b/src/test/java/it/geosolutions/geoserver/rest/encoder/GSLayerGroupEncoderTest.java new file mode 100755 index 0000000..4c87ed9 --- /dev/null +++ b/src/test/java/it/geosolutions/geoserver/rest/encoder/GSLayerGroupEncoderTest.java @@ -0,0 +1,232 @@ +package it.geosolutions.geoserver.rest.encoder; + +import it.geosolutions.geoserver.rest.GeoserverRESTTest; +import it.geosolutions.geoserver.rest.decoder.RESTLayerGroup; +import it.geosolutions.geoserver.rest.decoder.RESTLayerList; +import it.geosolutions.geoserver.rest.decoder.RESTPublished; +import it.geosolutions.geoserver.rest.decoder.RESTPublishedList; +import it.geosolutions.geoserver.rest.decoder.utils.NameLinkElem; + +import org.junit.Test; + +public class GSLayerGroupEncoderTest extends GeoserverRESTTest { + + @Test + public void testCreateLayerGroup() throws Exception { + String groupName = "my-tasmania"; + + GSLayerGroupEncoder groupWriter = new GSLayerGroupEncoder(); + groupWriter.setBounds("EPSG:26713", 589425.93423656, 609518.6719560538, 4913959.224611808, 4928082.949945881); + groupWriter.addLayer("topp:tasmania_roads"); + groupWriter.addLayer("topp:tasmania_cities"); + assertTrue(publisher.createLayerGroup(groupName, groupWriter)); + try { + RESTLayerGroup groupReader = reader.getLayerGroup(groupName); + assertNull(groupReader.getWorkspace()); + assertEquals(groupName, groupReader.getName()); + + RESTPublishedList publishedList = groupReader.getPublishedList(); + if (publishedList != null) { + // GeoServer >= 2.3 + assertEquals(2, publishedList.size()); + for (RESTPublished published : publishedList) { + assertEquals("layer", published.getType()); + assertTrue("tasmania_roads".equals(published.getName()) || "tasmania_cities".equals(published.getName())); + } + } else { + RESTLayerList layerList = groupReader.getLayerList(); + assertEquals(2, layerList.size()); + for (NameLinkElem layer : layerList) { + assertTrue("tasmania_roads".equals(layer.getName()) || "tasmania_cities".equals(layer.getName())); + } + } + } finally { + assertTrue(publisher.removeLayerGroup(groupName)); + } + } + + @Test + public void testCreateLayerGroupInWorkspace() throws Exception { + String groupName = "my-tasmania-in-ws"; + + GSLayerGroupEncoder groupWriter = new GSLayerGroupEncoder(); + groupWriter.setBounds("EPSG:26713", 589425.93423656, 609518.6719560538, 4913959.224611808, 4928082.949945881); + groupWriter.addLayer("topp:tasmania_roads"); + groupWriter.addLayer("topp:tasmania_cities"); + assertTrue(publisher.createLayerGroup("topp", groupName, groupWriter)); + try { + RESTLayerGroup groupReader = reader.getLayerGroup("topp", groupName); + assertEquals("topp", groupReader.getWorkspace()); + assertEquals(groupName, groupReader.getName()); + + RESTPublishedList publishedList = groupReader.getPublishedList(); + if (publishedList != null) { + // GeoServer >= 2.3 + assertEquals(2, publishedList.size()); + for (RESTPublished published : publishedList) { + assertEquals("layer", published.getType()); + assertTrue("tasmania_roads".equals(published.getName()) || "tasmania_cities".equals(published.getName())); + } + } else { + RESTLayerList layerList = groupReader.getLayerList(); + assertEquals(2, layerList.size()); + for (NameLinkElem layer : layerList) { + assertTrue("tasmania_roads".equals(layer.getName()) || "tasmania_cities".equals(layer.getName())); + } + } + } finally { + assertTrue(publisher.removeLayerGroup("topp", groupName)); + } + } + + private void createTestLayerGroup(String workspace, String groupName) { + GSLayerGroupEncoder groupWriter = new GSLayerGroupEncoder(); + groupWriter.setBounds("EPSG:26713", 589425.93423656, 609518.6719560538, 4913959.224611808, 4928082.949945881); + groupWriter.addLayer("topp:tasmania_roads"); + groupWriter.addLayer("topp:tasmania_cities"); + assertTrue(publisher.createLayerGroup(workspace, groupName, groupWriter)); + } + + @Test + public void testConfigureLayerGroup() throws Exception { + String groupName = "my-tasmania"; + + createTestLayerGroup(null, groupName); + try { + GSLayerGroupEncoder groupWriter = new GSLayerGroupEncoder(); + groupWriter.addLayer("topp:tasmania_roads"); + + assertTrue(publisher.configureLayerGroup(groupName, groupWriter)); + + RESTLayerGroup groupReader = reader.getLayerGroup(groupName); + assertNull(groupReader.getWorkspace()); + assertEquals(groupName, groupReader.getName()); + + RESTPublishedList publishedList = groupReader.getPublishedList(); + if (publishedList != null) { + // GeoServer >= 2.3 + assertEquals(1, publishedList.size()); + for (RESTPublished published : publishedList) { + assertEquals("layer", published.getType()); + assertTrue("tasmania_roads".equals(published.getName())); + } + } else { + RESTLayerList layerList = groupReader.getLayerList(); + assertEquals(1, layerList.size()); + for (NameLinkElem layer : layerList) { + assertTrue("tasmania_roads".equals(layer.getName())); + } + } + } finally { + assertTrue(publisher.removeLayerGroup(groupName)); + } + } + + @Test + public void testConfigureLayerGroupInWorkspace() throws Exception { + String groupName = "my-tasmania-in-ws"; + + createTestLayerGroup("topp", groupName); + try { + GSLayerGroupEncoder groupWriter = new GSLayerGroupEncoder(); + groupWriter.addLayer("topp:tasmania_roads"); + + assertTrue(publisher.configureLayerGroup("topp", groupName, groupWriter)); + + RESTLayerGroup groupReader = reader.getLayerGroup("topp", groupName); + assertEquals("topp", groupReader.getWorkspace()); + assertEquals(groupName, groupReader.getName()); + + RESTPublishedList publishedList = groupReader.getPublishedList(); + if (publishedList != null) { + // GeoServer >= 2.3 + assertEquals(1, publishedList.size()); + for (RESTPublished published : publishedList) { + assertEquals("layer", published.getType()); + assertTrue("tasmania_roads".equals(published.getName())); + } + } else { + RESTLayerList layerList = groupReader.getLayerList(); + assertEquals(1, layerList.size()); + for (NameLinkElem layer : layerList) { + assertTrue("tasmania_roads".equals(layer.getName())); + } + } + } finally { + assertTrue(publisher.removeLayerGroup("topp", groupName)); + } + } + + @Test + public void testConfigureLayerGroup23() throws Exception { + String groupName = "my-tasmania-23"; + + createTestLayerGroup(null, groupName); + try { + GSLayerGroupEncoder23 groupWriter = new GSLayerGroupEncoder23(); + groupWriter.addLayer("topp:tasmania_roads"); + groupWriter.setMode(GSLayerGroupEncoder23.MODE_NAMED); + groupWriter.setTitle("my title"); + groupWriter.setAbstract("my abstract"); + + assertTrue(publisher.configureLayerGroup(groupName, groupWriter)); + + RESTLayerGroup groupReader = reader.getLayerGroup(groupName); + assertNull(groupReader.getWorkspace()); + assertEquals(groupName, groupReader.getName()); + assertEquals("my title", groupReader.getTitle()); + assertEquals("my abstract", groupReader.getAbstract()); + assertEquals(GSLayerGroupEncoder23.MODE_NAMED, groupReader.getMode()); + + RESTPublishedList publishedList = groupReader.getPublishedList(); + assertEquals(1, publishedList.size()); + for (RESTPublished published : publishedList) { + assertEquals("layer", published.getType()); + assertTrue("tasmania_roads".equals(published.getName())); + } + } finally { + assertTrue(publisher.removeLayerGroup(groupName)); + } + } + + /** + * This test only works with GeoServer >= 2.3 + */ + @Test + public void testCreateNestedLayerGroup23() throws Exception { + String groupName = "my-tasmania-eo"; + + GSLayerGroupEncoder23 groupWriter = new GSLayerGroupEncoder23(); + groupWriter.setTitle("my title"); + groupWriter.setAbstract("my abstract"); + groupWriter.setMode(GSLayerGroupEncoder23.MODE_EO); + groupWriter.setRootLayer("topp:tasmania_roads", "simple_roads"); + groupWriter.setBounds("EPSG:26713", 589425.93423656, 609518.6719560538, 4913959.224611808, 4928082.949945881); + groupWriter.addLayer("topp:tasmania_cities"); + groupWriter.addLayerGroup("tasmania"); + + assertTrue(publisher.createLayerGroup(groupName, groupWriter)); + try { + RESTLayerGroup groupReader = reader.getLayerGroup(groupName); + assertNull(groupReader.getWorkspace()); + assertEquals(groupName, groupReader.getName()); + assertEquals("my title", groupReader.getTitle()); + assertEquals("my abstract", groupReader.getAbstract()); + assertEquals(GSLayerGroupEncoder23.MODE_EO, groupReader.getMode()); + assertEquals("tasmania_roads", groupReader.getRootLayer()); + + RESTPublishedList publishedList = groupReader.getPublishedList(); + assertEquals(2, publishedList.size()); + for (RESTPublished published : publishedList) { + if ("layer".equals(published.getType())) { + assertEquals("tasmania_cities", published.getName()); + } else { + assertEquals("layerGroup", published.getType()); + assertEquals("tasmania", published.getName()); + } + } + } finally { + assertTrue(publisher.removeLayerGroup(groupName)); + } + } +} \ No newline at end of file