Skip to content

Commit

Permalink
[GEOS-7421] harvesting file to mosaicstore using REST twice deletes a…
Browse files Browse the repository at this point in the history
…ll files in store directory
  • Loading branch information
aaime authored and jodygarnett committed Feb 18, 2016
1 parent 886a123 commit 9ec8fef
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 43 deletions.
13 changes: 11 additions & 2 deletions doc/en/user/source/rest/api/coveragestores.rst
Expand Up @@ -148,10 +148,10 @@ This end point allows a file containing spatial data to be added (via a POST or
-
* - POST
- If the coverage store is a simple one (e.g. GeoTiff) it will return a 405, if the coverage store is a structured one (e.g., mosaic) it will harvest the specified files into it, which in turn will integrate the files into the store. Harvest meaning is store dependent, for mosaic the new files will be added as new granules of the mosaic, and existing files will get their attribute updated, other stores might have a different behavior.
- 405 if the coverage store is a simple one, 200 if structured and the harvest operation succeded
- 405 if the coverage store is a simple one, 200 if structured and the harvest operation succeeded
-
-
- :ref:`recalculate <rest_api_coveragestores_recalculate>`
- :ref:`recalculate <rest_api_coveragestores_recalculate>`, :ref:`filename <rest_api_coveragestores_filename>`
* - PUT
- Creates or overwrites the files for coverage store ``cs``
- 200
Expand Down Expand Up @@ -238,3 +238,12 @@ The ``recalculate`` parameter specifies whether to recalculate any bounding boxe
* ``recalculate=nativebbox``—Recalculate the native bounding box, but do not recalculate the lat/long bounding box.
* ``recalculate=nativebbox,latlonbbox``—Recalculate both the native bounding box and the lat/long bounding box.

.. _rest_api_coveragestores_filename:

``filename``
^^^^^^^^^^^^^^^

The ``filename`` parameter specifies the target file name for a file that needs to harvested as part of a mosaic. This is important to avoid clashes and to make sure the
right dimension values are available in the name for multidimensional mosaics to work.

* ``filename=`NCOM_wattemp_000_20081102T0000000_12.tiff` Set the uploaded file name to ``NCOM_wattemp_000_20081102T0000000_12.tiff``
36 changes: 0 additions & 36 deletions src/rest/src/main/java/org/geoserver/rest/util/RESTUtils.java
Expand Up @@ -105,42 +105,6 @@ public static String getBaseURL( Request request ) {
}
}

/**
* This function gets the stream of the request to copy it into a file.
*
* This method will create a "data" folder in GEOSERVER_DATA_DIRECTORY if needed.
*
* @deprecated use {@link #handleBinUpload(String, File, Request)}.
*/
public static org.geoserver.platform.resource.Resource handleBinUpload(String datasetName, String extension,
Request request) throws IOException, ConfigurationException {
GeoServerResourceLoader loader = GeoServerExtensions.bean(GeoServerResourceLoader.class);
Resource data = loader.get("data");

return handleBinUpload( datasetName + "." + extension, null, data, request );
}

/**
* Reads content from the body of a request and writes it to a file in the given directory.
*
* If the file already exists, the directory content will be deleted recursively
* before creating the new file.
*
* @param fileName The name of the file to write out.
* @param directory The directory to write the file to
* @param request The request.
*
* @return The file object representing the newly written file.
*
* @throws IOException Any I/O errors that occur.
*
* @deprecated use {@link #handleBinUpload(String, File, boolean, Request)}.
*/
public static org.geoserver.platform.resource.Resource handleBinUpload(String fileName, String workSpace, org.geoserver.platform.resource.Resource directory, Request request)
throws IOException {
return handleBinUpload(fileName, directory, true, request, workSpace);
}

