From 434b9ec61c0172ed05a6ba62a3647fd2fb3778f4 Mon Sep 17 00:00:00 2001 From: ETj Date: Tue, 24 May 2011 10:24:20 +0200 Subject: [PATCH] Added method for creating PostGIS datastores (with some code from E.Grosso). Improved encoding of lists inside xml payloads. --- gitignore | 14 ++ .../rest/GeoServerRESTPublisher.java | 87 +++++---- .../geoserver/rest/decoder/utils/package.html | 2 +- .../rest/encoder/GSCoverageEncoder.java | 37 ++-- .../rest/encoder/GSLayerEncoder.java | 2 + .../encoder/GSPostGISDatastoreEncoder.java | 170 ++++++++++++++++++ .../rest/encoder/GSResourceEncoder.java | 2 + .../rest/encoder/GSWorkspaceEncoder.java | 2 + .../encoder/utils/EntryKeyListEncoder.java | 71 ++++++++ .../{ => utils}/PropertyXMLEncoder.java | 37 ++-- .../encoder/utils/TextNodeListEncoder.java | 79 ++++++++ .../geoserver/rest/encoder/utils/package.html | 3 + .../GeoserverRESTPostgisDatastoreTest.java | 130 ++++++++++++++ .../geoserver/rest/GeoserverRESTTest.java | 11 +- 14 files changed, 580 insertions(+), 67 deletions(-) create mode 100644 gitignore create mode 100644 src/main/java/it/geosolutions/geoserver/rest/encoder/GSPostGISDatastoreEncoder.java create mode 100644 src/main/java/it/geosolutions/geoserver/rest/encoder/utils/EntryKeyListEncoder.java rename src/main/java/it/geosolutions/geoserver/rest/encoder/{ => utils}/PropertyXMLEncoder.java (75%) create mode 100644 src/main/java/it/geosolutions/geoserver/rest/encoder/utils/TextNodeListEncoder.java create mode 100644 src/main/java/it/geosolutions/geoserver/rest/encoder/utils/package.html create mode 100644 src/test/java/it/geosolutions/geoserver/rest/GeoserverRESTPostgisDatastoreTest.java diff --git a/gitignore b/gitignore new file mode 100644 index 0000000..651e70d --- /dev/null +++ b/gitignore @@ -0,0 +1,14 @@ +## +## This file has been automatically generated with the command line: +## for pom in $(find -name "pom.xml") ; do path=${pom%*pom.xml} ; echo '#' $path ; echo ; echo ${path}target ; echo ; done > .gitignore +## +## - ETj + +nb*.xml +.classpath +.project +.settings +# ./ + +./target + diff --git a/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java b/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java index cb05d86..fd87017 100644 --- a/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java +++ b/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java @@ -22,7 +22,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - package it.geosolutions.geoserver.rest; import it.geosolutions.geoserver.rest.decoder.RESTCoverageList; @@ -30,6 +29,7 @@ import it.geosolutions.geoserver.rest.decoder.RESTCoverageStore; import it.geosolutions.geoserver.rest.encoder.GSCoverageEncoder; import it.geosolutions.geoserver.rest.encoder.GSFeatureTypeEncoder; import it.geosolutions.geoserver.rest.encoder.GSLayerEncoder; +import it.geosolutions.geoserver.rest.encoder.GSPostGISDatastoreEncoder; import it.geosolutions.geoserver.rest.encoder.GSWorkspaceEncoder; import java.io.File; @@ -68,7 +68,6 @@ public class GeoServerRESTPublisher { this.gspass = password; } - //========================================================================== //=== WORKSPACES //========================================================================== @@ -139,8 +138,9 @@ public class GeoServerRESTPublisher { */ public boolean publishStyle(File sldFile, String name) { String sUrl = restURL + "/rest/styles"; - if(name != null) + if (name != null) { sUrl += "?name=" + encode(name); + } LOGGER.debug("POSTing new style " + name + " to " + sUrl); String result = HTTPUtils.post(sUrl, sldFile, "application/vnd.ogc.sld+xml", gsuser, gspass); return result != null; @@ -162,6 +162,25 @@ public class GeoServerRESTPublisher { return HTTPUtils.delete(sUrl, gsuser, gspass); } + //========================================================================== + //=== DATASTORE + //========================================================================== + + /** + * Create a PostGIS datastore. + * + * @param workspace Name of the workspace to contain the database. This will also be the prefix of any layer names created from tables in the database. + * @param datastoreEncoder the set of parameters to be set to the datastore (including connection params) + * + * @return true if the PostGIS datastore has been successfully created, false otherwise + */ + public boolean createPostGISDatastore(String workspace, GSPostGISDatastoreEncoder datastoreEncoder) { + String sUrl = restURL + "/rest/workspaces/" + workspace + "/datastores/"; + String xml = datastoreEncoder.encodeXml(); + String result = HTTPUtils.postXml(sUrl, xml, gsuser, gspass); + return result != null; + } + //========================================================================== //=== SHAPEFILES //========================================================================== @@ -201,6 +220,7 @@ public class GeoServerRESTPublisher { layerEncoder.setDefaultStyle(defaultStyle); configureLayer(layerEncoder, layerName); } catch (Exception e) { + LOGGER.warn("Error in publishing shapefile " + e.getMessage(), e); sent = false; } } @@ -226,7 +246,10 @@ public class GeoServerRESTPublisher { */ public boolean publishShp(String workspace, String storename, String layername, File zipFile, String srs) throws FileNotFoundException { // build full URL - StringBuilder sbUrl = new StringBuilder(restURL).append("/rest/workspaces/").append(workspace).append("/datastores/").append(storename).append("/file.shp?"); + StringBuilder sbUrl = new StringBuilder(restURL) + .append("/rest/workspaces/").append(workspace) + .append("/datastores/").append(storename) + .append("/file.shp?"); // if (workspace != null) { // sbUrl.append("namespace=").append(workspace); // } @@ -246,7 +269,7 @@ public class GeoServerRESTPublisher { GSFeatureTypeEncoder fte = new GSFeatureTypeEncoder(); fte.setName(layername); fte.setSRS(srs); - + String configuredResult = HTTPUtils.putXml(postUrl.toString(), fte.encodeXml(), this.gsuser, this.gspass); boolean shpConfigured = configuredResult != null; @@ -288,13 +311,13 @@ public class GeoServerRESTPublisher { fte.setName(layername); fte.setSRS(srs); // srs=null?"EPSG:4326":srs); String ftypeXml = fte.encodeXml(); - + String configuredResult = HTTPUtils.postXml(postUrl.toString(), ftypeXml, this.gsuser, this.gspass); boolean published = configuredResult != null; boolean configured = false; if (!published) { - LOGGER.warn("Error in publishing ("+configuredResult+") " + LOGGER.warn("Error in publishing (" + configuredResult + ") " + workspace + ":" + storename + "/" + layername); } else { LOGGER.info("DB layer successfully added (layer:" + layername + ")"); @@ -304,7 +327,7 @@ public class GeoServerRESTPublisher { configured = configureLayer(layerEncoder, layername); if (!configured) { - LOGGER.warn("Error in configuring ("+configuredResult+") " + LOGGER.warn("Error in configuring (" + configuredResult + ") " + workspace + ":" + storename + "/" + layername); } else { LOGGER.info("DB layer successfully configured (layer:" + layername + ")"); @@ -353,12 +376,12 @@ public class GeoServerRESTPublisher { String sendResult = HTTPUtils.put(sUrl, geotiff.toURI().toString(), "text/plain", gsuser, gspass); RESTCoverageStore store = RESTCoverageStore.build(sendResult); - if (store!=null) { + if (store != null) { try { // // retrieve coverage name GeoServerRESTReader reader = new GeoServerRESTReader(restURL, gsuser, gspass); RESTCoverageList covList = reader.getCoverages(workspace, storeName); - if(covList.isEmpty()) { + if (covList.isEmpty()) { LOGGER.error("No coverages found in new coveragestore " + storeName); return null; } @@ -433,10 +456,10 @@ public class GeoServerRESTPublisher { GSLayerEncoder layerEncoder = new GSLayerEncoder(); layerEncoder.setDefaultStyle(defaultStyle); - + return publishExternalMosaic(workspace, storeName, mosaicDir, coverageEncoder, layerEncoder); } - + /** * Publish a Mosaic already in a filesystem readable by GeoServer. * @@ -456,30 +479,32 @@ public class GeoServerRESTPublisher { */ public RESTCoverageStore publishExternalMosaic(String workspace, String storeName, File mosaicDir, GSCoverageEncoder coverageEncoder, GSLayerEncoder layerEncoder) throws FileNotFoundException { RESTCoverageStore store = configureExternaMosaicDatastore(workspace, storeName, mosaicDir); - - if(coverageEncoder == null ) { - if(LOGGER.isDebugEnabled()) + + if (coverageEncoder == null) { + if (LOGGER.isDebugEnabled()) { LOGGER.debug("no coverageEncoder provided for " + workspace + ":" + storeName); + } coverageEncoder = new GSCoverageEncoder(); } - if(layerEncoder == null ) { - if(LOGGER.isDebugEnabled()) + if (layerEncoder == null) { + if (LOGGER.isDebugEnabled()) { LOGGER.debug("no layerEncoder provided for " + workspace + ":" + storeName); + } layerEncoder = new GSLayerEncoder(); } - - if (store != null ) { + + if (store != null) { try { // // retrieve coverage name GeoServerRESTReader reader = new GeoServerRESTReader(restURL, gsuser, gspass); RESTCoverageList covList = reader.getCoverages(workspace, storeName); - if(covList.isEmpty()) { + if (covList.isEmpty()) { LOGGER.error("No coverages found in new coveragestore " + storeName); return null; } String coverageName = covList.get(0).getName(); - + configureCoverage(coverageEncoder, workspace, storeName, coverageName); configureLayer(layerEncoder, storeName); @@ -636,12 +661,12 @@ public class GeoServerRESTPublisher { public boolean removeWorkspace(String workspace) { workspace = sanitize(workspace); try { - URL deleteUrl = new URL(restURL + "/rest/workspaces/" + workspace ); + URL deleteUrl = new URL(restURL + "/rest/workspaces/" + workspace); boolean deleted = HTTPUtils.delete(deleteUrl.toExternalForm(), gsuser, gspass); if (!deleted) { - LOGGER.warn("Could not delete Workspace " + workspace ); + LOGGER.warn("Could not delete Workspace " + workspace); } else { - LOGGER.info("Workspace successfully deleted " + workspace ); + LOGGER.info("Workspace successfully deleted " + workspace); } return deleted; @@ -691,7 +716,7 @@ public class GeoServerRESTPublisher { LOGGER.info("Layer successfully configured: " + layerName); } } else { - LOGGER.warn("Error configuring layer " + layerName + " ("+sendResult+")"); + LOGGER.warn("Error configuring layer " + layerName + " (" + sendResult + ")"); } return sendResult != null; @@ -703,16 +728,16 @@ public class GeoServerRESTPublisher { */ protected boolean configureCoverage(final GSCoverageEncoder ce, String wsname, String csname, String cname) { - final String url = restURL + "/rest/workspaces/"+wsname+"/coveragestores/"+csname+"/coverages/"+cname+".xml"; + final String url = restURL + "/rest/workspaces/" + wsname + "/coveragestores/" + csname + "/coverages/" + cname + ".xml"; String xmlBody = ce.encodeXml(); String sendResult = HTTPUtils.putXml(url, xmlBody, gsuser, gspass); if (sendResult != null) { if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Coverage successfully configured "+wsname+":"+csname+":"+cname); + LOGGER.debug("Coverage successfully configured " + wsname + ":" + csname + ":" + cname); } } else { - LOGGER.warn("Error configuring coverage " + wsname+":"+csname+":"+cname +" ("+sendResult+")"); + LOGGER.warn("Error configuring coverage " + wsname + ":" + csname + ":" + cname + " (" + sendResult + ")"); } return sendResult != null; @@ -722,13 +747,13 @@ public class GeoServerRESTPublisher { * */ protected String sanitize(String s) { - if(s.indexOf(".")!=-1) - return s+".DUMMY"; + if (s.indexOf(".") != -1) { + return s + ".DUMMY"; + } return s; } protected String encode(String s) { return URLEncoder.encode(s); } - } diff --git a/src/main/java/it/geosolutions/geoserver/rest/decoder/utils/package.html b/src/main/java/it/geosolutions/geoserver/rest/decoder/utils/package.html index ceb81b2..7ecd435 100644 --- a/src/main/java/it/geosolutions/geoserver/rest/decoder/utils/package.html +++ b/src/main/java/it/geosolutions/geoserver/rest/decoder/utils/package.html @@ -1,3 +1,3 @@ -Some util classes. +Some util classes for decoders. \ No newline at end of file diff --git a/src/main/java/it/geosolutions/geoserver/rest/encoder/GSCoverageEncoder.java b/src/main/java/it/geosolutions/geoserver/rest/encoder/GSCoverageEncoder.java index aead2dd..c512958 100644 --- a/src/main/java/it/geosolutions/geoserver/rest/encoder/GSCoverageEncoder.java +++ b/src/main/java/it/geosolutions/geoserver/rest/encoder/GSCoverageEncoder.java @@ -1,6 +1,6 @@ /* * GeoServer-Manager - Simple Manager Library for GeoServer - * + * * Copyright (C) 2007,2011 GeoSolutions S.A.S. * http://www.geo-solutions.it * @@ -10,10 +10,10 @@ * 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 @@ -25,39 +25,38 @@ package it.geosolutions.geoserver.rest.encoder; -import java.util.HashMap; -import java.util.Map; +import it.geosolutions.geoserver.rest.encoder.utils.EntryKeyListEncoder; +import it.geosolutions.geoserver.rest.encoder.utils.TextNodeListEncoder; import org.jdom.Element; /** - * + * Creates an XML + * * @author ETj (etj at geo-solutions.it) */ public class GSCoverageEncoder extends GSResourceEncoder { - private Map metadata = new HashMap(); + private EntryKeyListEncoder metadataEncoder = new EntryKeyListEncoder("metadata"); + private TextNodeListEncoder keywordsListEncoder = new TextNodeListEncoder("keywords"); + public GSCoverageEncoder() { super("coverage"); set("enabled", "true"); } - + public void addMetadata(String key, String value) { - metadata.put(key, value); + metadataEncoder.add(key, value); + } + + public void addKeyword(String keyword) { + keywordsListEncoder.add("string", keyword); } @Override protected void addNodesBeforeOutput(Element e) { super.addNodesBeforeOutput(e); - - if( ! metadata.isEmpty() ) { - Element md = new Element("metadata"); - for (Map.Entry entry : metadata.entrySet()) { - md.addContent("entry") - .setAttribute("key", entry.getKey()) - .setText(entry.getValue()); - } - e.addContent(md); - } + keywordsListEncoder.attachList(e); + metadataEncoder.attachList(e); } } diff --git a/src/main/java/it/geosolutions/geoserver/rest/encoder/GSLayerEncoder.java b/src/main/java/it/geosolutions/geoserver/rest/encoder/GSLayerEncoder.java index 0ae7c83..274844f 100644 --- a/src/main/java/it/geosolutions/geoserver/rest/encoder/GSLayerEncoder.java +++ b/src/main/java/it/geosolutions/geoserver/rest/encoder/GSLayerEncoder.java @@ -25,6 +25,8 @@ package it.geosolutions.geoserver.rest.encoder; +import it.geosolutions.geoserver.rest.encoder.utils.PropertyXMLEncoder; + /** * * @author ETj (etj at geo-solutions.it) diff --git a/src/main/java/it/geosolutions/geoserver/rest/encoder/GSPostGISDatastoreEncoder.java b/src/main/java/it/geosolutions/geoserver/rest/encoder/GSPostGISDatastoreEncoder.java new file mode 100644 index 0000000..bbb49e9 --- /dev/null +++ b/src/main/java/it/geosolutions/geoserver/rest/encoder/GSPostGISDatastoreEncoder.java @@ -0,0 +1,170 @@ +/* + * GeoServer-Manager - Simple Manager Library for GeoServer + * + * Copyright (C) 2007,2011 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.EntryKeyListEncoder; +import it.geosolutions.geoserver.rest.encoder.utils.PropertyXMLEncoder; +import org.jdom.Element; + +/** + * Geoserver datastore XML encoder. + * + * @author Eric Grosso + * @author ETj + */ +public class GSPostGISDatastoreEncoder extends PropertyXMLEncoder { + + private EntryKeyListEncoder connectionParameters = new EntryKeyListEncoder("connectionParameters"); + + + public GSPostGISDatastoreEncoder() { + super("dataStore"); + setType("PostGIS"); // may be overwritten with e.g. "PostGIS (JNDI)" + setDatabaseType("postgis"); + } + + /** + * Set some initial defaults. + *

