From 9eaf1026c424d072f86beb66ed95df83992b98ac Mon Sep 17 00:00:00 2001 From: gmantele <gmantele@ari.uni-heidelberg.de> Date: Mon, 9 Feb 2015 18:49:55 +0100 Subject: [PATCH] [TAP] Add ADQL geometry restriction inside the configuration file. --- src/tap/config/DefaultServiceConnection.java | 55 ++++++++++++++++- src/tap/config/TAPConfiguration.java | 4 ++ src/tap/config/tap_configuration_file.html | 17 ++++++ .../config/TestDefaultServiceConnection.java | 60 ++++++++++++++++++- 4 files changed, 132 insertions(+), 4 deletions(-) diff --git a/src/tap/config/DefaultServiceConnection.java b/src/tap/config/DefaultServiceConnection.java index 7dfcf6f..c7baae8 100644 --- a/src/tap/config/DefaultServiceConnection.java +++ b/src/tap/config/DefaultServiceConnection.java @@ -13,6 +13,7 @@ import static tap.config.TAPConfiguration.KEY_DEFAULT_UPLOAD_LIMIT; import static tap.config.TAPConfiguration.KEY_DIRECTORY_PER_USER; import static tap.config.TAPConfiguration.KEY_FILE_MANAGER; import static tap.config.TAPConfiguration.KEY_FILE_ROOT_PATH; +import static tap.config.TAPConfiguration.KEY_GEOMETRIES; import static tap.config.TAPConfiguration.KEY_GROUP_USER_DIRECTORIES; import static tap.config.TAPConfiguration.KEY_MAX_ASYNC_JOBS; import static tap.config.TAPConfiguration.KEY_MAX_EXECUTION_DURATION; @@ -31,6 +32,7 @@ import static tap.config.TAPConfiguration.VALUE_CSV; import static tap.config.TAPConfiguration.VALUE_DB; import static tap.config.TAPConfiguration.VALUE_JSON; import static tap.config.TAPConfiguration.VALUE_LOCAL; +import static tap.config.TAPConfiguration.VALUE_NONE; import static tap.config.TAPConfiguration.VALUE_SV; import static tap.config.TAPConfiguration.VALUE_TSV; import static tap.config.TAPConfiguration.VALUE_XML; @@ -97,7 +99,10 @@ public final class DefaultServiceConnection implements ServiceConnection { private UserIdentifier userIdentifier = null; - private final Collection<FunctionDef> udfs = new ArrayList<FunctionDef>(0); + private ArrayList<String> geometries = null; + private final String GEOMETRY_REGEXP = "(AREA|BOX|CENTROID|CIRCLE|CONTAINS|DISTANCE|COORD1|COORD2|COORDSYS|INTERSECTS|POINT|POLYGON|REGION)"; + + private Collection<FunctionDef> udfs = new ArrayList<FunctionDef>(0); public DefaultServiceConnection(final Properties tapConfig) throws NullPointerException, TAPException, UWSException{ // 1. INITIALIZE THE FILE MANAGER: @@ -139,7 +144,10 @@ public final class DefaultServiceConnection implements ServiceConnection { // 8. SET A USER IDENTIFIER: initUserIdentifier(tapConfig); - // 9. MAKE THE SERVICE AVAILABLE: + // 9. CONFIGURE ADQL: + initADQLGeometries(tapConfig); + + // 10. MAKE THE SERVICE AVAILABLE: setAvailable(true, "TAP service available."); } @@ -445,6 +453,47 @@ public final class DefaultServiceConnection implements ServiceConnection { } } + private void initADQLGeometries(final Properties tapConfig) throws TAPException{ + // Get the property value: + String propValue = getProperty(tapConfig, KEY_GEOMETRIES); + + // NO VALUE => ALL FCT ALLOWED! + if (propValue == null) + geometries = null; + + // "NONE" => ALL FCT FORBIDDEN (= none of these functions are allowed)! + else if (propValue.equalsIgnoreCase(VALUE_NONE)) + geometries = new ArrayList<String>(0); + + // OTHERWISE, JUST THE ALLOWED ONE ARE LISTED: + else{ + // split all the list items: + String[] items = propValue.split(","); + if (items.length > 0){ + geometries = new ArrayList<String>(items.length); + for(String item : items){ + item = item.trim(); + // empty item => ignored + if (item.length() <= 0) + continue; + // if it is a name of known ADQL geometrical function, add it to the list: + else if (item.toUpperCase().matches(GEOMETRY_REGEXP)) + geometries.add(item.toUpperCase()); + // "NONE" is not allowed inside a list => error! + else if (item.toUpperCase().equals(VALUE_NONE)) + throw new TAPException("The special value \"" + VALUE_NONE + "\" can not be used inside a list! It MUST be used in replacement of a whole list to specify that no value is allowed."); + // unknown value => error! + else + throw new TAPException("Unknown ADQL geometrical function: \"" + item + "\"!"); + } + // if finally no item has been specified, consider it as "all functions allowed": + if (geometries.size() == 0) + geometries = null; + }else + geometries = null; + } + } + @Override public String getProviderName(){ return providerName; @@ -668,7 +717,7 @@ public final class DefaultServiceConnection implements ServiceConnection { @Override public Collection<String> getGeometries(){ - return null; // ALL GEOMETRIES ALLOWED + return geometries; } @Override diff --git a/src/tap/config/TAPConfiguration.java b/src/tap/config/TAPConfiguration.java index 8cb44b6..860873e 100644 --- a/src/tap/config/TAPConfiguration.java +++ b/src/tap/config/TAPConfiguration.java @@ -86,6 +86,10 @@ public final class TAPConfiguration { /* USER IDENTIFICATION */ public final static String KEY_USER_IDENTIFIER = "user_identifier"; + /* ADQL RESTRICTIONS */ + public final static String KEY_GEOMETRIES = "geometries"; + public final static String VALUE_NONE = "NONE"; + /** * <p>Read the asked property from the given Properties object.</p> * <ul> diff --git a/src/tap/config/tap_configuration_file.html b/src/tap/config/tap_configuration_file.html index 429d2fd..7573f5e 100644 --- a/src/tap/config/tap_configuration_file.html +++ b/src/tap/config/tap_configuration_file.html @@ -454,6 +454,23 @@ </td> <td>{apackage.FooUserIdentifier}</td> </tr> + + <tr><td colspan="5">ADQL restrictions</td></tr> + <tr> + <td class="done">geometries</td> + <td></td> + <td>text</td> + <td> + <p>Comma-separated list of all allowed geometries.</p> + <p> + Each item of the list must be the name (whatever is the case) of an ADQL geometrical function (e.g. INTERSECTS, COORDSYS, POINT) to allow. + If the list is empty (no item), all functions are allowed. And if the special value <em>NONE</em> is given, no ADQL function will be allowed. + </p> + <p><em>By default, all ADQL geometrical functions are allowed.</em></p> + </td> + <td><ul><li>ΓΈ <em>(default)</em></li><li>NONE</li><li>CONTAINS, intersects, Point, Box, CIRCLE</li></ul></td> + </tr> + </table> </body> </html> \ No newline at end of file diff --git a/test/tap/config/TestDefaultServiceConnection.java b/test/tap/config/TestDefaultServiceConnection.java index 54c3e95..4124ce7 100644 --- a/test/tap/config/TestDefaultServiceConnection.java +++ b/test/tap/config/TestDefaultServiceConnection.java @@ -8,6 +8,7 @@ import static org.junit.Assert.fail; import static tap.config.TAPConfiguration.DEFAULT_MAX_ASYNC_JOBS; import static tap.config.TAPConfiguration.KEY_DEFAULT_OUTPUT_LIMIT; import static tap.config.TAPConfiguration.KEY_FILE_MANAGER; +import static tap.config.TAPConfiguration.KEY_GEOMETRIES; import static tap.config.TAPConfiguration.KEY_MAX_ASYNC_JOBS; import static tap.config.TAPConfiguration.KEY_MAX_OUTPUT_LIMIT; import static tap.config.TAPConfiguration.KEY_METADATA; @@ -18,12 +19,14 @@ import static tap.config.TAPConfiguration.VALUE_CSV; import static tap.config.TAPConfiguration.VALUE_DB; import static tap.config.TAPConfiguration.VALUE_JSON; import static tap.config.TAPConfiguration.VALUE_LOCAL; +import static tap.config.TAPConfiguration.VALUE_NONE; import static tap.config.TAPConfiguration.VALUE_SV; import static tap.config.TAPConfiguration.VALUE_TSV; import static tap.config.TAPConfiguration.VALUE_XML; import java.io.File; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.Map; import java.util.Properties; @@ -52,7 +55,8 @@ public class TestDefaultServiceConnection { badSVFormat2Prop, unknownFormatProp, maxAsyncProp, negativeMaxAsyncProp, notIntMaxAsyncProp, defaultOutputLimitProp, maxOutputLimitProp, bothOutputLimitGoodProp, - bothOutputLimitBadProp, userIdentProp, notClassPathUserIdentProp; + bothOutputLimitBadProp, userIdentProp, notClassPathUserIdentProp, + geometriesProp, noneGeomProp, noneInsideGeomProp, unknownGeomProp; @Before public void setUp() throws Exception{ @@ -126,6 +130,18 @@ public class TestDefaultServiceConnection { notClassPathUserIdentProp = (Properties)validProp.clone(); notClassPathUserIdentProp.setProperty(KEY_USER_IDENTIFIER, "foo"); + + geometriesProp = (Properties)validProp.clone(); + geometriesProp.setProperty(KEY_GEOMETRIES, "point, CIRCle , cONTAins,intersECTS"); + + noneGeomProp = (Properties)validProp.clone(); + noneGeomProp.setProperty(KEY_GEOMETRIES, VALUE_NONE); + + noneInsideGeomProp = (Properties)validProp.clone(); + noneInsideGeomProp.setProperty(KEY_GEOMETRIES, "POINT, Box, none, circle"); + + unknownGeomProp = (Properties)validProp.clone(); + unknownGeomProp.setProperty(KEY_GEOMETRIES, "POINT, Contains, foo, circle,Polygon"); } /** @@ -167,6 +183,7 @@ public class TestDefaultServiceConnection { assertTrue(connection.getRetentionPeriod()[0] <= connection.getRetentionPeriod()[1]); assertTrue(connection.getExecutionDuration()[0] <= connection.getExecutionDuration()[1]); assertNull(connection.getUserIdentifier()); + assertNull(connection.getGeometries()); // finally, save metadata in an XML file for the other tests: writer = new PrintWriter(new File(XML_FILE)); @@ -195,6 +212,7 @@ public class TestDefaultServiceConnection { assertTrue(connection.getRetentionPeriod()[0] <= connection.getRetentionPeriod()[1]); assertTrue(connection.getExecutionDuration()[0] <= connection.getExecutionDuration()[1]); assertNull(connection.getUserIdentifier()); + assertNull(connection.getGeometries()); }catch(Exception e){ e.printStackTrace(); fail("This MUST have succeeded because the property file is valid! \nCaught exception: " + getPertinentMessage(e)); @@ -413,6 +431,46 @@ public class TestDefaultServiceConnection { assertEquals(e.getClass(), TAPException.class); assertEquals(e.getMessage(), "Class path expected for the property \"" + KEY_USER_IDENTIFIER + "\", instead of: \"foo\"!"); } + + // Valid geometry list: + try{ + ServiceConnection connection = new DefaultServiceConnection(geometriesProp); + assertNotNull(connection.getGeometries()); + assertEquals(4, connection.getGeometries().size()); + assertEquals("POINT", ((ArrayList<String>)connection.getGeometries()).get(0)); + assertEquals("CIRCLE", ((ArrayList<String>)connection.getGeometries()).get(1)); + assertEquals("CONTAINS", ((ArrayList<String>)connection.getGeometries()).get(2)); + assertEquals("INTERSECTS", ((ArrayList<String>)connection.getGeometries()).get(3)); + }catch(Exception e){ + fail("This MUST have succeeded because the given list of geometries is correct! \nCaught exception: " + getPertinentMessage(e)); + } + + // "NONE" as geometry list: + try{ + ServiceConnection connection = new DefaultServiceConnection(noneGeomProp); + assertNotNull(connection.getGeometries()); + assertEquals(0, connection.getGeometries().size()); + }catch(Exception e){ + fail("This MUST have succeeded because the given list of geometries is correct (reduced to only NONE)! \nCaught exception: " + getPertinentMessage(e)); + } + + // "NONE" inside a geometry list: + try{ + new DefaultServiceConnection(noneInsideGeomProp); + fail("This MUST have failed because the given geometry list contains at least 2 items, whose one is NONE!"); + }catch(Exception e){ + assertEquals(e.getClass(), TAPException.class); + assertEquals(e.getMessage(), "The special value \"" + VALUE_NONE + "\" can not be used inside a list! It MUST be used in replacement of a whole list to specify that no value is allowed."); + } + + // Unknown geometrical function: + try{ + new DefaultServiceConnection(unknownGeomProp); + fail("This MUST have failed because the given geometry list contains at least 1 unknown ADQL geometrical function!"); + }catch(Exception e){ + assertEquals(e.getClass(), TAPException.class); + assertEquals(e.getMessage(), "Unknown ADQL geometrical function: \"foo\"!"); + } } public static final String getPertinentMessage(final Exception ex){ -- GitLab