diff --git a/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java b/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java
index d827dd2..2a709b7 100644
--- a/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java
+++ b/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java
@@ -30,11 +30,12 @@ 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.GSNamespaceEncoder;
-import it.geosolutions.geoserver.rest.encoder.GSPostGISDatastoreEncoder;
import it.geosolutions.geoserver.rest.encoder.GSResourceEncoder;
import it.geosolutions.geoserver.rest.encoder.GSResourceEncoder.ProjectionPolicy;
import it.geosolutions.geoserver.rest.encoder.GSWorkspaceEncoder;
import it.geosolutions.geoserver.rest.encoder.coverage.GSCoverageEncoder;
+import it.geosolutions.geoserver.rest.encoder.datastore.GSAbstractDatastoreEncoder;
+import it.geosolutions.geoserver.rest.encoder.datastore.GSPostGISDatastoreEncoder;
import it.geosolutions.geoserver.rest.encoder.feature.GSFeatureTypeEncoder;
import java.io.File;
@@ -655,20 +656,20 @@ public class GeoServerRESTPublisher {
}
/**
- * The file, url, and external endpoints are used to specify the method that
- * is used to upload the file.
- *
- * The file method is used to directly upload a file from a local source.
+ * The {@code file}, {@code url}, and {@code external} endpoints are used to specify
+ * the method that is used to upload the file.
+ *
+ * - The {@code file} method is used to directly upload a file from a local source.
* The body of the request is the file itself.
*
- * The url method is used to indirectly upload a file from an remote source.
+ *
- The {@code url} method is used to indirectly upload a file from an remote source.
* The body of the request is a url pointing to the file to upload. This url
* must be visible from the server.
*
- * The external method is used to forgo upload and use an existing file on
+ *
- The {@code external} method is used to forgo upload and use an existing file on
* the server. The body of the request is the absolute path to the existing
* file.
- *
+ *
* @author Carlo Cancellieri - carlo.cancellieri@geo-solutions.it
*
*/
@@ -677,7 +678,7 @@ public class GeoServerRESTPublisher {
}
// ==========================================================================
- // === DATASTORE
+ // === DATASTORES
// ==========================================================================
/**
@@ -702,11 +703,52 @@ public class GeoServerRESTPublisher {
String result = HTTPUtils.postXml(sUrl, xml, gsuser, gspass);
return result != null;
}
+
+ /**
+ * Create a datastore (any datastore extending GSAbstractDatastoreEncoder).
+ *
+ * @param workspace
+ * Name of the workspace to contain the datastore. This will also
+ * be the prefix of any layer names contained in the datastore.
+ * @param datastore
+ * the set of parameters to be set to the datastore (including
+ * connection parameters).
+ * @return true if the datastore has been successfully
+ * created, false otherwise
+ */
+ public boolean createDatastore(String workspace,
+ GSAbstractDatastoreEncoder datastore) {
+ String sUrl = restURL + "/rest/workspaces/" + workspace
+ + "/datastores/";
+ String xml = datastore.toString();
+ String result = HTTPUtils.postXml(sUrl, xml, gsuser, gspass);
+ return result != null;
+ }
+
+ /**
+ * Update a datastore (any datastore extending GSAbstractDatastoreEncoder).
+ *
+ * @param workspace
+ * Name of the workspace that contains the datastore.
+ * @param datastore
+ * the set of parameters to be set to the datastore (including
+ * connection parameters).
+ * @return true if the datastore has been successfully
+ * updated, false otherwise
+ */
+ public boolean updateDatastore(String workspace,
+ GSAbstractDatastoreEncoder datastore) {
+ String sUrl = restURL + "/rest/workspaces/" + workspace
+ + "/datastores/" + datastore.getName();
+ String xml = datastore.toString();
+ String result = HTTPUtils.putXml(sUrl, xml, gsuser, gspass);
+ return result != null;
+ }
// ==========================================================================
// === SHAPEFILES
// ==========================================================================
-
+
/**
* Publish a zipped shapefile.
* The defaultCRS will be set to EPSG:4326.
@@ -896,6 +938,57 @@ public class GeoServerRESTPublisher {
return publishShp(workspace, storename, params, layername, UploadMethod.file, zipFile.toURI(), srs, ProjectionPolicy.NONE,null);
}
+
+
+ /**
+ * Publish a collection of shapefiles.
+ *
+ * It will automatically create the store and publish each shapefile as a layer.
+ *
+ * @param workspace the name of the workspace to use
+ * @param storeName the name of the store to create
+ * @param resource the shapefile collection. It can be:
+ * - A path to a directory containing shapefiles in the server.
+ *
- A local zip file containing shapefiles that will be uploaded.
+ *
- A URL pointing to a shapefile collection in the wild web (not tested).
+ * @return {@code true} if publication successful.
+ * @throws FileNotFoundException if the specified zip file does not exist.
+ */
+ public boolean publishShpCollection(String workspace, String storeName, URI resource)
+ throws FileNotFoundException {
+
+ // Deduce upload method & mime type from resource syntax.
+ UploadMethod method = null;
+ String mime = null;
+ if (resource.getScheme().equals("file") || resource.isAbsolute() == false) {
+ File f = new File(resource);
+ if (f.exists() && f.isFile() && f.toString().endsWith(".zip")) {
+ method = UploadMethod.file;
+ mime = "application/zip";
+ } else if (f.isDirectory()) {
+ method = UploadMethod.external;
+ mime = "text/plain";
+ }
+ } else {
+ try {
+ if(resource.toURL() != null) {
+ method = UploadMethod.url;
+ mime = "text/plain";
+ }
+ } catch (MalformedURLException e) {
+ throw new IllegalArgumentException("Resource is not recognized as a zip file, or a directory, or a valid URL", e);
+ }
+ }
+
+ // Create store, upload data, and publish layers
+ return createStore(
+ workspace, DataStoreType.datastores,
+ storeName, method,
+ DataStoreExtension.shp, // TODO if GEOS-5113 is accepted, change to DataStoreExtension.shpdir
+ mime, resource,
+ ParameterConfigure.ALL,
+ new NameValuePair[0]);
+ }
/**
* @param workspace
@@ -1159,7 +1252,7 @@ public class GeoServerRESTPublisher {
*
*/
public enum DataStoreExtension {
- shp, properties, h2, spatialite
+ shp, /*shpdir,*/ properties, h2, spatialite // TODO uncomment if GEOS-5113 is accepted
}
/**
diff --git a/src/main/java/it/geosolutions/geoserver/rest/decoder/RESTDataStore.java b/src/main/java/it/geosolutions/geoserver/rest/decoder/RESTDataStore.java
index 22c24f0..52904d7 100644
--- a/src/main/java/it/geosolutions/geoserver/rest/decoder/RESTDataStore.java
+++ b/src/main/java/it/geosolutions/geoserver/rest/decoder/RESTDataStore.java
@@ -26,7 +26,11 @@
package it.geosolutions.geoserver.rest.decoder;
import it.geosolutions.geoserver.rest.decoder.utils.JDOMBuilder;
+
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+
import org.jdom.Element;
/**
@@ -108,15 +112,44 @@ public class RESTDataStore {
public String getName() {
return dsElem.getChildText("name");
}
+
+ public String getStoreType() {
+ return dsElem.getChildText("type");
+ }
+
+ public String getDescription() {
+ return dsElem.getChildText("description");
+ }
+ public boolean isEnabled() {
+ return Boolean.parseBoolean(dsElem.getChildText("enabled"));
+ }
+
public String getWorkspaceName() {
return dsElem.getChild("workspace").getChildText("name");
}
-
- protected String getConnectionParameter(String paramName) {
+
+ public Map getConnectionParameters() {
Element elConnparm = dsElem.getChild("connectionParameters");
if (elConnparm != null) {
- for (Element entry : (List) elConnparm.getChildren("entry")) {
+ @SuppressWarnings("unchecked")
+ List elements = (List)elConnparm.getChildren("entry");
+ Map params = new HashMap(elements.size());
+ for (Element element : elements) {
+ String key = element.getAttributeValue("key");
+ String value = element.getTextTrim();
+ params.put(key, value);
+ }
+ return params;
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected String getConnectionParameter(String paramName) {
+ Element elConnparm = dsElem.getChild("connectionParameters");
+ if (elConnparm != null) {
+ for (Element entry : (List) elConnparm.getChildren("entry")) {
String key = entry.getAttributeValue("key");
if (paramName.equals(key)) {
return entry.getTextTrim();
@@ -126,7 +159,7 @@ public class RESTDataStore {
return null;
}
-
+
public DBType getType() {
return DBType.get(getConnectionParameter("dbtype"));
}
diff --git a/src/main/java/it/geosolutions/geoserver/rest/encoder/datastore/GSAbstractDatastoreEncoder.java b/src/main/java/it/geosolutions/geoserver/rest/encoder/datastore/GSAbstractDatastoreEncoder.java
new file mode 100644
index 0000000..f957810
--- /dev/null
+++ b/src/main/java/it/geosolutions/geoserver/rest/encoder/datastore/GSAbstractDatastoreEncoder.java
@@ -0,0 +1,146 @@
+/*
+ * 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.datastore;
+
+import java.util.Map;
+
+import it.geosolutions.geoserver.rest.decoder.RESTDataStore;
+import it.geosolutions.geoserver.rest.encoder.utils.ElementUtils;
+import it.geosolutions.geoserver.rest.encoder.utils.NestedElementEncoder;
+import it.geosolutions.geoserver.rest.encoder.utils.PropertyXMLEncoder;
+
+/**
+ * Generic Datastore encoder.
+ *
+ * Provides getters and setters for parameters common to all Datastores,
+ * an internal placeholder for specific connection parameters, and
+ * a constructor to read parameters from a {@link RESTDataStore}.
+ *
+ * @author Oscar Fonts
+ */
+public abstract class GSAbstractDatastoreEncoder extends PropertyXMLEncoder {
+
+ final static String ROOT = "dataStore";
+
+ NestedElementEncoder connectionParameters = new NestedElementEncoder("connectionParameters");
+
+ GSAbstractDatastoreEncoder(String storeName) {
+ super(ROOT);
+ // Add mandatory parameter
+ ensureValidName(storeName);
+ setName(storeName);
+
+ // Add connection parameters
+ addContent(connectionParameters.getRoot());
+ }
+
+ /**
+ * Create a {@value #TYPE} datastore encoder from a store read from server.
+ *
+ * @param store The existing store.
+ * @throws IllegalArgumentException if store type or mandatory parameters are not valid
+ */
+ GSAbstractDatastoreEncoder(RESTDataStore store) {
+ this(store.getName());
+
+ // Match datastore type
+ ensureValidType(store.getStoreType());
+ setType(store.getStoreType());
+
+ // Copy store parameters
+ setDescription(store.getDescription());
+ setEnabled(store.isEnabled());
+
+ // Copy connection parameters - bulk
+ Map params = store.getConnectionParameters();
+ for(String key : params.keySet()) {
+ connectionParameters.set(key, params.get(key));
+ }
+ }
+
+ void setType(String type) {
+ set("type", type);
+ }
+
+ public String getType() {
+ return ElementUtils.contains(getRoot(), "type").getTextTrim();
+ }
+
+ public void setName(String name) {
+ ensureValidName(name);
+ set("name", name);
+ }
+
+ public String getName() {
+ return ElementUtils.contains(getRoot(), "name").getTextTrim();
+ }
+
+ public void setDescription(String description) {
+ set("description", description);
+ }
+
+ public String getDescription() {
+ return ElementUtils.contains(getRoot(), "description").getTextTrim();
+ }
+
+ public void setEnabled(boolean enabled) {
+ set("enabled", Boolean.toString(enabled));
+ }
+
+ public boolean getEnabled() {
+ return Boolean.parseBoolean(ElementUtils.contains(getRoot(), "enabled").getTextTrim());
+ }
+
+ /**
+ * Check name validity.
+ *
+ * @param name the name
+ * @throws IllegalArgumentException if name is null or empty
+ */
+ void ensureValidName(String name) {
+ if (name == null || name.isEmpty()) {
+ throw new IllegalArgumentException(
+ "Store name cannot be null or empty");
+ }
+ }
+
+ /**
+ * Check type validity.
+ *
+ * @param type the type.
+ * @throws IllegalArgumentException if type is not {@value #TYPE}
+ */
+ void ensureValidType(String type) {
+ if (!type.equals(getValidType())) {
+ throw new IllegalArgumentException(
+ "The store type '"+ type +"' is not valid");
+ }
+ }
+
+ /**
+ * The type of the implementing datastore.
+ */
+ abstract String getValidType();
+}
diff --git a/src/main/java/it/geosolutions/geoserver/rest/encoder/datastore/GSDirectoryOfShapefilesDatastoreEncoder.java b/src/main/java/it/geosolutions/geoserver/rest/encoder/datastore/GSDirectoryOfShapefilesDatastoreEncoder.java
new file mode 100644
index 0000000..eae422e
--- /dev/null
+++ b/src/main/java/it/geosolutions/geoserver/rest/encoder/datastore/GSDirectoryOfShapefilesDatastoreEncoder.java
@@ -0,0 +1,68 @@
+/*
+ * 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.datastore;
+
+import it.geosolutions.geoserver.rest.decoder.RESTDataStore;
+
+import java.net.URL;
+
+/**
+ * Encoder for a {@value #TYPE} datastore.
+ *
+ * @author Oscar Fonts
+ */
+public class GSDirectoryOfShapefilesDatastoreEncoder extends GSShapefileDatastoreEncoder {
+
+ static final String TYPE = "Directory of spatial files (shapefiles)";
+
+ /**
+ * Create a {@value #TYPE} datastore with default connection parameters,
+ * given a store name and a url (the store location).
+ *
+ * @param name New datastore name
+ * @param url The shapefile location in the server, relative to $GEOSERVER_DATA_DIR.
+ */
+ public GSDirectoryOfShapefilesDatastoreEncoder(String name, URL url) {
+ super(name, url);
+ setType(TYPE);
+ }
+
+ /**
+ * Create a {@value #TYPE} datastore encoder from an existing store read from server.
+ *
+ * @param store The existing store.
+ * @throws IllegalArgumentException if store type or mandatory parameters are not valid
+ */
+ public GSDirectoryOfShapefilesDatastoreEncoder(RESTDataStore store) {
+ super(store);
+ }
+
+ /**
+ * @return {@value #TYPE}
+ */
+ String getValidType() {
+ return TYPE;
+ }
+}
diff --git a/src/main/java/it/geosolutions/geoserver/rest/encoder/GSPostGISDatastoreEncoder.java b/src/main/java/it/geosolutions/geoserver/rest/encoder/datastore/GSPostGISDatastoreEncoder.java
similarity index 99%
rename from src/main/java/it/geosolutions/geoserver/rest/encoder/GSPostGISDatastoreEncoder.java
rename to src/main/java/it/geosolutions/geoserver/rest/encoder/datastore/GSPostGISDatastoreEncoder.java
index 1db6613..0323fb3 100644
--- a/src/main/java/it/geosolutions/geoserver/rest/encoder/GSPostGISDatastoreEncoder.java
+++ b/src/main/java/it/geosolutions/geoserver/rest/encoder/datastore/GSPostGISDatastoreEncoder.java
@@ -23,7 +23,7 @@
* THE SOFTWARE.
*/
-package it.geosolutions.geoserver.rest.encoder;
+package it.geosolutions.geoserver.rest.encoder.datastore;
import it.geosolutions.geoserver.rest.encoder.utils.NestedElementEncoder;
import it.geosolutions.geoserver.rest.encoder.utils.PropertyXMLEncoder;
diff --git a/src/main/java/it/geosolutions/geoserver/rest/encoder/datastore/GSShapefileDatastoreEncoder.java b/src/main/java/it/geosolutions/geoserver/rest/encoder/datastore/GSShapefileDatastoreEncoder.java
new file mode 100644
index 0000000..3a9d949
--- /dev/null
+++ b/src/main/java/it/geosolutions/geoserver/rest/encoder/datastore/GSShapefileDatastoreEncoder.java
@@ -0,0 +1,163 @@
+/*
+ * 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.datastore;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.charset.Charset;
+
+import it.geosolutions.geoserver.rest.decoder.RESTDataStore;
+import it.geosolutions.geoserver.rest.encoder.utils.ElementUtils;
+
+/**
+ * Encoder for a {@value #TYPE} datastore.
+ *
+ * @author Oscar Fonts
+ */
+public class GSShapefileDatastoreEncoder extends GSAbstractDatastoreEncoder {
+
+ static final String TYPE = "Shapefile";
+
+ final static boolean DEFAULT_ENABLED = true;
+ final static String DEFAULT_CHARSET = "ISO-8859-1";
+ final static boolean DEFAULT_CREATE_SPATIAL_INDEX = true;
+ final static boolean DEFAULT_MEMORY_MAPPED_BUFFER = false;
+ final static boolean DEFAULT_CACHE_AND_REUSE_MEMORY_MAPS = true;
+
+ /**
+ * Create a {@value #TYPE} datastore with default connection parameters,
+ * given a store name and a url (the store location).
+ *
+ * The following default connection parameters are set:
+ *
+ * - enabled: {@value #DEFAULT_ENABLED}
+ *
- charset: {@value #DEFAULT_CHARSET}
+ *
- create spatial index: {@value #DEFAULT_CREATE_SPATIAL_INDEX}
+ *
- memory mapped buffer: {@value #DEFAULT_MEMORY_MAPPED_BUFFER}
+ *
- cache and reuse memory maps: {@value #DEFAULT_CACHE_AND_REUSE_MEMORY_MAPS}
+ *
+ *
+ * @param name New datastore name
+ * @param url The shapefile location in the server, relative to $GEOSERVER_DATA_DIR.
+ */
+ public GSShapefileDatastoreEncoder(String name, URL url) {
+ // Set fixed values
+ super(name);
+ setType(TYPE);
+
+ // Set mandatory parameter
+ ensureValidURL(url);
+ setUrl(url);
+
+ // Set default values
+ setEnabled(DEFAULT_ENABLED);
+ setCharset(Charset.forName(DEFAULT_CHARSET));
+ setCreateSpatialIndex(DEFAULT_CREATE_SPATIAL_INDEX);
+ setMemoryMappedBuffer(DEFAULT_MEMORY_MAPPED_BUFFER);
+ setCacheAndReuseMemoryMaps(DEFAULT_CACHE_AND_REUSE_MEMORY_MAPS);
+ }
+
+ /**
+ * Create a {@value #TYPE} datastore encoder from an existing store read from server.
+ *
+ * @param store The existing store.
+ * @throws IllegalArgumentException if store type or mandatory parameters are not valid
+ */
+ public GSShapefileDatastoreEncoder(RESTDataStore store) {
+ super(store);
+
+ // Check mandatory parameter validity
+ try {
+ ensureValidURL(new URL(store.getConnectionParameters().get("url")));
+ } catch (MalformedURLException e) {
+ throw new IllegalArgumentException("Shapefile store URL is malformed", e);
+ }
+ }
+
+ public void setUrl(URL url) {
+ ensureValidURL(url);
+ connectionParameters.set("url", url.toString());
+ }
+
+ public URL getUrl() {
+ try {
+ return new URL(ElementUtils.contains(connectionParameters.getRoot(), "description").getTextTrim());
+ } catch (MalformedURLException e) {
+ return null;
+ }
+ }
+
+ public void setCharset(Charset charset) {
+ connectionParameters.set("charset", charset.name());
+ }
+
+ public Charset getCharset() {
+ return Charset.forName(ElementUtils.contains(connectionParameters.getRoot(), "charset").getTextTrim());
+ }
+
+ public void setCreateSpatialIndex(boolean createSpatialIndex) {
+ connectionParameters.set("create spatial index", Boolean.toString(createSpatialIndex));
+ }
+
+ public boolean getCreateSpatialIndex() {
+ return Boolean.parseBoolean(ElementUtils.contains(connectionParameters.getRoot(), "create spatial index").getTextTrim());
+ }
+
+ public void setMemoryMappedBuffer(boolean memoryMappedBuffer) {
+ connectionParameters.set("memory mapped buffer", Boolean.toString(memoryMappedBuffer));
+ }
+
+ public boolean getMemoryMappedBuffer() {
+ return Boolean.parseBoolean(ElementUtils.contains(connectionParameters.getRoot(), "memory mapped buffer").getTextTrim());
+ }
+
+ public void setCacheAndReuseMemoryMaps(boolean cacheAndReuseMemoryMaps) {
+ connectionParameters.set("cache and reuse memory maps", Boolean.toString(cacheAndReuseMemoryMaps));
+ }
+
+ public boolean getCacheAndReuseMemoryMaps() {
+ return Boolean.parseBoolean(ElementUtils.contains(connectionParameters.getRoot(), "cache and reuse memory maps").getTextTrim());
+ }
+
+ /**
+ * Check url validity.
+ *
+ * @param url the url
+ * @throws IllegalArgumentException if url is null or empty
+ */
+ private static void ensureValidURL(URL url) {
+ if (url == null || url.toString().isEmpty()) {
+ throw new IllegalArgumentException(
+ "Shapefile store URL cannot be null or empty");
+ }
+ }
+
+ /**
+ * @return {@value #TYPE}
+ */
+ String getValidType() {
+ return TYPE;
+ }
+}
diff --git a/src/main/java/it/geosolutions/geoserver/rest/encoder/utils/NestedElementEncoder.java b/src/main/java/it/geosolutions/geoserver/rest/encoder/utils/NestedElementEncoder.java
index aaf97d8..a72dee4 100644
--- a/src/main/java/it/geosolutions/geoserver/rest/encoder/utils/NestedElementEncoder.java
+++ b/src/main/java/it/geosolutions/geoserver/rest/encoder/utils/NestedElementEncoder.java
@@ -155,7 +155,7 @@ public class NestedElementEncoder extends XmlElement {
// if some previous similar object is found
final Element search;
if ((search = ElementUtils.contains(getRoot(), new NestedElementFilter(
- getRoot(), key, value))) != null) {
+ getRoot(), key, null))) != null) {
// remove it
ElementUtils.remove(getRoot(), search);
}
diff --git a/src/test/java/it/geosolutions/geoserver/rest/publisher/GeoserverRESTCreateReadUpdateDatastoreTest.java b/src/test/java/it/geosolutions/geoserver/rest/publisher/GeoserverRESTCreateReadUpdateDatastoreTest.java
new file mode 100644
index 0000000..d56a885
--- /dev/null
+++ b/src/test/java/it/geosolutions/geoserver/rest/publisher/GeoserverRESTCreateReadUpdateDatastoreTest.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.publisher;
+
+import org.junit.Test;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.Map;
+
+import it.geosolutions.geoserver.rest.GeoServerRESTPublisher;
+import it.geosolutions.geoserver.rest.GeoserverRESTTest;
+import it.geosolutions.geoserver.rest.decoder.RESTDataStore;
+import it.geosolutions.geoserver.rest.encoder.datastore.GSAbstractDatastoreEncoder;
+import it.geosolutions.geoserver.rest.encoder.datastore.GSShapefileDatastoreEncoder;
+import it.geosolutions.geoserver.rest.encoder.datastore.GSDirectoryOfShapefilesDatastoreEncoder;
+
+/**
+ * Test datastore handling (create, read and update):
+ *
+ * - Tests all the constructors and setters from
+ * {@link GSDirectoryOfShapefilesDatastoreEncoder} and parent classes
+ * ({@link GSShapefileDatastoreEncoder}, {@link GSAbstractDatastoreEncoder}).
+ *
+ *
- Tests constructors and getters from {@link RESTDataStore} (reader).
+ *
+ *
- Tests {@link GeoServerRESTPublisher#createDatastore} and
+ * {@link GeoServerRESTPublisher#updateDatastore} methods.
+ *
+ * The sequence is:
+ *
+ * - Create a DirectoryOfShapefilesDatastoreEncoder, with default parameters.
+ *
- Publish via createDatastore.
+ *
- Read the datastore from server.
+ *
- Test all parameter values.
+ *
- Create a new Encoder from it.
+ *
- Change all datastore parameter to non-default ones.
+ *
- Update via updateDatastore.
+ *
- Read again.
+ *
- Test all new values.
+ *
+ *
+ * @author Oscar Fonts
+ */
+public class GeoserverRESTCreateReadUpdateDatastoreTest extends GeoserverRESTTest {
+
+ private static final String WS_NAME = DEFAULT_WS;
+ private static final String DS_NAME = "testCreateDatastore";
+ private static final String DS_DESCRIPTION = "A description";
+ private static URL LOCATION_1;
+ private static URL LOCATION_2;
+
+ public GeoserverRESTCreateReadUpdateDatastoreTest(String testName) throws Exception {
+ super(testName);
+ LOCATION_1 = new URL("file:data/1");
+ LOCATION_2 = new URL("file:data/2");
+ }
+
+ @Test
+ public void test() throws Exception {
+ assertTrue(enabled());
+
+ // Delete all resources except styles
+ deleteAllWorkspacesRecursively();
+
+ // Create workspace
+ assertTrue(publisher.createWorkspace(WS_NAME));
+
+ // Create a directory of spatial files with default parameters
+ GSDirectoryOfShapefilesDatastoreEncoder create = new GSDirectoryOfShapefilesDatastoreEncoder(DS_NAME, LOCATION_1);
+ assertTrue(publisher.createDatastore(WS_NAME, create));
+
+ // Read the store from server; check all parameter values
+ RESTDataStore read = reader.getDatastore(WS_NAME, DS_NAME);
+ assertEquals(read.getName(), DS_NAME);
+ assertEquals(read.getWorkspaceName(), WS_NAME);
+ assertEquals(read.isEnabled(), true);
+
+ Map connParams = read.getConnectionParameters();
+ assertEquals(connParams.get("url"), LOCATION_1.toString());
+ assertEquals(connParams.get("charset"), "ISO-8859-1");
+ assertEquals(connParams.get("create spatial index"), "true");
+ assertEquals(connParams.get("memory mapped buffer"), "false");
+ assertEquals(connParams.get("cache and reuse memory maps"), "true");
+
+ // Change all parameter to non-default values
+ GSDirectoryOfShapefilesDatastoreEncoder update = new GSDirectoryOfShapefilesDatastoreEncoder(read);
+ update.setDescription(DS_DESCRIPTION);
+ update.setEnabled(false);
+ update.setUrl(LOCATION_2);
+ update.setCharset(Charset.forName("UTF-8"));
+ update.setCreateSpatialIndex(false);
+ update.setMemoryMappedBuffer(true);
+ update.setCacheAndReuseMemoryMaps(false);
+
+ //update the store
+ assertTrue(publisher.updateDatastore(WS_NAME, update));
+
+ // Read again, check that all parameters have changed
+ read = reader.getDatastore(WS_NAME, DS_NAME);
+ assertEquals(read.getWorkspaceName(), WS_NAME);
+ assertEquals(read.isEnabled(), false);
+ connParams = read.getConnectionParameters();
+ assertEquals(connParams.get("url"), LOCATION_2.toString());
+ assertEquals(connParams.get("charset"), "UTF-8");
+ assertEquals(connParams.get("create spatial index"), "false");
+ assertEquals(connParams.get("memory mapped buffer"), "true");
+ assertEquals(connParams.get("cache and reuse memory maps"), "false");
+ }
+}
diff --git a/src/test/java/it/geosolutions/geoserver/rest/publisher/GeoserverRESTPostgisDatastoreTest.java b/src/test/java/it/geosolutions/geoserver/rest/publisher/GeoserverRESTPostgisDatastoreTest.java
index 2d76af5..2bceb7b 100644
--- a/src/test/java/it/geosolutions/geoserver/rest/publisher/GeoserverRESTPostgisDatastoreTest.java
+++ b/src/test/java/it/geosolutions/geoserver/rest/publisher/GeoserverRESTPostgisDatastoreTest.java
@@ -28,7 +28,7 @@ package it.geosolutions.geoserver.rest.publisher;
import it.geosolutions.geoserver.rest.GeoserverRESTTest;
import it.geosolutions.geoserver.rest.decoder.RESTDataStore;
-import it.geosolutions.geoserver.rest.encoder.GSPostGISDatastoreEncoder;
+import it.geosolutions.geoserver.rest.encoder.datastore.GSPostGISDatastoreEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/test/java/it/geosolutions/geoserver/rest/publisher/GeoserverRESTPublishShpCollectionTest.java b/src/test/java/it/geosolutions/geoserver/rest/publisher/GeoserverRESTPublishShpCollectionTest.java
new file mode 100644
index 0000000..c5bd0a2
--- /dev/null
+++ b/src/test/java/it/geosolutions/geoserver/rest/publisher/GeoserverRESTPublishShpCollectionTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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 java.net.URI;
+import java.util.List;
+import org.springframework.core.io.ClassPathResource;
+
+import it.geosolutions.geoserver.rest.GeoserverRESTTest;
+
+/**
+ * @author Oscar Fonts
+ */
+public class GeoserverRESTPublishShpCollectionTest extends GeoserverRESTTest {
+
+ final String workspace = DEFAULT_WS;
+ final String storeName = "testshpcollection";
+
+ public GeoserverRESTPublishShpCollectionTest(String testName) {
+ super(testName);
+ }
+
+ @Test
+ public void testLocalZip() throws Exception {
+ assertTrue(enabled());
+
+ URI location = new ClassPathResource("testdata/multipleshp.zip").getFile().toURI();
+ test(location);
+ }
+
+ @Test
+ public void testExternalDir() throws Exception {
+ assertTrue(enabled());
+
+ URI location = new ClassPathResource("testdata/multipleshapefiles").getFile().toURI();
+ test(location);
+ }
+
+ void test(URI location) throws Exception {
+
+ // Delete all resources except styles
+ deleteAllWorkspacesRecursively();
+
+ // Create workspace
+ assertTrue(publisher.createWorkspace(workspace));
+
+ // Publish shp collection
+ assertTrue(publisher.publishShpCollection(workspace, storeName, location));
+
+ // Test store type */
+ /* TODO uncomment if GEOS-5113 is accepted
+ String storeType = reader.getDatastore(workspace, storeName).getStoreType();
+ assertEquals(storeType, "Directory of spatial files (shapefiles)");
+ */
+
+ // Test published layer names
+ List layers = reader.getLayers().getNames();
+ assertTrue(layers.contains("cities"));
+ assertTrue(layers.contains("boundaries"));
+ }
+}
diff --git a/src/test/java/it/geosolutions/geoserver/rest/publisher/GeoserverRESTShapeTest.java b/src/test/java/it/geosolutions/geoserver/rest/publisher/GeoserverRESTShapeTest.java
index 8859d92..3f3ebfa 100644
--- a/src/test/java/it/geosolutions/geoserver/rest/publisher/GeoserverRESTShapeTest.java
+++ b/src/test/java/it/geosolutions/geoserver/rest/publisher/GeoserverRESTShapeTest.java
@@ -166,11 +166,12 @@ public class GeoserverRESTShapeTest extends GeoserverRESTTest {
String ns = "geosolutions";
String storeName = "resttestshp";
String layerName = "cities";
+ final String styleName = "restteststyle";
File zipFile = new ClassPathResource("testdata/resttestshp.zip").getFile();
publisher.removeDatastore(DEFAULT_WS, storeName,true);
+ publisher.removeStyle(styleName);
- final String styleName = "restteststyle";
File sldFile = new ClassPathResource("testdata/restteststyle.sld").getFile();
// insert style
diff --git a/src/test/resources/testdata/multipleshapefiles/boundaries.dbf b/src/test/resources/testdata/multipleshapefiles/boundaries.dbf
new file mode 100644
index 0000000..b245a5e
Binary files /dev/null and b/src/test/resources/testdata/multipleshapefiles/boundaries.dbf differ
diff --git a/src/test/resources/testdata/multipleshapefiles/boundaries.prj b/src/test/resources/testdata/multipleshapefiles/boundaries.prj
new file mode 100644
index 0000000..7a70628
--- /dev/null
+++ b/src/test/resources/testdata/multipleshapefiles/boundaries.prj
@@ -0,0 +1 @@
+GEOGCS["GCS_WGS_1984",DATUM["WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
diff --git a/src/test/resources/testdata/multipleshapefiles/boundaries.shp b/src/test/resources/testdata/multipleshapefiles/boundaries.shp
new file mode 100644
index 0000000..85957fa
Binary files /dev/null and b/src/test/resources/testdata/multipleshapefiles/boundaries.shp differ
diff --git a/src/test/resources/testdata/multipleshapefiles/cities.dbf b/src/test/resources/testdata/multipleshapefiles/cities.dbf
new file mode 100644
index 0000000..6b53516
Binary files /dev/null and b/src/test/resources/testdata/multipleshapefiles/cities.dbf differ
diff --git a/src/test/resources/testdata/multipleshapefiles/cities.prj b/src/test/resources/testdata/multipleshapefiles/cities.prj
new file mode 100644
index 0000000..c0c0792
Binary files /dev/null and b/src/test/resources/testdata/multipleshapefiles/cities.prj differ
diff --git a/src/test/resources/testdata/multipleshapefiles/cities.shp b/src/test/resources/testdata/multipleshapefiles/cities.shp
new file mode 100644
index 0000000..54fd672
Binary files /dev/null and b/src/test/resources/testdata/multipleshapefiles/cities.shp differ
diff --git a/src/test/resources/testdata/multipleshp.zip b/src/test/resources/testdata/multipleshp.zip
new file mode 100644
index 0000000..6a58512
Binary files /dev/null and b/src/test/resources/testdata/multipleshp.zip differ
diff --git a/src/test/resources/testdata/shapefile/cities.shx b/src/test/resources/testdata/shapefile/cities.shx
deleted file mode 100644
index 6817e44..0000000
Binary files a/src/test/resources/testdata/shapefile/cities.shx and /dev/null differ