+ * The default parameters are as follows:
    + *
  • maximum connections: 10,
  • + *
  • minimum connections: 1,
  • + *
  • fetch size: 1000,
  • + *
  • connection timeout: 20 seconds,
  • + *
  • loose BBox: true,
  • + *
  • prepared statements: false,
  • + *
  • maximum open prepared statements: 50.
  • + *
+ */ + public void defaultInit() { + setMinConnections(1); + setMaxConnections(10); + setFetchSize(1000); + setConnectionTimeout(20); + setLooseBBox(true); + setPreparedStatements(false); + setMaxOpenPreparedStatements(50); + } + + public void setName(String name) { + setOrRemove("name", name); + } + + public void setDescription(String description) { + setOrRemove("description", description); + } + + public void setType(String type) { + setOrRemove("type", type); + } + + public void setEnabled(boolean enabled) { + setOrRemove("enabled", Boolean.toString(enabled)); + } + + public void setNamespace(String namespace) { + connectionParameters.add("namespace", namespace); + } + + public void setHost(String host) { + connectionParameters.add("host", host); + } + + public void setPort(int port) { + connectionParameters.add("port", Integer.toString(port)); + } + + public void setDatabase(String database) { + connectionParameters.add("database", database); + } + + public void setSchema(String schema) { + connectionParameters.add("schema", schema); + } + + public void setUser(String user) { + connectionParameters.add("user", user); + } + + public void setPassword(String password) { + connectionParameters.add("passwd", password); + } + + public void setDatabaseType(String dbtype) { + connectionParameters.add("dbtype", dbtype); + } + + public void setJndiReferenceName(String jndiReferenceName) { + connectionParameters.add("jndiReferenceName", jndiReferenceName); + } + + public void setExposePrimaryKeys(boolean exposePrimaryKeys) { + connectionParameters.add("Expose primary keys", Boolean.toString(exposePrimaryKeys)); + } + + public void setMaxConnections(int maxConnections) { + connectionParameters.add("max connections", Integer.toString(maxConnections)); + } + + public void setMinConnections(int minConnections) { + connectionParameters.add("min connections", Integer.toString(minConnections)); + } + + public void setFetchSize(int fetchSize) { + connectionParameters.add("fetch size", Integer.toString(fetchSize)); + } + + public void setConnectionTimeout(int seconds) { + connectionParameters.add("Connection timeout", Integer.toString(seconds)); + } + + public void setValidateConnections(boolean validateConnections) { + connectionParameters.add("validate connections", Boolean.toString(validateConnections)); + } + + public void setPrimaryKeyMetadataTable(String primaryKeyMetadataTable) { + connectionParameters.add("Primary key metadata table", primaryKeyMetadataTable); + } + + public void setLooseBBox(boolean looseBBox) { + connectionParameters.add("Loose bbox", Boolean.toString(looseBBox)); + } + + public void setPreparedStatements(boolean preparedStatements) { + connectionParameters.add("preparedStatements", Boolean.toString(preparedStatements)); + } + + public void setMaxOpenPreparedStatements(int maxOpenPreparedStatements) { + connectionParameters.add("Max open prepared statements", Integer.toString(maxOpenPreparedStatements)); + } + + @Override + protected void addNodesBeforeOutput(Element e) { + super.addNodesBeforeOutput(e); + connectionParameters.attachList(e); + } + +} \ No newline at end of file diff --git a/src/main/java/it/geosolutions/geoserver/rest/encoder/GSResourceEncoder.java b/src/main/java/it/geosolutions/geoserver/rest/encoder/GSResourceEncoder.java index d2dbc6d..0e27b78 100644 --- a/src/main/java/it/geosolutions/geoserver/rest/encoder/GSResourceEncoder.java +++ b/src/main/java/it/geosolutions/geoserver/rest/encoder/GSResourceEncoder.java @@ -25,6 +25,8 @@ package it.geosolutions.geoserver.rest.encoder; +import it.geosolutions.geoserver.rest.encoder.utils.PropertyXMLEncoder; + /** * * @author ETj (etj at geo-solutions.it) diff --git a/src/main/java/it/geosolutions/geoserver/rest/encoder/GSWorkspaceEncoder.java b/src/main/java/it/geosolutions/geoserver/rest/encoder/GSWorkspaceEncoder.java index 350a9ce..86c5321 100644 --- a/src/main/java/it/geosolutions/geoserver/rest/encoder/GSWorkspaceEncoder.java +++ b/src/main/java/it/geosolutions/geoserver/rest/encoder/GSWorkspaceEncoder.java @@ -25,6 +25,8 @@ package it.geosolutions.geoserver.rest.encoder; +import it.geosolutions.geoserver.rest.encoder.utils.PropertyXMLEncoder; + /** * * @author ETj (etj at geo-solutions.it) diff --git a/src/main/java/it/geosolutions/geoserver/rest/encoder/utils/EntryKeyListEncoder.java b/src/main/java/it/geosolutions/geoserver/rest/encoder/utils/EntryKeyListEncoder.java new file mode 100644 index 0000000..a931ac4 --- /dev/null +++ b/src/main/java/it/geosolutions/geoserver/rest/encoder/utils/EntryKeyListEncoder.java @@ -0,0 +1,71 @@ +/* + * GeoServer-Manager - Simple Manager Library for GeoServer + * + * Copyright (C) 2007,2011 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.utils; + +import java.util.HashMap; +import java.util.Map; +import org.jdom.Element; + +/** + * Encodes lists of entries with key attribute. + *
e.g.: + *
+ * {@code 
+ *  
+ *   val1
+ *   val2
+ *   val3
+ * }
+ * 
+ *
+ * @author ETj (etj at geo-solutions.it)
+ */
+public class EntryKeyListEncoder {
+
+    private Map metadata = new HashMap();
+    private final String listName;
+
+    public EntryKeyListEncoder(String listName) {
+        this.listName = listName;
+    }
+    
+    public void add(String key, String value) {
+        metadata.put(key, value);
+    }
+
+    public void attachList(Element e) {
+        
+        if( ! metadata.isEmpty() ) {
+            Element md = new Element(listName);
+            for (Map.Entry entry : metadata.entrySet()) {
+                md.addContent("entry")
+                        .setAttribute("key", entry.getKey())
+                        .setText(entry.getValue());
+            }
+            e.addContent(md);
+        }
+    }
+}
diff --git a/src/main/java/it/geosolutions/geoserver/rest/encoder/PropertyXMLEncoder.java b/src/main/java/it/geosolutions/geoserver/rest/encoder/utils/PropertyXMLEncoder.java
similarity index 75%
rename from src/main/java/it/geosolutions/geoserver/rest/encoder/PropertyXMLEncoder.java
rename to src/main/java/it/geosolutions/geoserver/rest/encoder/utils/PropertyXMLEncoder.java
index fc869c6..dc77a2a 100644
--- a/src/main/java/it/geosolutions/geoserver/rest/encoder/PropertyXMLEncoder.java
+++ b/src/main/java/it/geosolutions/geoserver/rest/encoder/utils/PropertyXMLEncoder.java
@@ -23,7 +23,7 @@
  * THE SOFTWARE.
  */
 
