diff --git a/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java b/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java index 9b703ce..2691b12 100644 --- a/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java +++ b/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java @@ -26,6 +26,7 @@ package it.geosolutions.geoserver.rest; import it.geosolutions.geoserver.rest.decoder.RESTCoverageList; import it.geosolutions.geoserver.rest.decoder.RESTCoverageStore; +import it.geosolutions.geoserver.rest.decoder.RESTStructuredCoverageGranulesList; import it.geosolutions.geoserver.rest.decoder.utils.NameLinkElem; import it.geosolutions.geoserver.rest.encoder.GSBackupEncoder; import it.geosolutions.geoserver.rest.encoder.GSLayerEncoder; @@ -37,9 +38,11 @@ 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.feature.GSFeatureTypeEncoder; +import it.geosolutions.geoserver.rest.manager.GeoServerRESTStructuredCoverageGridReaderManager; import java.io.File; import java.io.FileNotFoundException; +import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; @@ -2537,7 +2540,7 @@ public class GeoServerRESTPublisher { * * configured - Only setup or configured feature types are returned. This is the default value. available - Only unconfigured feature types * (not yet setup) but are available from the specified datastore will be returned. available_with_geom - Same as available but only - * includes feature types that have a geometry attribute. all - The union of configured and available. + * includes feature types that have a geometry granule. all - The union of configured and available. * * * @return true if success @@ -2647,4 +2650,94 @@ public class GeoServerRESTPublisher { return URLEncoder.encode(s); // } } + + // ==> StructuredCoverageGridReader + + /** + * Create a store or harvest the coverage from the provided external path. + * + * @param workspace the GeoServer workspace + * @param coverageStore the GeoServer coverageStore + * @param format the format of the file to upload + * @param the absolut path to the file to upload + * + * @return true if the call succeeds or false otherwise. + */ + public boolean createOrHarvestExternal(String workspace, String coverageStore, String format, String path) { + try { + GeoServerRESTStructuredCoverageGridReaderManager manager = + new GeoServerRESTStructuredCoverageGridReaderManager(new URL(restURL), gsuser, gspass); + return manager.createOrHarvestExternal(workspace, coverageStore, format, path); + } catch (IllegalArgumentException e) { + if(LOGGER.isInfoEnabled()){ + LOGGER.info(e.getLocalizedMessage(),e); + } + } catch (MalformedURLException e) { + if(LOGGER.isInfoEnabled()){ + LOGGER.info(e.getLocalizedMessage(),e); + } + } + return false; + } + + /** + * Remove a granule from a structured coverage by id. + * + * @param workspace the GeoServer workspace + * @param coverageStore the GeoServer coverageStore + * @param coverage the name of the target coverage from which we are going to remove + * @param filter the absolute path to the file to upload + * + * @return null in case the call does not succeed, or an instance of {@link RESTStructuredCoverageGranulesList}. + * + * @throws MalformedURLException + * @throws UnsupportedEncodingException + */ + public boolean removeGranuleById(final String workspace, String coverageStore, String coverage, String granuleId) { + try { + GeoServerRESTStructuredCoverageGridReaderManager manager = + new GeoServerRESTStructuredCoverageGridReaderManager(new URL(restURL), gsuser, gspass); + return manager.removeGranuleById(workspace, coverageStore, coverage, granuleId); + } catch (IllegalArgumentException e) { + if(LOGGER.isInfoEnabled()){ + LOGGER.info(e.getLocalizedMessage(),e); + } + } catch (MalformedURLException e) { + if(LOGGER.isInfoEnabled()){ + LOGGER.info(e.getLocalizedMessage(),e); + } + } + return false; + } + /** + * Remove granules from a structured coverage, by providing a CQL filter. + * + * @param workspace the GeoServer workspace + * @param coverageStore the GeoServer coverageStore + * @param coverage the name of the target coverage from which we are going to remove + * @param filter the absolute path to the file to upload + * + * @return null in case the call does not succeed, or an instance of {@link RESTStructuredCoverageGranulesList}. + * + * @throws MalformedURLException + * @throws UnsupportedEncodingException + */ + public boolean removeGranulesByCQL(final String workspace, String coverageStore,String coverage, String filter) throws UnsupportedEncodingException{ + try { + GeoServerRESTStructuredCoverageGridReaderManager manager = + new GeoServerRESTStructuredCoverageGridReaderManager(new URL(restURL), gsuser, gspass); + return manager.removeGranulesByCQL(workspace, coverageStore, coverage, filter); + } catch (IllegalArgumentException e) { + if(LOGGER.isInfoEnabled()){ + LOGGER.info(e.getLocalizedMessage(),e); + } + } catch (MalformedURLException e) { + if(LOGGER.isInfoEnabled()){ + LOGGER.info(e.getLocalizedMessage(),e); + } + } + return false; + + } + } diff --git a/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTReader.java b/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTReader.java index 0cf9846..95654ba 100644 --- a/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTReader.java +++ b/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTReader.java @@ -39,16 +39,20 @@ 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.RESTStructuredCoverageGranulesList; +import it.geosolutions.geoserver.rest.decoder.RESTStructuredCoverageIndexSchema; import it.geosolutions.geoserver.rest.decoder.RESTStyleList; import it.geosolutions.geoserver.rest.decoder.RESTWorkspaceList; +import it.geosolutions.geoserver.rest.manager.GeoServerRESTStructuredCoverageGridReaderManager; +import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; +import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -575,4 +579,101 @@ public class GeoServerRESTReader { return names; } + /** + * Get information about a granule for a structured coverage. + * + * @param workspace the GeoServer workspace + * @param coverageStore the GeoServer coverageStore + * @param format the format of the file to upload + * @param the absolute path to the file to upload + * @param id the ID of the granule to get information for + * + * @return null in case the call does not succeed, or an instance of {@link RESTStructuredCoverageGranulesList}. + * + * @throws MalformedURLException + * @throws UnsupportedEncodingException + */ + public RESTStructuredCoverageGranulesList getGranuleById(final String workspace, + String coverageStore, String coverage, String id) throws MalformedURLException, + UnsupportedEncodingException { + try { + GeoServerRESTStructuredCoverageGridReaderManager manager = + new GeoServerRESTStructuredCoverageGridReaderManager(new URL(baseurl), username, password); + return manager.getGranuleById(workspace, coverageStore, coverage, id); + } catch (IllegalArgumentException e) { + if(LOGGER.isInfoEnabled()){ + LOGGER.info(e.getLocalizedMessage(),e); + } + } catch (MalformedURLException e) { + if(LOGGER.isInfoEnabled()){ + LOGGER.info(e.getLocalizedMessage(),e); + } + } + return null; + } + + /** + * Get information about the schema of the index for a structured coverage. + * + * @param workspace the GeoServer workspace + * @param coverageStore the GeoServer coverageStore + * @param format the format of the file to upload + * + * @return null in case the call does not succeed, or an instance of {@link RESTStructuredCoverageGranulesList}. + * + * @throws MalformedURLException + * @throws UnsupportedEncodingException + */ + @Test + public RESTStructuredCoverageIndexSchema getGranuleIndexSchema(final String workspace, String coverageStore, String coverage) throws MalformedURLException { + try { + GeoServerRESTStructuredCoverageGridReaderManager manager = + new GeoServerRESTStructuredCoverageGridReaderManager(new URL(baseurl), username, password); + return manager.getGranuleIndexSchema(workspace, coverageStore, coverage); + } catch (IllegalArgumentException e) { + if(LOGGER.isInfoEnabled()){ + LOGGER.info(e.getLocalizedMessage(),e); + } + } catch (MalformedURLException e) { + if(LOGGER.isInfoEnabled()){ + LOGGER.info(e.getLocalizedMessage(),e); + } + } + return null; + } + + /** + * Get information about the granules for a coverage with optional filter and paging. + * + * @param workspace the GeoServer workspace + * @param coverageStore the GeoServer coverageStore + * @param coverage the name of the target coverage + * @param filter the format of the file to upload, can be null to include all the granules + * @param offset the start page, can be null or an integer + * @param limit the dimension of the page, can be null or a positive integer + * + * @return null in case the call does not succeed, or an instance of {@link RESTStructuredCoverageGranulesList}. + * + * @throws MalformedURLException + * @throws UnsupportedEncodingException + */ + @Test + public RESTStructuredCoverageGranulesList getGranules(final String workspace, String coverageStore, String coverage, String filter, String offset, String limit) + throws MalformedURLException, UnsupportedEncodingException { + try { + GeoServerRESTStructuredCoverageGridReaderManager manager = + new GeoServerRESTStructuredCoverageGridReaderManager(new URL(baseurl), username, password); + return manager.getGranules(workspace, coverageStore, coverage, filter, offset, limit); + } catch (IllegalArgumentException e) { + if(LOGGER.isInfoEnabled()){ + LOGGER.info(e.getLocalizedMessage(),e); + } + } catch (MalformedURLException e) { + if(LOGGER.isInfoEnabled()){ + LOGGER.info(e.getLocalizedMessage(),e); + } + } + return null; + } + } diff --git a/src/main/java/it/geosolutions/geoserver/rest/HTTPUtils.java b/src/main/java/it/geosolutions/geoserver/rest/HTTPUtils.java index a08da22..ad8e2d0 100644 --- a/src/main/java/it/geosolutions/geoserver/rest/HTTPUtils.java +++ b/src/main/java/it/geosolutions/geoserver/rest/HTTPUtils.java @@ -336,7 +336,7 @@ public class HTTPUtils { InputStream is = httpMethod.getResponseBodyAsStream(); response = IOUtils.toString(is); IOUtils.closeQuietly(is); - if (response.trim().equals("")) { // sometimes gs rest fails + if (response.trim().equals("")) { if (LOGGER.isDebugEnabled()) LOGGER .debug("ResponseBody is empty (this may be not an error since we just performed a DELETE call)"); @@ -467,14 +467,14 @@ public class HTTPUtils { /** * @param str a string array - * @return create a StringBuffer appending all the passed arguments + * @return create a StringBuilder appending all the passed arguments */ - public static StringBuffer append(String ... str){ + public static StringBuilder append(String ... str){ if (str==null){ return null; } - StringBuffer buf=new StringBuffer(); + StringBuilder buf=new StringBuilder(); for (String s: str){ if (s!=null) buf.append(s); @@ -488,12 +488,12 @@ public class HTTPUtils { * @param str strings to append * @return the base URL with parameters attached */ - public static StringBuffer append(URL base, String ... str){ + public static StringBuilder append(URL base, String ... str){ if (str==null){ return append(base.toString()); } - StringBuffer buf=new StringBuffer(base.toString()); + StringBuilder buf=new StringBuilder(base.toString()); for (String s: str){ if (s!=null) buf.append(s); diff --git a/src/main/java/it/geosolutions/geoserver/rest/decoder/RESTStructuredCoverageGranulesList.java b/src/main/java/it/geosolutions/geoserver/rest/decoder/RESTStructuredCoverageGranulesList.java new file mode 100644 index 0000000..80d612a --- /dev/null +++ b/src/main/java/it/geosolutions/geoserver/rest/decoder/RESTStructuredCoverageGranulesList.java @@ -0,0 +1,230 @@ +/* + * 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.decoder; + +import it.geosolutions.geoserver.rest.decoder.utils.JDOMBuilder; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.jdom.Element; +import org.jdom.Namespace; + +/** + * This decode turns index format for a GeoServer StructuredGridCoverageReader into something + * useful, giving access to the definition of the single attributes. + * + *

This is the XML REST representation: + *

+  {@code
+
+
+
+  
+    
+      
+        5.0
+        45.0
+      
+      
+        14.875
+        50.9375
+      
+    
+  
+  
+    
+      
+        
+          
+            
+              5.0,45.0 5.0,50.9375 14.875,50.9375 14.875,45.0 5.0,45.0
+            
+          
+        
+      
+      ..\\polyphemus\\polyphemus_20130302.nc
+      672
+      2013-03-01T23:00:00Z
+      10.0
+      2013-03-01T23:00:00Z
+      2013-04-08T05:40:29.061Z
+    
+  
+
+
+}
+ * @author Simone Giannecchini, GeoSolutions SAS + * + */ +public class RESTStructuredCoverageGranulesList implements Iterable { + + /** GML_NAMESPACE */ + private static final Namespace GML_NAMESPACE = Namespace.getNamespace("gml", "http://www.opengis.net/gml"); + + private final List granulesList; + + private final Element bbox; + + /** + * @return the bbox + */ + public Element getBbox() { + return bbox; + } + + /** + * @param list + */ + @SuppressWarnings("unchecked") + protected RESTStructuredCoverageGranulesList(Element featureCollection) { + + // check ordering of elements + if(!featureCollection.getName().equals("FeatureCollection")){ + throw new IllegalStateException("Root element should be wfs:FeatureCollection"); + } + Element boundedBy = featureCollection.getChild("boundedBy",GML_NAMESPACE); + if(boundedBy==null){ + throw new IllegalStateException("Unable to find boundedBy element"); + } + // save bbox + bbox=boundedBy.getChild("Box",GML_NAMESPACE); + + // now get the feature members + List tmpList = new ArrayList(); + for(Element el : (List)featureCollection.getChildren("featureMember",GML_NAMESPACE)){ + tmpList.add(new RESTStructuredCoverageGranule(el)); + } + granulesList = Collections.unmodifiableList(tmpList); + } + + public static RESTStructuredCoverageGranulesList build(String response) { + if(response == null) + return null; + + Element pb = JDOMBuilder.buildElement(response); + if(pb != null){ + return new RESTStructuredCoverageGranulesList(pb); + } else { + return null; + } + } + + public int size() { + return granulesList.size(); + } + + public boolean isEmpty() { + return granulesList.isEmpty(); + } + + public RESTStructuredCoverageGranule get(int index) { + return granulesList.get(index); + } + + /* (non-Javadoc) + * @see java.lang.Iterable#iterator() + */ + @Override + public Iterator iterator() { + return granulesList.iterator(); + } + + /** + * Generic granule of the index. + * + *

This is the XML REST representation: + *

+  {@code
+  
+    
+      
+        
+          
+            
+              5.0,45.0 5.0,50.9375 14.875,50.9375 14.875,45.0 5.0,45.0
+            
+          
+        
+      
+      polyphemus_20130301.nc
+      672
+      2013-02-28T23:00:00Z
+      10.0
+      2013-02-28T23:00:00Z
+      2013-04-08T06:18:41.597Z
+    
+  
+
+     * @author Simone Giannecchini, GeoSolutions SAS
+     *
+     */
+    public static class RESTStructuredCoverageGranule {
+
+        protected final Element granule;
+        
+        private final String fid;
+
+        private final List children;
+
+        @SuppressWarnings("unchecked")
+        public RESTStructuredCoverageGranule(Element elem) {
+            if(!elem.getName().equals("featureMember")){
+                throw new IllegalStateException("Root element should be gml:featureMember for a granule");
+            }
+            Element feature = (Element) elem.getChildren().get(0);
+            if(feature==null){
+                throw new IllegalStateException("Unable to find feature element for this granule");
+            }    
+            this.granule = feature;
+            this.fid=granule.getAttribute("fid").getValue();
+            this.children=granule.getChildren();
+            
+        }
+
+        public String getAttributeByName(String name) {
+            return granule.getChildTextTrim(name,null);
+        }   
+
+        public String getAttributeByIndex(int index) {
+            return children.get(index).getValue();
+        }   
+        
+        @SuppressWarnings("unchecked")
+        public Iterator getAttributesIterator() {
+            return granule.getChildren().iterator();
+        }  
+        
+        /**
+         * @return the fid
+         */
+        public String getFid() {
+            return fid;
+        }
+    }
+
+}
diff --git a/src/main/java/it/geosolutions/geoserver/rest/decoder/RESTStructuredCoverageIndexSchema.java b/src/main/java/it/geosolutions/geoserver/rest/decoder/RESTStructuredCoverageIndexSchema.java
new file mode 100644
index 0000000..b19e0e6
--- /dev/null
+++ b/src/main/java/it/geosolutions/geoserver/rest/decoder/RESTStructuredCoverageIndexSchema.java
@@ -0,0 +1,212 @@
+/*
+ *  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.decoder;
+
+import it.geosolutions.geoserver.rest.decoder.utils.JDOMBuilder;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.jdom.Element;
+
+/**
+ * This decode turns index format for a GeoServer StructuredGridCoverageReader into something
+ * useful, giving access to the definition of the single attributes.
+ * 
+ * 

This is the XML REST representation: + *

+  {@code
+
+
+  
+    
+      the_geom
+      0
+      1
+      true
+      com.vividsolutions.jts.geom.Polygon
+    
+    
+      location
+      0
+      1
+      true
+      java.lang.String
+    
+    
+      imageindex
+      0
+      1
+      true
+      java.lang.Integer
+    
+    
+      time
+      0
+      1
+      true
+      java.sql.Timestamp
+    
+    
+      elevation
+      0
+      1
+      true
+      java.lang.Double
+    
+    
+      fileDate
+      0
+      1
+      true
+      java.sql.Timestamp
+    
+    
+      updated
+      0
+      1
+      true
+      java.sql.Timestamp
+    
+  
+  
+
+}
+ * @author Simone Giannecchini, GeoSolutions SAS + * + */ +public class RESTStructuredCoverageIndexSchema implements Iterable { + + private final List attributeList; + + /** + * @param list + */ + @SuppressWarnings("unchecked") + protected RESTStructuredCoverageIndexSchema(Element schema) { + + // check ordering of elements + if(!schema.getName().equals("Schema")){ + throw new IllegalStateException("Root element should be Schema"); + } + Element attributes = schema.getChild("attributes"); + if(attributes==null){ + throw new IllegalStateException("Root element should be Schema"); + } + + List tmpList = new ArrayList(); + for(Element el : (List)attributes.getChildren()){ + tmpList.add(new RESTStructuredCoverageIndexAttribute(el)); + } + attributeList = Collections.unmodifiableList(tmpList); + } + + public static RESTStructuredCoverageIndexSchema build(String response) { + if(response == null) + return null; + + Element pb = JDOMBuilder.buildElement(response); + if(pb != null){ + return new RESTStructuredCoverageIndexSchema(pb); + } else { + return null; + } + } + + public int size() { + return attributeList.size(); + } + + public boolean isEmpty() { + return attributeList.isEmpty(); + } + + public RESTStructuredCoverageIndexAttribute get(int index) { + return attributeList.get(index); + } + + /* (non-Javadoc) + * @see java.lang.Iterable#iterator() + */ + @Override + public Iterator iterator() { + return attributeList.iterator(); + } + + /** + * Generic granule of the index. + * + *

This is the XML REST representation: + *

+  {@code
+    
+      the_geom
+      0
+      1
+      true
+      com.vividsolutions.jts.geom.Polygon
+    
+     * @author Simone Giannecchini, GeoSolutions SAS
+     *
+     */
+    public static class RESTStructuredCoverageIndexAttribute {
+        protected final Element attribute;
+
+        public RESTStructuredCoverageIndexAttribute(Element elem) {
+            this.attribute = elem;
+        }
+
+        public String getName() {
+            return attribute.getChildTextTrim("name");
+        }
+        
+        public String getMinOccurs() {
+            return attribute.getChildTextTrim("minOccurs");
+        }
+        
+        public String getMaxOccurs() {
+            return attribute.getChildTextTrim("maxOccurs");
+        }
+        
+        public String getNillable() {
+            return attribute.getChildTextTrim("nillable");
+        }
+        
+        public String getBinding() {
+            return attribute.getChildTextTrim("binding");
+        }
+
+        @Override
+        public String toString() {
+            return "RESTStructuredCoverageGranule [getName()=" + getName()
+                    + ", getMinOccurs()=" + getMinOccurs() + ", getMaxOccurs()=" + getMaxOccurs()
+                    + ", getNillable()=" + getNillable() + ", getBinding()=" + getBinding() + "]";
+        }
+        
+    }
+
+}
diff --git a/src/main/java/it/geosolutions/geoserver/rest/manager/GeoServerRESTStoreManager.java b/src/main/java/it/geosolutions/geoserver/rest/manager/GeoServerRESTStoreManager.java
index 34dad05..5aad7be 100644
--- a/src/main/java/it/geosolutions/geoserver/rest/manager/GeoServerRESTStoreManager.java
+++ b/src/main/java/it/geosolutions/geoserver/rest/manager/GeoServerRESTStoreManager.java
@@ -107,7 +107,7 @@ public class GeoServerRESTStoreManager extends GeoServerRESTAbstractManager {
 //            if (workspace.isEmpty() || storename.isEmpty())
 //                throw new IllegalArgumentException("Arguments may not be empty!");
 
-            final StringBuffer url=HTTPUtils.append(restURL,"/rest/workspaces/",workspace,"/", store.getStoreType().toString(), "/",store.getName());
+            final StringBuilder url=HTTPUtils.append(restURL,"/rest/workspaces/",workspace,"/", store.getStoreType().toString(), "/",store.getName());
             if (recurse)
                 url.append("?recurse=true");
             final URL deleteStore = new URL(url.toString());
diff --git a/src/main/java/it/geosolutions/geoserver/rest/manager/GeoServerRESTStructuredCoverageGridReaderManager.java b/src/main/java/it/geosolutions/geoserver/rest/manager/GeoServerRESTStructuredCoverageGridReaderManager.java
new file mode 100644
index 0000000..44b3ccc
--- /dev/null
+++ b/src/main/java/it/geosolutions/geoserver/rest/manager/GeoServerRESTStructuredCoverageGridReaderManager.java
@@ -0,0 +1,354 @@
+/*
+ *  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.manager;
+
+import it.geosolutions.geoserver.rest.GeoServerRESTPublisher.UploadMethod;
+import it.geosolutions.geoserver.rest.HTTPUtils;
+import it.geosolutions.geoserver.rest.decoder.RESTStructuredCoverageGranulesList;
+import it.geosolutions.geoserver.rest.decoder.RESTStructuredCoverageIndexSchema;
+
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLEncoder;
+
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Manage GeoTools StructuredCoverageGridReader. It allows to create a store from a file or harvest
+ * the coverages contained in a file, to delete granules from an existing coverage and eventually
+ * to get information about the granules insi a StructuredCoverageGridReader.
+ * 
+ * @author Simone Giannecchini, GeoSolutions
+ */
+public class GeoServerRESTStructuredCoverageGridReaderManager extends GeoServerRESTAbstractManager {
+
+    /**
+     * Default logger
+     */
+    private final static Logger LOGGER = LoggerFactory.getLogger(GeoServerRESTStructuredCoverageGridReaderManager.class);
+
+    /**
+     * Default constructor.
+     * 
+     * @param restURL GeoServer REST API endpoint
+     * @param username GeoServer REST API authorized username
+     * @param password GeoServer REST API password for the former username
+     * @throws IllegalArgumentException
+     */
+    public GeoServerRESTStructuredCoverageGridReaderManager(URL restURL, String username, String password) throws IllegalArgumentException, MalformedURLException{
+        super(restURL, username, password);
+    }
+
+    /**
+     * Create a store or harvest the coverage from the provided external path.
+     * 
+     * @param workspace the GeoServer workspace
+     * @param coverageStore the GeoServer coverageStore
+     * @param format the format of the file to upload
+     * @param the absolut path to the file to upload
+     * 
+     * @return true if the call succeeds or false otherwise.
+     */
+    public boolean createOrHarvestExternal(String workspace, String coverageStore, String format, String path) {
+        // checks
+        checkString(workspace);
+        checkString(coverageStore);
+        checkString(format);
+        checkString(path);
+        
+        // create URL
+        String sUrl = HTTPUtils.append(restURL, "/rest/workspaces/", workspace, "/coveragestores/",coverageStore,"/",UploadMethod.EXTERNAL.toString(),".", format).toString();
+        
+        // POST request
+        String result = HTTPUtils.post(sUrl, "file:/"+path, "text/plain", gsuser, gspass);
+        return result != null;
+    }
+
+    /**
+     * Check the provided string for not being null or empty.
+     * 
+     * 

+ * It throws an exception in case the string is either null or empty. + * + * @param string the {@link String} to be checked + */ + private static void checkString(String string) { + if(string==null){ + throw new NullPointerException("Provided string is is null!"); + } + if(string.length()<=0){ + throw new IllegalArgumentException("Provided string is is empty!"); + } + + } + + /** + * Remove granules from a structured coverage, by providing a CQL filter. + * + * @param workspace the GeoServer workspace + * @param coverageStore the GeoServer coverageStore + * @param coverage the name of the target coverage from which we are going to remove + * @param filter the absolute path to the file to upload + * + * @return null in case the call does not succeed, or an instance of {@link RESTStructuredCoverageGranulesList}. + * + * @throws MalformedURLException + * @throws UnsupportedEncodingException + */ + public boolean removeGranulesByCQL(final String workspace, String coverageStore,String coverage, String filter) throws UnsupportedEncodingException{ + // checks + checkString(workspace); + checkString(coverage); + checkString(filter); + checkString(coverageStore); + + // does it exist? + RESTStructuredCoverageGranulesList granulesList=null; + try { + granulesList = getGranules(workspace, coverageStore, coverageStore, filter, null, "1"); + } catch (MalformedURLException e) { + if(LOGGER.isTraceEnabled()){ + LOGGER.trace(e.getMessage(), e); + } + } catch (UnsupportedEncodingException e) { + if(LOGGER.isTraceEnabled()){ + LOGGER.trace(e.getMessage(), e); + } + } + if (granulesList == null||granulesList.isEmpty()) { + if(LOGGER.isTraceEnabled()){ + LOGGER.trace("Granules for filter: "+filter+ " does not exist for coverage "+coverage); + } + return true; // nothing to remove + } + + // method + String sUrl = HTTPUtils.append(restURL, "/rest/workspaces/", workspace, "/coveragestores", "/",coverageStore,"/coverages/",coverage,"/index/granules?filter=",URLEncoder.encode(filter, "UTF-8")).toString(); + if(!HTTPUtils.delete(sUrl, gsuser, gspass)){ + return false; + } + + // does it exist? + granulesList=null; + try { + granulesList = getGranules(workspace, coverageStore, coverageStore, filter, null, "1"); + } catch (MalformedURLException e) { + if(LOGGER.isTraceEnabled()){ + LOGGER.trace(e.getMessage(), e); + } + } catch (UnsupportedEncodingException e) { + if(LOGGER.isTraceEnabled()){ + LOGGER.trace(e.getMessage(), e); + } + } + if (granulesList == null||granulesList.isEmpty()) { + return true; // nothing to remove + } + return false; + } + + /** + * Remove a granule from a structured coverage by id. + * + * @param workspace the GeoServer workspace + * @param coverageStore the GeoServer coverageStore + * @param coverage the name of the target coverage from which we are going to remove + * @param filter the absolute path to the file to upload + * + * @return null in case the call does not succeed, or an instance of {@link RESTStructuredCoverageGranulesList}. + * + * @throws MalformedURLException + * @throws UnsupportedEncodingException + */ + public boolean removeGranuleById(final String workspace, String coverageStore, String coverage, String granuleId) { + // checks + checkString(workspace); + checkString(coverage); + checkString(granuleId); + checkString(coverageStore); + + // does it exist? + RESTStructuredCoverageGranulesList granule=null; + try { + granule = getGranuleById(workspace, coverageStore, coverage, granuleId); + } catch (MalformedURLException e) { + if(LOGGER.isTraceEnabled()){ + LOGGER.trace(e.getMessage(), e); + } + } catch (UnsupportedEncodingException e) { + if(LOGGER.isTraceEnabled()){ + LOGGER.trace(e.getMessage(), e); + } + } + if (granule == null) { + if(LOGGER.isTraceEnabled()){ + LOGGER.trace("Granule for id: "+granuleId+ " does not exist for coverage "+coverage); + } + return true; // nothing to remove + } + + // delete + String sUrl = HTTPUtils.append(restURL, "/rest/workspaces/", workspace, "/coveragestores", + "/", coverageStore, "/coverages/", coverage, "/index/granules/", granuleId) + .toString(); + if(!HTTPUtils.delete(sUrl, gsuser, gspass)){ + return false; + } + + // has it been canceled? + // does it exist? + granule=null; + try { + granule = getGranuleById(workspace, coverageStore, coverage, granuleId); + } catch (MalformedURLException e) { + if(LOGGER.isTraceEnabled()){ + LOGGER.trace(e.getMessage(), e); + } + } catch (UnsupportedEncodingException e) { + if(LOGGER.isTraceEnabled()){ + LOGGER.trace(e.getMessage(), e); + } + } + if (granule == null) { + return true; + } + + return false; + } + + /** + * Get information about the schema of the index for a structured coverage. + * + * @param workspace the GeoServer workspace + * @param coverageStore the GeoServer coverageStore + * @param format the format of the file to upload + * + * @return null in case the call does not succeed, or an instance of {@link RESTStructuredCoverageGranulesList}. + * + * @throws MalformedURLException + * @throws UnsupportedEncodingException + */ + @Test + public RESTStructuredCoverageIndexSchema getGranuleIndexSchema(final String workspace, String coverageStore, String coverage) throws MalformedURLException { + // checks + checkString(workspace); + checkString(coverage); + checkString(coverageStore); + + // create URL and then call it + String sUrl = HTTPUtils.append(restURL, "/rest/workspaces/", workspace, "/coveragestores/", coverageStore, "/coverages/", coverage, "/index.xml").toString(); + String result = HTTPUtils.get(sUrl, gsuser, gspass); + if (result != null) { + return RESTStructuredCoverageIndexSchema.build(result); + } + return null; + } + + /** + * Get information about the granules for a coverage with optional filter and paging. + * + * @param workspace the GeoServer workspace + * @param coverageStore the GeoServer coverageStore + * @param coverage the name of the target coverage + * @param filter the format of the file to upload, can be null to include all the granules + * @param offset the start page, can be null or an integer + * @param limit the dimension of the page, can be null or a positive integer + * + * @return null in case the call does not succeed, or an instance of {@link RESTStructuredCoverageGranulesList}. + * + * @throws MalformedURLException + * @throws UnsupportedEncodingException + */ + @Test + public RESTStructuredCoverageGranulesList getGranules(final String workspace, String coverageStore, String coverage, String filter, String offset, String limit) + throws MalformedURLException, UnsupportedEncodingException { + // checks + checkString(workspace); + checkString(coverage); + checkString(coverageStore); + + // method + boolean append = false; + String sUrl = HTTPUtils.append(restURL, "/rest/workspaces/", workspace, "/coveragestores/", coverageStore, "/coverages/", coverage, "/index/granules.xml").toString(); + if (filter != null && !filter.isEmpty()) { + append = true; + sUrl = HTTPUtils.append(sUrl, "?filter=", URLEncoder.encode(filter, "UTF-8")).toString(); + } + if (offset != null && !offset.isEmpty()) { + sUrl = HTTPUtils.append(sUrl, append ? "&offset=" : "?offset=", offset).toString(); + append = true; + } + if (limit != null && !limit.isEmpty()) { + sUrl = HTTPUtils.append(sUrl, append ? "&limit=" : "?limit=", limit).toString(); + append = true; + } + String result = HTTPUtils.get(sUrl, gsuser, gspass); + if (result != null) { + return RESTStructuredCoverageGranulesList.build(result); + } + return null; + } + + /** + * Get information about a granule for a structured coverage. + * + * @param workspace the GeoServer workspace + * @param coverageStore the GeoServer coverageStore + * @param format the format of the file to upload + * @param the absolute path to the file to upload + * @param id the ID of the granule to get information for + * + * @return null in case the call does not succeed, or an instance of {@link RESTStructuredCoverageGranulesList}. + * + * @throws MalformedURLException + * @throws UnsupportedEncodingException + */ + @Test + public RESTStructuredCoverageGranulesList getGranuleById(final String workspace, + String coverageStore, String coverage, String id) throws MalformedURLException, + UnsupportedEncodingException { + // checks + checkString(workspace); + checkString(coverage); + checkString(coverageStore); + checkString(id); + try{ + Integer.parseInt(id); + }catch (NumberFormatException e) { + throw new IllegalArgumentException(e); + } + + // method + String sUrl = HTTPUtils.append(restURL, "/rest/workspaces/", workspace, "/coveragestores/", coverageStore, "/coverages/", coverage, "/index/granules/", id, ".xml").toString(); + String result = HTTPUtils.get(sUrl, gsuser, gspass); + if (result != null) { + return RESTStructuredCoverageGranulesList.build(result); + } + return null; + } +} diff --git a/src/test/java/it/geosolutions/geoserver/rest/manager/GeoServerRESTStructuredCoverageGridReaderManagerTest.java b/src/test/java/it/geosolutions/geoserver/rest/manager/GeoServerRESTStructuredCoverageGridReaderManagerTest.java new file mode 100644 index 0000000..e71f2f8 --- /dev/null +++ b/src/test/java/it/geosolutions/geoserver/rest/manager/GeoServerRESTStructuredCoverageGridReaderManagerTest.java @@ -0,0 +1,136 @@ +/* + * GeoTools - The Open Source Java GIS Toolkit + * http://geotools.org + * + * (C) 2002-2011, Open Source Geospatial Foundation (OSGeo) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ +package it.geosolutions.geoserver.rest.manager; + +import it.geosolutions.geoserver.rest.datastore.StoreIntegrationTest; +import it.geosolutions.geoserver.rest.decoder.RESTStructuredCoverageGranulesList; +import it.geosolutions.geoserver.rest.decoder.RESTStructuredCoverageGranulesList.RESTStructuredCoverageGranule; +import it.geosolutions.geoserver.rest.decoder.RESTStructuredCoverageIndexSchema; +import it.geosolutions.geoserver.rest.decoder.RESTStructuredCoverageIndexSchema.RESTStructuredCoverageIndexAttribute; +import it.geosolutions.geoserver.rest.encoder.GSAbstractStoreEncoder; + +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Iterator; + +import junit.framework.Assert; + +import org.junit.Test; + +/** + * @author Simone Giannecchini, simone.giannecchini@geo-solutions.it + * + */ +public class GeoServerRESTStructuredCoverageGridReaderManagerTest extends StoreIntegrationTest { + + /** + * @param ignore + * @throws IllegalArgumentException + * @throws MalformedURLException + */ + public GeoServerRESTStructuredCoverageGridReaderManagerTest() + throws IllegalArgumentException, MalformedURLException { + super(true); + } + + @Override + public GSAbstractStoreEncoder getStoreEncoderTest() { + // TODO Auto-generated method stub + return null; + } + + @Test + public void createAndDelete() throws IllegalArgumentException, MalformedURLException, UnsupportedEncodingException{ + GeoServerRESTStructuredCoverageGridReaderManager manager = + new GeoServerRESTStructuredCoverageGridReaderManager(new URL("http://localhost:8080/geoserver"), "admin", "geoserver"); +// boolean result=manager.createOrHarvestExternal("it.geosolutions", "polyphemus", "imagemosaic", "D:\\DLR\\Geoserver-MD\\polyphemus\\polyphemus_20130301.nc"); +// Assert.assertTrue(result); + + // check index format + RESTStructuredCoverageIndexSchema indexFormat = manager.getGranuleIndexSchema("it.geosolutions", "polyphemus","V"); + assertNotNull(indexFormat); + assertFalse(indexFormat.isEmpty()); + assertEquals(7, indexFormat.size()); + Iterator iterator = indexFormat.iterator(); + while(iterator.hasNext()){ + final RESTStructuredCoverageIndexAttribute element = iterator.next(); + if(element.getName().equals("location")){ + assertEquals("0", element.getMinOccurs()); + assertEquals("1", element.getMaxOccurs()); + assertEquals("true", element.getNillable()); + assertEquals("java.lang.String", element.getBinding()); + break; + } + } + + // get some granules by id + RESTStructuredCoverageGranulesList granulesList = manager.getGranuleById("it.geosolutions", "polyphemus","V","348"); + assertNotNull(granulesList); + assertSame(1, granulesList.size()); + assertFalse(granulesList.isEmpty()); + RESTStructuredCoverageGranule granule = granulesList.get(0); + assertNotNull(granule); + assertEquals(granule.getAttributeByIndex(4), "1250.0"); + assertEquals(granule.getAttributeByName("elevation"), "1250.0"); + + + // get with paging + granulesList = manager.getGranules("it.geosolutions", "polyphemus","V",null,"0","10"); + assertNotNull(granulesList); + assertEquals(10, granulesList.size()); + assertFalse(granulesList.isEmpty()); + granule = granulesList.get(0); + assertNotNull(granule); + + granulesList = manager.getGranules("it.geosolutions", "polyphemus","V",null,null,"10"); + assertNotNull(granulesList); + assertEquals(10, granulesList.size()); + assertFalse(granulesList.isEmpty()); + granule = granulesList.get(0); + assertNotNull(granule); + + granulesList = manager.getGranules("it.geosolutions", "polyphemus","V",null,null,null); + assertNotNull(granulesList); + assertEquals(1007, granulesList.size()); + assertFalse(granulesList.isEmpty()); + granule = granulesList.get(0); + assertNotNull(granule); + + granulesList = manager.getGranules("it.geosolutions", "polyphemus","V","elevation = 10",null,null); + assertNotNull(granulesList); + assertEquals(72, granulesList.size()); + assertFalse(granulesList.isEmpty()); + granule = granulesList.get(0); + assertNotNull(granule); + + granulesList = manager.getGranules("it.geosolutions", "polyphemus","V","elevation = 10","0","10"); + assertNotNull(granulesList); + assertEquals(10, granulesList.size()); + assertFalse(granulesList.isEmpty()); + granule = granulesList.get(0); + assertNotNull(granule); + + // remove by id + boolean result = manager.removeGranuleById("it.geosolutions", "polyphemus","V", "349"); + assertTrue(result); + + // remove by filter + result = manager.removeGranulesByCQL("it.geosolutions", "polyphemus","V", "location = 'polyphemus_20130301.nc'"); + Assert.assertTrue(result); + } +}