diff --git a/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java b/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java index 35bc2f2..f6603bf 100644 --- a/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java +++ b/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java @@ -28,6 +28,7 @@ import it.geosolutions.geoserver.rest.decoder.RESTCoverageList; import it.geosolutions.geoserver.rest.decoder.RESTCoverageStore; import it.geosolutions.geoserver.rest.decoder.utils.NameLinkElem; import it.geosolutions.geoserver.rest.encoder.GSLayerEncoder; +import it.geosolutions.geoserver.rest.encoder.GSNamespaceEncoder; import it.geosolutions.geoserver.rest.encoder.GSPostGISDatastoreEncoder; import it.geosolutions.geoserver.rest.encoder.GSResourceEncoder; import it.geosolutions.geoserver.rest.encoder.GSResourceEncoder.ProjectionPolicy; @@ -110,6 +111,84 @@ public class GeoServerRESTPublisher { final String result = HTTPUtils.postXml(sUrl, wsxml, gsuser, gspass); return result != null; } + + /** + * Create both a workspace and its associated namespace. + * + * Note that this method is equivalent to {@link #createNamespace}. + * + * @param name Name for the new workspace, which will be also its associated namespace prefix. + * @param uri Namespace URI. Cannot be empty. + * @return true if the Workspace and its associated namespace were successfully created. + */ + public boolean createWorkspace(final String name, final URI uri) { + // This is really an alias to createNamespace, as GeoServer + // will automatically create the workspace as well. + return createNamespace(name, uri); + } + + // ========================================================================== + // === NAMESPACES + // ========================================================================== + + /** + * Create a new namespace. GeoServer will automatically create the corresponding workspace. + * + * Prefix and uri are mandatory and cannot be empty. + * If a namespace with the given prefix already exists, it won't be created. + * + * @param prefix The name of the new namespace. + * @param uri The URI of the new namespace. + * @return true if the namespace was successfully created. + * @see GeoServer Documentation + */ + public boolean createNamespace(final String prefix, final URI uri) { + final String sUrl = restURL + "/rest/namespaces"; + final GSNamespaceEncoder nsenc = new GSNamespaceEncoder(prefix, uri); + final String nsxml = nsenc.toString(); + final String result = HTTPUtils.postXml(sUrl, nsxml, gsuser, gspass); + return result != null; + } + + /** + * Update a namespace URI. + * + * Prefix and uri are mandatory and cannot be empty. + * A namespace with the given prefix should exist. + * + * @param prefix The prefix of an existing namespace. + * @param uri The new URI. + * @return true if the namespace was successfully updated. + */ + public boolean updateNamespace(final String prefix, final URI uri) { + final String sUrl = restURL + "/rest/namespaces/"+ encode(prefix); + final GSNamespaceEncoder nsenc = new GSNamespaceEncoder(prefix, uri); + final String nsxml = nsenc.toString(); + final String result = HTTPUtils.put(sUrl, nsxml, "application/xml", gsuser, gspass); + return result != null; + } + + /** + * Remove a given Namespace. It will remove the associated workspace as well. + * + * @param prefix + * The namespace prefix + * @param recurse + * The recurse parameter is used to recursively delete all + * resources contained in the workspace associated with this + * namespace. This includesdata stores, coverage stores, + * feature types, etc... Allowable values for this parameter + * are true or false. The default (safer) value + * is false. + * @return true if the namespace was successfully removed. + */ + public boolean removeNamespace(final String prefix, boolean recurse) { + // Hack: We are instead calling removeWorkspace, as DELETE on + // a namespace will leave associated workspace in an inconsistent + // state. See https://jira.codehaus.org/browse/GEOS-5075 + // TODO switch to namespace when GEOS-5075 is solved + return removeWorkspace(prefix, recurse); + } // ========================================================================== // === STYLES diff --git a/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTReader.java b/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTReader.java index 792a54a..bf7075b 100644 --- a/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTReader.java +++ b/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTReader.java @@ -36,6 +36,7 @@ import it.geosolutions.geoserver.rest.decoder.RESTLayer; import it.geosolutions.geoserver.rest.decoder.RESTLayerGroup; import it.geosolutions.geoserver.rest.decoder.RESTLayerGroupList; import it.geosolutions.geoserver.rest.decoder.RESTLayerList; +import it.geosolutions.geoserver.rest.decoder.RESTNamespace; import it.geosolutions.geoserver.rest.decoder.RESTNamespaceList; import it.geosolutions.geoserver.rest.decoder.RESTResource; import it.geosolutions.geoserver.rest.decoder.RESTStyleList; @@ -454,6 +455,25 @@ public class GeoServerRESTReader { //=== NAMESPACES //========================================================================== + /** + * Get a namespace. + * + * @param prefix namespace prefix. + * + * @return a RESTNamespace, or null if couldn't be created. + */ + public RESTNamespace getNamespace(String prefix) { + if (prefix == null || prefix.isEmpty()) { + throw new IllegalArgumentException( + "Namespace prefix cannot be null or empty"); + } + String url = "/rest/namespaces/"+prefix+".xml"; + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("### Getting namespace from " + url); + } + return RESTNamespace.build(load(url)); + } + /** * Get summary info about all Namespaces. * diff --git a/src/main/java/it/geosolutions/geoserver/rest/decoder/RESTNamespace.java b/src/main/java/it/geosolutions/geoserver/rest/decoder/RESTNamespace.java new file mode 100644 index 0000000..aa034ea --- /dev/null +++ b/src/main/java/it/geosolutions/geoserver/rest/decoder/RESTNamespace.java @@ -0,0 +1,99 @@ +/* + * GeoServer-Manager - Simple Manager Library for GeoServer + * + * Copyright (C) 2007,2012 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.decoder; + +import it.geosolutions.geoserver.rest.decoder.utils.JDOMBuilder; + +import org.jdom.Element; +import java.net.URI; + +/** + * Parse namespaces returned as XML REST objects. + * + * This is the XML REST representation: + *
{@code
+   
+     topp
+     http://www.openplans.org/topp
+     
+       
+     
+   
+ * }
+ * + * @author Oscar Fonts + */ +public class RESTNamespace { + public final static String NAMESPACE="namespace"; + public final static String PREFIX="prefix"; + public final static String URI="uri"; + public final static String FEATURE_TYPES="featureTypes"; + + private final Element namespaceElem; + + /** + * Build a RESTNamespace from a REST response. + * + * @param response XML representation of the namespace. + * @return a new RESTNamespace, or null if XML could not be parsed. + */ + public static RESTNamespace build(String response) { + if(response == null) + return null; + + Element pb = JDOMBuilder.buildElement(response); + if(pb != null) + return new RESTNamespace(pb); + else + return null; + } + + /** + * Create a RESTNamespace from a XML element. + * + * @param elem The jdom XML Element describing a namespace. + */ + public RESTNamespace(Element elem) { + this.namespaceElem = elem; + } + + /** + * Get the namespace prefix + * + * @return the namespace prefix. + */ + public String getPrefix() { + return namespaceElem.getChildText(PREFIX); + } + + /** + * Get the namespace URI. + * + * @return the namespace uri. + */ + public URI getURI() { + return java.net.URI.create(namespaceElem.getChildText(URI)); + } +} diff --git a/src/main/java/it/geosolutions/geoserver/rest/encoder/GSNamespaceEncoder.java b/src/main/java/it/geosolutions/geoserver/rest/encoder/GSNamespaceEncoder.java new file mode 100644 index 0000000..d46b1a5 --- /dev/null +++ b/src/main/java/it/geosolutions/geoserver/rest/encoder/GSNamespaceEncoder.java @@ -0,0 +1,131 @@ +/* + * GeoServer-Manager - Simple Manager Library for GeoServer + * + * Copyright (C) 2007,2012 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.net.URI; + +import it.geosolutions.geoserver.rest.encoder.utils.ElementUtils; +import it.geosolutions.geoserver.rest.encoder.utils.PropertyXMLEncoder; + +/** + * Namespace XML encoder. Namespaces must contain a non empty prefix and a URI: + * + *
+ * <namespace>
+ *   <prefix>example</prefix>
+ *   <uri>http://example.com</uri>
+ * </namespace>
+ * 
+ * + * @see GeoServer Documentation + * @author Oscar Fonts + */ +public class GSNamespaceEncoder extends PropertyXMLEncoder { + + public final static String NAMESPACE="namespace"; + public final static String PREFIX="prefix"; + public final static String URI="uri"; + + /** + * Create a namespace XML encoder. + * + * @param prefix the namespace prefix + * @param uri the namespace URI + * @throws IllegalArgumentException if prefix or uri are null or empty + */ + public GSNamespaceEncoder(String prefix, URI uri) { + super(NAMESPACE); + + ensureValidPrefix(prefix); + ensureValidURI(uri); + + add(PREFIX, prefix); + add(URI, uri.toString()); + } + + /** + * Get the namespace prefix. + * @return the prefix + */ + public String getPrefix() { + return ElementUtils.contains(getRoot(), PREFIX).getTextTrim(); + } + + /** + * Change the namespace prefix. + * @param prefix the new prefix + * @throws IllegalArgumentException if prefix is null or empty + */ + public void setPrefix(final String prefix) { + ensureValidPrefix(prefix); + ElementUtils.contains(getRoot(), PREFIX).setText(prefix); + } + + /** + * Get the namespace uri. + * @return the uri + */ + public URI getURI() { + String sUri = ElementUtils.contains(getRoot(), URI).getTextTrim(); + return java.net.URI.create(sUri); + } + + /** + * change the nampespace uri. + * @param URI the new uri + * @throws IllegalArgumentException if uri is null or empty + */ + public void setURI(final URI uri) { + ensureValidURI(uri); + String sUri = uri.toString(); + ElementUtils.contains(getRoot(), URI).setText(sUri); + } + + /** + * Check prefix value. + * + * @param prefix the prefix + * @throws IllegalArgumentException if prefix is null or empty + */ + private static void ensureValidPrefix(String prefix) { + if (prefix == null || prefix.isEmpty()) { + throw new IllegalArgumentException( + "Namespace prefix cannot be null or empty"); + } + } + + /** + * Check uri value. + * + * @param prefix the uri + * @throws IllegalArgumentException if uri is null or empty + */ + private static void ensureValidURI(URI uri) { + if (uri == null || uri.toString().isEmpty()) { + throw new IllegalArgumentException( + "Namespace uri cannot be null or empty"); + } + } +} diff --git a/src/test/java/it/geosolutions/geoserver/rest/GeoserverRESTReaderTest.java b/src/test/java/it/geosolutions/geoserver/rest/GeoserverRESTReaderTest.java index d92739c..773066c 100644 --- a/src/test/java/it/geosolutions/geoserver/rest/GeoserverRESTReaderTest.java +++ b/src/test/java/it/geosolutions/geoserver/rest/GeoserverRESTReaderTest.java @@ -161,7 +161,24 @@ public class GeoserverRESTReaderTest extends GeoserverRESTTest { } System.out.println(); } + + /** + * Test of getWorkspaceNames method, of class GeoServerRESTReader. + */ + public void testGetNamespaceNames() { + if(!enabled()) return; + List names = reader.getNamespaceNames(); + assertNotNull(names); +// assertEquals(7, names.size()); // value in default gs installation + + System.out.println("Namespaces:" + names.size()); + System.out.print("Namespaces:"); + for (String name : names) { + System.out.print(name + " "); + } + System.out.println(); + } /** * Test of getWorkspaceNames method, of class GeoServerRESTReader. diff --git a/src/test/java/it/geosolutions/geoserver/rest/encoder/GSNamespaceEncoderTest.java b/src/test/java/it/geosolutions/geoserver/rest/encoder/GSNamespaceEncoderTest.java new file mode 100644 index 0000000..4bf709c --- /dev/null +++ b/src/test/java/it/geosolutions/geoserver/rest/encoder/GSNamespaceEncoderTest.java @@ -0,0 +1,73 @@ +/* + * GeoServer-Manager - Simple Manager Library for GeoServer + * + * Copyright (C) 2007,2012 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 static org.junit.Assert.*; +import java.net.URI; +import org.junit.Test; + +/** + * @author Oscar Fonts + */ +public class GSNamespaceEncoderTest { + + private static final String ROOT_NAME = "namespace"; + private static final String TEST_PREFIX = "example"; + private static final URI TEST_URI = URI.create("http://example.com"); + + /** + * Test method for {@link GSNamespaceEncoder#GSNamespaceEncoder()}. + */ + @Test + public void testGSNamespaceEncoder() { + + // Test constructor and getters. + GSNamespaceEncoder enc = new GSNamespaceEncoder(TEST_PREFIX, TEST_URI); + assertEquals(enc.getRoot().getName(), ROOT_NAME); + assertEquals(enc.getPrefix(), TEST_PREFIX); + assertEquals(enc.getURI(), TEST_URI); + assertEquals(enc.toString(),""+TEST_PREFIX+""+ + ""+TEST_URI+""); + + // Test constructor parameter extreme values. + // Should throw IllegalArgumentException if null or empty. + try { + new GSNamespaceEncoder(null, TEST_URI); + fail("Namespace encoder should not accept a null prefix"); + } catch (IllegalArgumentException e) {} + try { + new GSNamespaceEncoder("", TEST_URI); + fail("Namespace encoder should not accept an empty prefix"); + } catch (IllegalArgumentException e) {} + try { + new GSNamespaceEncoder(TEST_PREFIX, null); + fail("Namespace encoder should not accept a null uri"); + } catch (IllegalArgumentException e) {} + try { + new GSNamespaceEncoder(TEST_PREFIX, URI.create("")); + fail("Namespace encoder should not accept an empty uri"); + } catch (IllegalArgumentException e) {} + } +} diff --git a/src/test/java/it/geosolutions/geoserver/rest/publisher/GeoserverRESTNamespaceTest.java b/src/test/java/it/geosolutions/geoserver/rest/publisher/GeoserverRESTNamespaceTest.java new file mode 100644 index 0000000..7a9f60a --- /dev/null +++ b/src/test/java/it/geosolutions/geoserver/rest/publisher/GeoserverRESTNamespaceTest.java @@ -0,0 +1,103 @@ +/* + * GeoServer-Manager - Simple Manager Library for GeoServer + * + * Copyright (C) 2007,2012 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.publisher; + +import org.junit.Test; + +import it.geosolutions.geoserver.rest.GeoserverRESTTest; +import it.geosolutions.geoserver.rest.decoder.RESTNamespace; + +import java.net.URI; + +/** + * Testcase for namespace management. + * + * We need a running GeoServer to properly run the tests. + * If such geoserver instance cannot be contacted, tests will be skipped. + * + * @author Oscar Fonts + */ +public class GeoserverRESTNamespaceTest extends GeoserverRESTTest { + + public GeoserverRESTNamespaceTest(String testName) { + super(testName); + } + + /** + * Test Namespace create + */ + @Test + public void testCreate() { + if (!enabled()) return; + + deleteAll(); + assertEquals(0, reader.getNamespaces().size()); + assertEquals(0, reader.getWorkspaces().size()); + + // Test Namespace Creation + assertTrue(publisher.createNamespace("NS1", URI.create("http://a.example.com"))); + assertTrue(publisher.createNamespace("NS2", URI.create("http://b.example.com"))); + assertEquals(2, reader.getNamespaces().size()); + + // When creating a namespace, its associated workspace will be automatically created: + assertEquals(2, reader.getWorkspaces().size()); + + // Existing prefix / existing URI + assertFalse(publisher.createNamespace("NS1", URI.create("http://c.example.com"))); + assertFalse(publisher.createNamespace("NS3", URI.create("http://a.example.com"))); + assertEquals(2, reader.getWorkspaces().size()); + } + + /** + * Test Namespace read, update and delete + */ + @Test + public void testReadUpdateDelete() { + if (!enabled()) return; + + deleteAll(); + assertTrue(publisher.createNamespace("NS1", URI.create("http://a.example.com"))); + + // Test read namespace list + String nsName = reader.getNamespaceNames().get(0); + assertEquals(nsName, "NS1"); + + // Read a namespace + RESTNamespace ns = reader.getNamespace(nsName); + assertEquals(ns.getPrefix(), "NS1"); + assertEquals(ns.getURI(), URI.create("http://a.example.com")); + + // Update namespaces (change URI) + assertTrue(publisher.updateNamespace("NS1", URI.create("http://b.example.com"))); + assertFalse(publisher.updateNamespace("NS2", URI.create("http://a.example.com"))); // Nonexistent + + // Delete namespaces + assertTrue(publisher.removeNamespace("NS1", true)); + assertFalse(publisher.removeNamespace("NS3", true)); // Nonexistent + + assertEquals(0, reader.getNamespaces().size()); + assertEquals(0, reader.getWorkspaces().size()); + } +}