/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved
* (c) 2014 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.rest.ecql;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.geoserver.catalog.CoverageInfo;
import org.geoserver.catalog.CoverageStoreInfo;
import org.geoserver.catalog.MetadataMap;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.catalog.impl.ModificationProxy;
import org.geoserver.catalog.rest.CatalogRESTTestSupport;
import org.geoserver.config.GeoServerInfo;
import org.geoserver.config.impl.SettingsInfoImpl;
import org.geoserver.data.test.MockData;
import org.geoserver.rest.util.RESTUtils;
import org.geotools.data.DataUtilities;
import org.geotools.feature.SchemaException;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.filter.text.cql2.CQLException;
import org.geotools.filter.text.ecql.ECQL;
import org.junit.Test;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.expression.Expression;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import org.springframework.mock.web.MockHttpServletResponse;
/**
* Unit test for evaluating the ECQL REST PathMapper.
*/
public class RESTECQLTest extends CatalogRESTTestSupport {
private static SimpleFeatureType type;
private static List<String> fileNames;
static {
try {
// Feature type associated to the path variable inside the cql expressions
type = DataUtilities.createType("type", "path:string,name:string");
} catch (SchemaException e) {
LOGGER.log(Level.WARNING, e.getMessage(), e);
}
// Populating the filename list
fileNames = new ArrayList<String>();
fileNames.add("NCOM_wattemp_000_20081031T0000000_12.tiff");
fileNames.add("NCOM_wattemp_000_20081101T0000000_12.tiff");
fileNames.add("NCOM_wattemp_100_20081031T0000000_12.tiff");
fileNames.add("NCOM_wattemp_100_20081101T0000000_12.tiff");
}
@Test
public void testRegExp() throws Exception {
// RegExp expression
String expression = "stringTemplate(path, '(\\w{4})_(\\w{7})_(\\d{3})_(\\d{4})(\\d{2})(\\d{2})T(\\d{7})_(\\d{2})\\.(\\w{4})', "
+ "'/${1}/${4}/${5}/${6}/${0}')";
// Testing of the defined exception
testExpression("test", "mosaic_test", expression, fileNames);
}
@Test
public void testSubString() throws Exception {
// SubString expression
String expression = "if_then_else(strEndsWith(name,'.tiff'),Concatenate(strSubstring(path, 0, 4),'/',name),'')";
// Testing of the defined exception
testExpression("test2", "mosaic_test2", expression, fileNames);
}
/**
* Initial settings for the root key, mapper and expression used
*
* @param expression
*/
private void initialSetup(String expression) {
// Selection of the root directory
String root = getTestData().getDataDirectoryRoot().getAbsolutePath();
// Setting of the global configuration
GeoServerInfo global = getGeoServer().getGlobal();
SettingsInfoImpl info = (SettingsInfoImpl) ModificationProxy.unwrap(global.getSettings());
// Setting of the metadata map if not present
if (info.getMetadata() == null) {
info.setMetadata(new MetadataMap());
}
// Selection of the metadata map
MetadataMap map = info.getMetadata();
// Insertion of the Root directory and the ecql expression
map.put(RESTUtils.ROOT_KEY, root);
map.put(RESTUploadECQLPathMapper.EXPRESSION_KEY, expression);
// Save the global settings
getGeoServer().save(global);
}
/**
* Private method for adding the selected coverage inside the defined workspace via REST and then checking if the coverage has been placed inside
* the defined directory
*
* @param root
* @param workspace
* @param coverageStore
* @param fileName
* @throws IOException
* @throws ParserConfigurationException
* @throws SAXException
*/
private void testExpression(String workspace, String coverageStore, String expression,
List<String> fileNames) throws IOException, Exception, ParserConfigurationException,
SAXException {
// Initial Settings
initialSetup(expression);
// Selection of a zip file
URL zip = MockData.class.getResource("watertemp.zip");
//byte[] bytes = FileUtils.readFileToByteArray(DataUtilities.urlToFile(zip));
InputStream is = null;
byte[] bytes;
try {
is = zip.openStream();
bytes = IOUtils.toByteArray(is);
} finally {
IOUtils.closeQuietly(is);
}
// creation of the workspace if not already present
createWorkSpace(workspace);
// Uploading the file via rest
MockHttpServletResponse response = putAsServletResponse("/rest/workspaces/" + workspace
+ "/coveragestores/" + coverageStore + "/file.imagemosaic", bytes,
"application/zip");
assertEquals(201, response.getStatus());
// Check if the coverage is present
String content = response.getContentAsString();
Document d = dom(new ByteArrayInputStream(content.getBytes()));
assertEquals("coverageStore", d.getDocumentElement().getNodeName());
// Final checks
CoverageStoreInfo cs = getCatalog().getCoverageStoreByName(workspace, coverageStore);
assertNotNull(cs);
CoverageInfo ci = getCatalog().getCoverageByName(workspace, coverageStore);
assertNotNull(ci);
// Check if the final path is correct for each input file
for (String fileName : fileNames) {
// File related to the filenamee
File finalFile = extractFile(expression, cs, fileName, fileName);
// Check if the file really exists
assertTrue(finalFile.exists());
}
}
/**
* Private method for creating a new file object associated to the input path.
*
* @param expression
* @param cs
* @param filename
*
* @throws CQLException
*/
private File extractFile(String expression, CoverageStoreInfo cs, String itemPath, String filename)
throws CQLException {
// Url to the final element
String url = cs.getURL();
// Convert the String expression into a CQL expression
Expression exp = ECQL.toExpression(expression);
// Feature associated to the input path
SimpleFeature feature = SimpleFeatureBuilder.build(type, new Object[] { itemPath, filename }, null);
// Perform Regular Expression match
String newPath = exp.evaluate(feature, String.class);
// Final FILE creation
return new File(url, newPath);
}
/**
* Creation of a new workspace defined by the input "workspace" name
*
* @param workspace
*/
private void createWorkSpace(String workspace) throws Exception {
// Check if the workspace is already present
if (getCatalog().getWorkspaceByName(workspace) != null) {
return;
}
// Creation of a new Workspace called "test"
String xml = "<workspace>" + "<name>" + workspace + "</name>" + "</workspace>";
MockHttpServletResponse responseBefore = postAsServletResponse("/rest/workspaces", xml,
"text/xml");
assertEquals(201, responseBefore.getStatus());
assertNotNull(responseBefore.getHeader("Location"));
assertTrue(responseBefore.getHeader("Location").endsWith("/workspaces/" + workspace));
// Setting of the workspace configuration
WorkspaceInfo ws = getCatalog().getWorkspaceByName(workspace);
assertNotNull(ws);
}
}