/**
* Reads content from the body of a request and writes it to a file.
*
Expand Down
@@ -1,4 +1,4 @@
/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
Expand Down Expand Up @@ -27,6 +27,7 @@
import org.geoserver.rest.util.RESTUtils;
import org.geotools.data.DataUtilities;
import org.geotools.util.logging.Logging;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Method;
import org.restlet.data.Request;
Expand Down Expand Up @@ -169,7 +170,15 @@ protected List<org.geoserver.platform.resource.Resource> handleFileUpload(String
try {
String method = (String) getRequest().getResourceRef().getLastSegment();
if (method != null && method.toLowerCase().startsWith("file.")) {
uploadedFile = RESTUtils.handleBinUpload(store + "." + format, workspace, directory, getRequest());
// we want to delete the previous dir contents only in case of PUT, not
// in case of POST (harvest, available only for raster data)
boolean cleanPreviousContents = getRequest().getMethod() == Method.PUT ;
Form form = getRequest().getResourceRef().getQueryAsForm();
String filename = form.getFirstValue("filename", true);
if(filename == null) {
filename = store + "." + format;
}
uploadedFile = RESTUtils.handleBinUpload(filename, directory, cleanPreviousContents, getRequest(), workspace);
}
else if (method != null && method.toLowerCase().startsWith("url.")) {
uploadedFile = RESTUtils.handleURLUpload(store + "." + format, workspace, directory, getRequest());
Expand Down
@@ -1,12 +1,11 @@
/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.catalog.rest;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.*;

import java.io.ByteArrayInputStream;
import java.io.File;
Expand All @@ -15,6 +14,8 @@
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.commons.io.FileUtils;
import org.custommonkey.xmlunit.XMLAssert;
Expand All @@ -33,6 +34,7 @@
import org.geotools.data.DataUtilities;
import org.geotools.factory.GeoTools;
import org.geotools.gce.imagemosaic.ImageMosaicFormat;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.opengis.coverage.grid.GridCoverageReader;
Expand All @@ -45,6 +47,15 @@

public class CoverageStoreFileUploadTest extends CatalogRESTTestSupport {

@Before
public void cleanup() {
// wipe out everything under "mosaic"
CoverageInfo coverage = getCatalog().getResourceByName("mosaic", CoverageInfo.class);
if(coverage != null) {
removeStore(coverage.getStore().getWorkspace().getName(), coverage.getStore().getName());
}
}

@Test
public void testWorldImageUploadZipped() throws Exception {
URL zip = getClass().getResource( "test-data/usa.zip" );
Expand Down Expand Up @@ -321,6 +332,114 @@ public void testHarvestExternalImageMosaic() throws Exception {
}
}
}

@Test
public void testReHarvestSingleTiff() throws Exception {
// Check if an already existing directory called "mosaic" is present
URL resource = getClass().getResource("test-data/mosaic");
if (resource != null) {
File oldDir = DataUtilities.urlToFile(resource);
if (oldDir.exists()) {
FileUtils.deleteDirectory(oldDir);
}
}
// reading of the mosaic directory
Resource mosaic = readMosaic();
// Creation of the builder for building a new CoverageStore
CatalogBuilder builder = new CatalogBuilder(getCatalog());
// Definition of the workspace associated to the coverage
WorkspaceInfo ws = getCatalog().getWorkspaceByName("gs");
// Creation of a CoverageStore
CoverageStoreInfo store = builder.buildCoverageStore("watertemp5");
store.setURL(DataUtilities.fileToURL(Resources.find(mosaic)).toExternalForm());
store.setWorkspace(ws);
ImageMosaicFormat imageMosaicFormat = new ImageMosaicFormat();
store.setType((imageMosaicFormat.getName()));
// Addition to the catalog
getCatalog().add(store);
builder.setStore(store);
// Input reader used for reading the mosaic folder
GridCoverage2DReader reader = null;
// Reader used for checking if the mosaic has been configured correctly
StructuredGridCoverage2DReader reader2 = null;

try {
// Selection of the reader to use for the mosaic
reader = imageMosaicFormat.getReader(DataUtilities
.fileToURL(Resources.find(mosaic)));

// configure the coverage
configureCoverageInfo(builder, store, reader);

// check the coverage is actually there
CoverageStoreInfo storeInfo = getCatalog().getCoverageStoreByName("watertemp5");
assertNotNull(storeInfo);
CoverageInfo ci = getCatalog().getCoverageByName("mosaic");
assertNotNull(ci);
assertEquals(storeInfo, ci.getStore());

// Harvesting of the Mosaic
URL zipHarvest = MockData.class.getResource("harvesting.zip");
// Extract the first file as payload (the tiff)
byte[] bytes = null;
try(ZipInputStream zis = new ZipInputStream(zipHarvest.openStream())) {
ZipEntry entry = null;
while((entry = zis.getNextEntry()) != null) {
if("NCOM_wattemp_000_20081102T0000000_12.tiff".equals(entry.getName())) {
bytes = IOUtils.toByteArray(zis);
}
}
if(bytes == null) {
fail("Could not find the expected zip entry NCOM_wattemp_000_20081102T0000000_12.tiff");
}
}
reader2 = uploadGeotiffAndCheck(storeInfo, bytes, "NCOM_wattemp_000_20081102T0000000_12.tiff");
// now re-upload, used to blow up
reader2 = uploadGeotiffAndCheck(storeInfo, bytes, "NCOM_wattemp_000_20081102T0000000_12.tiff");
// Removal of all the data associated to the mosaic
reader2.delete(true);
} finally {
// Reader disposal
if (reader != null) {
try {
reader.dispose();
} catch (Throwable t) {
// Does nothing
}
}
if (reader2 != null) {
try {
reader2.dispose();
} catch (Throwable t) {
// Does nothing
}
}
}
}

private StructuredGridCoverage2DReader uploadGeotiffAndCheck(CoverageStoreInfo storeInfo,
byte[] bytes, String filename) throws Exception, IOException {
StructuredGridCoverage2DReader reader2;
// Create the POST request
MockHttpServletRequest request = createRequest("/rest/workspaces/gs/coveragestores/watertemp5/file.imagemosaic?filename=" + filename);
request.setMethod("POST");
request.setContentType("image/tiff");
request.setBodyContent(bytes);
request.setHeader("Content-type", "image/tiff");
// Get The response
assertEquals(202, dispatch(request).getStatusCode());
// Get the Mosaic Reader
reader2 = (StructuredGridCoverage2DReader) storeInfo.getGridCoverageReader(null,
GeoTools.getDefaultHints());
// Test if all the TIME DOMAINS are present
String[] metadataNames = reader2.getMetadataNames();
assertNotNull(metadataNames);
assertEquals("true", reader2.getMetadataValue("HAS_TIME_DOMAIN"));
assertEquals(
"2008-10-31T00:00:00.000Z,2008-11-01T00:00:00.000Z,2008-11-02T00:00:00.000Z",
reader2.getMetadataValue(metadataNames[0]));
return reader2;
}

private Resource readMosaic() throws NoSuchAuthorityCodeException, FactoryException, IOException {
// Select the zip file containing the mosaic
Expand Down

0 comments on commit 9ec8fef

Please sign in to comment.