-package it.geosolutions.geoserver.rest.encoder;
+package it.geosolutions.geoserver.rest.encoder.utils;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -33,13 +33,15 @@ import org.jdom.output.XMLOutputter;
 
 /**
  * Creates an XML document by mapping properties to XML nodes.
- * You can set the root element in the constructor. - * Any key/value pair will be encoded as value node. + * You can set the root element name in the constructor. + * Any key/value pair will be encoded as {@code value} node.

+ * + *

Nested nodes

* Any key containing one or more slash ("/") will be encoded as nested nodes; - *

e.g.:

- *
 {@code key = "k1/k2/k3", value = "value" }
- * will be encoded as - *
 {@code value }
+ *
e.g.: + *
 {@code 
+ *          key = "k1/k2/k3", value = "value" }
will be encoded as + *
 {@code        value }
* * @author ETj (etj at geo-solutions.it) */ @@ -69,20 +71,29 @@ public class PropertyXMLEncoder { return configElements.isEmpty(); } + /** + * @return an xml document representing the stored properties. + */ public String encodeXml() { - Element layer = new Element(rootName); + Element root = new Element(rootName); for (String key : configElements.keySet()) { final String value = configElements.get(key); - add(layer, key, value); + add(root, key, value); } - addNodesBeforeOutput(layer); - return OUTPUTTER.outputString(layer); + addNodesBeforeOutput(root); + return OUTPUTTER.outputString(root); } - protected void addNodesBeforeOutput(Element e) { - + /** + * Subclasses may need to override this method if some more info in the XML + * string are needed when calling {@link #encodeXml() encodeXml()}. + * + * @param root the root element that will be converted into String by encodeXml + */ + protected void addNodesBeforeOutput(Element root) { + // nothing to do, just override when needed. } private void add(Element e, String key, String value) { diff --git a/src/main/java/it/geosolutions/geoserver/rest/encoder/utils/TextNodeListEncoder.java b/src/main/java/it/geosolutions/geoserver/rest/encoder/utils/TextNodeListEncoder.java new file mode 100644 index 0000000..2cf27e5 --- /dev/null +++ b/src/main/java/it/geosolutions/geoserver/rest/encoder/utils/TextNodeListEncoder.java @@ -0,0 +1,79 @@ +/* + * GeoServer-Manager - Simple Manager Library for GeoServer + * + * Copyright (C) 2007,2011 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.utils; + +import java.util.ArrayList; +import java.util.List; +import org.jdom.Element; + +/** + * Encodes lists of simple text nodes. + *
e.g.: + *
+ * {@code 
+ *  
+ *   nodetext1
+ *   nodetext2
+ *   nodetext3
+ * }
+ * 
+ * 
+ * @author ETj (etj at geo-solutions.it)
+ */
+public class TextNodeListEncoder {
+
+    private List list = new ArrayList();
+    private final String listName;
+
+    public TextNodeListEncoder(String listName) {
+        this.listName = listName;
+    }   
+                    
+    public void add(String nodename, String nodetext) {
+        list.add(new Pair(nodename, nodetext));
+    }
+
+    public void attachList(Element e) {
+        
+        if( ! list.isEmpty() ) {
+            Element elist = new Element(listName);
+            for (Pair pair : list) {
+                elist.addContent(pair.v1).setText(pair.v2);
+            }
+            e.addContent(elist);
+        }
+    }
+    
+    class Pair {
+        String v1;
+        String v2;
+
+        public Pair(String v1, String v2) {
+            this.v1 = v1;
+            this.v2 = v2;
+        }
+    }
+}
diff --git a/src/main/java/it/geosolutions/geoserver/rest/encoder/utils/package.html b/src/main/java/it/geosolutions/geoserver/rest/encoder/utils/package.html
new file mode 100644
index 0000000..58bda61
--- /dev/null
+++ b/src/main/java/it/geosolutions/geoserver/rest/encoder/utils/package.html
@@ -0,0 +1,3 @@
+
+Some util classes for encoders.
+
\ No newline at end of file
diff --git a/src/test/java/it/geosolutions/geoserver/rest/GeoserverRESTPostgisDatastoreTest.java b/src/test/java/it/geosolutions/geoserver/rest/GeoserverRESTPostgisDatastoreTest.java
new file mode 100644
index 0000000..2930d6c
--- /dev/null
+++ b/src/test/java/it/geosolutions/geoserver/rest/GeoserverRESTPostgisDatastoreTest.java
@@ -0,0 +1,130 @@
+/*
+ *  GeoServer-Manager - Simple Manager Library for GeoServer
+ *  
+ *  Copyright (C) 2007,2011 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;
+
+
+import it.geosolutions.geoserver.rest.decoder.RESTDataStore;
+import it.geosolutions.geoserver.rest.encoder.GSPostGISDatastoreEncoder;
+import org.apache.log4j.Logger;
+
+/**
+ * Testcase for creating postgis-based resources on geoserver.
+ * 

+ * Since these tests require a running postgis instance, this is more like integration tests.
+ * You may skip them by defining

+ *        -DpgIgnore=true 
+ * When pgIgnore is defined that way, failing tests will not break + * the build: they will be logged as errors instead. + * + *

+ * The target postgis instance can be customized by defining the following env vars:

    + *
  • pgHost (default localhost)
  • + *
  • pgPort (default: 5432)
  • + *
  • pgDatabase (default: test)
  • + *
  • pgSchema (default: public)
  • + *
  • pgUser (default: utest)
  • + *
  • pgPassword (default: ptest)
  • + *
+ * + * @author etj + * @author Eric Grosso + * + * @see GeoserverRESTTest + */ +public class GeoserverRESTPostgisDatastoreTest extends GeoserverRESTTest { + + private final static Logger LOGGER = Logger.getLogger(GeoserverRESTPostgisDatastoreTest.class); + private static final String DEFAULT_WS = "it.geosolutions"; + + private final boolean pgIgnore; + private final String pgHost; + private final int pgPort; + private final String pgDatabase; + private final String pgSchema; + private final String pgUser; + private final String pgPassword; + + public GeoserverRESTPostgisDatastoreTest(String testName) { + super(testName); + + pgIgnore = System.getProperty("pgIgnore", "false").equalsIgnoreCase("true"); + pgHost = System.getProperty("pgHost", "localhost"); + pgPort = Integer.parseInt(System.getProperty("pgPort", "5432")); + pgDatabase = System.getProperty("pgDatabase", "test"); + pgSchema = System.getProperty("pgSchema", "public"); + pgUser = System.getProperty("pgUser", "utest"); + pgPassword = System.getProperty("pgPassword", "ptest"); + } + + public void testCreateDeletePostGISDatastore() { + if (!enabled()) { + return; + } + + String wsName = "it.geosolutions"; + String datastoreName = "resttestpostgis"; + String description = "description"; + String dsNamespace = "http://www.geo-solutions.it"; + boolean exposePrimaryKeys = true; + boolean validateConnections = false; + String primaryKeyMetadataTable = "test"; + + GSPostGISDatastoreEncoder datastoreEncoder = new GSPostGISDatastoreEncoder(); + datastoreEncoder.defaultInit(); + datastoreEncoder.setName(datastoreName); + datastoreEncoder.setDescription(description); + datastoreEncoder.setNamespace(dsNamespace); + datastoreEncoder.setHost(pgHost); + datastoreEncoder.setPort(pgPort); + datastoreEncoder.setDatabase(pgDatabase); + datastoreEncoder.setSchema(pgSchema); + datastoreEncoder.setUser(pgUser); + datastoreEncoder.setPassword(pgPassword); + datastoreEncoder.setExposePrimaryKeys(exposePrimaryKeys); + datastoreEncoder.setValidateConnections(validateConnections); + datastoreEncoder.setPrimaryKeyMetadataTable(primaryKeyMetadataTable); + + // creation test + boolean created = publisher.createPostGISDatastore(wsName, datastoreEncoder); + + if( ! pgIgnore ) + assertTrue("PostGIS datastore not created", created); + else if( ! created) + LOGGER.error("*** Datastore " + datastoreName + " has not been created."); + + + RESTDataStore datastore = reader.getDatastore(wsName, datastoreName); + LOGGER.info("The type of the created datastore is: " + datastore.getType()); + + // removing test + boolean removed = publisher.removeDatastore(wsName, datastoreName); + if( ! pgIgnore ) + assertTrue("PostGIS datastore not removed", removed); + else if( ! removed ) + LOGGER.error("*** Datastore " + datastoreName + " has not been removed."); + } + +} diff --git a/src/test/java/it/geosolutions/geoserver/rest/GeoserverRESTTest.java b/src/test/java/it/geosolutions/geoserver/rest/GeoserverRESTTest.java index 2d50bac..142ba6c 100644 --- a/src/test/java/it/geosolutions/geoserver/rest/GeoserverRESTTest.java +++ b/src/test/java/it/geosolutions/geoserver/rest/GeoserverRESTTest.java @@ -42,9 +42,14 @@ import org.apache.log4j.Logger; /** * Initializes REST params. *

- * Default target geoserver instance is at http://localhost:8080/geoserver. - *
Connection parameters can be customized by defining env vars - * resturl, restuser, restpw, + * These tests are destructive, so you have to explicitly enable them + * by setting the env var resttest to true. + *

+ * The target geoserver instance can be customized by defining the following env vars:

    + *
  • resturl (default http://localhost:8080/geoserver)
  • + *
  • restuser (default: admin)
  • + *
  • restpw (default: geoserver)
  • + *
* * @author etj */