diff --git a/src/tap/config/ConfigurableServiceConnection.java b/src/tap/config/ConfigurableServiceConnection.java index 540f44f4abe2f1f88ad7ea276df0b41000fe666c..9079d01257d00292dd02b6cce18eb87a9f2ce11f 100644 --- a/src/tap/config/ConfigurableServiceConnection.java +++ b/src/tap/config/ConfigurableServiceConnection.java @@ -6,6 +6,7 @@ import static tap.config.TAPConfiguration.DEFAULT_GROUP_USER_DIRECTORIES; import static tap.config.TAPConfiguration.DEFAULT_MAX_ASYNC_JOBS; import static tap.config.TAPConfiguration.DEFAULT_RETENTION_PERIOD; import static tap.config.TAPConfiguration.DEFAULT_UPLOAD_MAX_FILE_SIZE; +import static tap.config.TAPConfiguration.KEY_COORD_SYS; import static tap.config.TAPConfiguration.KEY_DEFAULT_EXECUTION_DURATION; import static tap.config.TAPConfiguration.KEY_DEFAULT_OUTPUT_LIMIT; import static tap.config.TAPConfiguration.KEY_DEFAULT_RETENTION_PERIOD; @@ -87,6 +88,7 @@ import uws.service.file.LocalUWSFileManager; import uws.service.file.UWSFileManager; import uws.service.log.UWSLog.LogLevel; import adql.db.FunctionDef; +import adql.db.STCS; import adql.parser.ParseException; import adql.query.operand.function.UserDefinedFunction; @@ -123,6 +125,8 @@ public final class ConfigurableServiceConnection implements ServiceConnection { private UserIdentifier userIdentifier = null; + private ArrayList<String> lstCoordSys = null; + private ArrayList<String> geometries = null; private final String GEOMETRY_REGEXP = "(AREA|BOX|CENTROID|CIRCLE|CONTAINS|DISTANCE|COORD1|COORD2|COORDSYS|INTERSECTS|POINT|POLYGON|REGION)"; @@ -175,6 +179,7 @@ public final class ConfigurableServiceConnection implements ServiceConnection { initUserIdentifier(tapConfig); // 9. CONFIGURE ADQL: + initCoordSys(tapConfig); initADQLGeometries(tapConfig); initUDFs(tapConfig); } @@ -669,6 +674,57 @@ public final class ConfigurableServiceConnection implements ServiceConnection { userIdentifier = newInstance(propValue, KEY_USER_IDENTIFIER, UserIdentifier.class); } + private void initCoordSys(final Properties tapConfig) throws TAPException{ + // Get the property value: + String propValue = getProperty(tapConfig, KEY_COORD_SYS); + + // NO VALUE => ALL COORD SYS ALLOWED! + if (propValue == null) + lstCoordSys = null; + + // "NONE" => ALL COORD SYS FORBIDDEN (= no coordinate system expression is allowed)! + else if (propValue.equalsIgnoreCase(VALUE_NONE)) + lstCoordSys = new ArrayList<String>(0); + + // "ANY" => ALL COORD SYS ALLOWED (= any coordinate system is allowed)! + else if (propValue.equalsIgnoreCase(VALUE_ANY)) + lstCoordSys = null; + + // OTHERWISE, JUST THE ALLOWED ONE ARE LISTED: + else{ + // split all the list items: + String[] items = propValue.split(","); + if (items.length > 0){ + lstCoordSys = new ArrayList<String>(items.length); + for(String item : items){ + item = item.trim(); + // empty item => ignored + if (item.length() <= 0) + continue; + // "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."); + // "ANY" is not allowed inside a list => error! + else if (item.toUpperCase().equals(VALUE_ANY)) + throw new TAPException("The special value \"" + VALUE_ANY + "\" can not be used inside a list! It MUST be used in replacement of a whole list to specify that any value is allowed."); + // parse the coordinate system regular expression in order to check it: + else{ + try{ + STCS.buildCoordSysRegExp(new String[]{item}); + lstCoordSys.add(item); + }catch(ParseException pe){ + throw new TAPException("Incorrect coordinate system regular expression (\"" + item + "\"): " + pe.getMessage(), pe); + } + } + } + // if finally no item has been specified, consider it as "any coordinate system allowed": + if (lstCoordSys.size() == 0) + lstCoordSys = null; + }else + lstCoordSys = null; + } + } + private void initADQLGeometries(final Properties tapConfig) throws TAPException{ // Get the property value: String propValue = getProperty(tapConfig, KEY_GEOMETRIES); @@ -996,7 +1052,7 @@ public final class ConfigurableServiceConnection implements ServiceConnection { @Override public Collection<String> getCoordinateSystems(){ - return null; + return lstCoordSys; } @Override diff --git a/src/tap/config/TAPConfiguration.java b/src/tap/config/TAPConfiguration.java index bdf2b0a933d3c2448f7d340375977bfbf0b0785e..9a256c0fb99954158197ead5bcf4c7ebd3cc085d 100644 --- a/src/tap/config/TAPConfiguration.java +++ b/src/tap/config/TAPConfiguration.java @@ -107,6 +107,7 @@ public final class TAPConfiguration { public final static String KEY_USER_IDENTIFIER = "user_identifier"; /* ADQL RESTRICTIONS */ + public final static String KEY_COORD_SYS = "coordinate_systems"; public final static String KEY_GEOMETRIES = "geometries"; public final static String VALUE_NONE = "NONE"; public final static String KEY_UDFS = "udfs"; diff --git a/src/tap/config/tap_configuration_file.html b/src/tap/config/tap_configuration_file.html index 93c07aac5ba1ad1280281a86b43fd393d57de78e..534d88a80f1ef15987e4f9f799acfe748160945b 100644 --- a/src/tap/config/tap_configuration_file.html +++ b/src/tap/config/tap_configuration_file.html @@ -568,6 +568,33 @@ </tr> <tr><td colspan="5">ADQL restrictions</td></tr> + <tr class="optional"> + <td class="done">coordinate_systems</td> + <td></td> + <td>text</td> + <td> + <p>Comma-separated list of all allowed coordinate systems.</p> + <p> + Each item of the list be a kind of regular expression respecting the following syntax: + <code><i>Frame</i> <i>RefPos</i> <i>Flavor</i></code>. In other words, it must be a string of exactly + 3 parts. Each of this part is a single value, a list of allowed values or a <code>*</code> meaning all + values. A list of values must be indicated between parenthesis and values must be separated by a pipe. + </p> + <p>Allowed values for <code>Frame</code> are: <code>ICRS</code>, <code>FK4</code>, + <code>FK5</code>, <code>ECLIPTIC</code>, <code>GALACTIC</code> and <code>UNKNOWNFRAME</code>.</p> + <p>Allowed values for <code>RefPos</code> are: <code>BARYCENTER</code>, <code>GEOCENTER</code>, + <code>HELIOCENTER</code>, <code>LSR</code>, <code>TOPOCENTER</code>, <code>RELOCATABLE</code> + and <code>UNKNOWNREFPOS</code>.</p> + <p>Allowed values for <code>Flavor</code> are: <code>CARTESIAN2</code>, <code>CARTESIAN3</code> and + <code>SPHERICAL2</code>.</p> + <p> + If the special value <em>NONE</em> is given instead of a list of allowed coordinate systems, + no coordinate system will be allowed. And if the list is empty, any coordinate system will be allowed. + </p> + <p><em>By default, any coordinate system is allowed.</em></p> + </td> + <td><ul><li>ΓΈ <em>(default)</em></li><li>NONE</li><li>ICRS * *</li><li>ICRS * *, ECLIPTIC * (CARTESIAN2 | SPHERICAL2)</li></ul></td> + </tr> <tr class="optional"> <td class="done">geometries</td> <td></td> diff --git a/src/tap/config/tap_full.properties b/src/tap/config/tap_full.properties index 38cc237a0e8ebe777fc73b94c76f7a0e4db2a938..1e4800870523df255655c35b1da0262b0a38295c 100644 --- a/src/tap/config/tap_full.properties +++ b/src/tap/config/tap_full.properties @@ -2,7 +2,7 @@ # FULL TAP CONFIGURATION FILE # # # # TAP Version: 2.0 # -# Date: 10 Mars 2015 # +# Date: 11 Mars 2015 # # Author: Gregory Mantelet (ARI) # # # ########################################################## @@ -416,6 +416,24 @@ upload_max_file_size = 2147483647B # Default: no identification is performed => all users are then anonymous and their jobs can be seen by everybody. user_identifier = +###################### +# COORDINATE SYSTEMS # +###################### + +# [OPTIONAL] +# Comma-separated list of all allowed coordinate systems. +# +# Each item of the list be a kind of regular expression respecting the following syntax: Frame RefPos Flavor. In other words, it must be a string of exactly 3 parts. Each of this part is a single value, a list of allowed values or a * meaning all values. A list of values must be indicated between parenthesis and values must be separated by a pipe. +# +# Allowed values for Frame are: ICRS, FK4, FK5, ECLIPTIC, GALACTIC and UNKNOWNFRAME. +# Allowed values for RefPos are: BARYCENTER, GEOCENTER, HELIOCENTER, LSR, TOPOCENTER, RELOCATABLE and UNKNOWNREFPOS. +# Allowed values for Flavor are: CARTESIAN2, CARTESIAN3 and SPHERICAL2. +# +# If the special value NONE is given instead of a list of allowed coordinate systems, no coordinate system will be allowed. And if the list is empty, any coordinate system will be allowed. +# +# By default, any coordinate system is allowed. +coordinate_systems = + ############## # GEOMETRIES # ############## diff --git a/test/tap/config/TestConfigurableServiceConnection.java b/test/tap/config/TestConfigurableServiceConnection.java index ccba62d53fddd51c6e8f206609ec09de2f1b6cd6..006bd5ef2d78fc2f079b5d07407728c86c9277c6 100644 --- a/test/tap/config/TestConfigurableServiceConnection.java +++ b/test/tap/config/TestConfigurableServiceConnection.java @@ -7,6 +7,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static tap.config.TAPConfiguration.DEFAULT_MAX_ASYNC_JOBS; +import static tap.config.TAPConfiguration.KEY_COORD_SYS; import static tap.config.TAPConfiguration.KEY_DEFAULT_OUTPUT_LIMIT; import static tap.config.TAPConfiguration.KEY_FILE_MANAGER; import static tap.config.TAPConfiguration.KEY_GEOMETRIES; @@ -65,6 +66,9 @@ import uws.service.file.LocalUWSFileManager; import uws.service.log.DefaultUWSLog; import uws.service.log.UWSLog.LogLevel; import adql.db.FunctionDef; +import adql.db.STCS.Flavor; +import adql.db.STCS.Frame; +import adql.db.STCS.RefPos; import adql.db.TestDBChecker.UDFToto; import adql.translator.PostgreSQLTranslator; @@ -83,14 +87,15 @@ public class TestConfigurableServiceConnection { maxAsyncProp, negativeMaxAsyncProp, notIntMaxAsyncProp, defaultOutputLimitProp, maxOutputLimitProp, bothOutputLimitGoodProp, bothOutputLimitBadProp, userIdentProp, - notClassPathUserIdentProp, geometriesProp, noneGeomProp, - anyGeomProp, noneInsideGeomProp, unknownGeomProp, anyUdfsProp, - noneUdfsProp, udfsProp, udfsWithClassNameProp, - udfsListWithNONEorANYProp, udfsWithWrongParamLengthProp, - udfsWithMissingBracketsProp, udfsWithMissingDefProp1, - udfsWithMissingDefProp2, emptyUdfItemProp1, emptyUdfItemProp2, - udfWithMissingEndBracketProp, customFactoryProp, - badCustomFactoryProp; + notClassPathUserIdentProp, coordSysProp, noneCoordSysProp, + anyCoordSysProp, noneInsideCoordSysProp, unknownCoordSysProp, + geometriesProp, noneGeomProp, anyGeomProp, noneInsideGeomProp, + unknownGeomProp, anyUdfsProp, noneUdfsProp, udfsProp, + udfsWithClassNameProp, udfsListWithNONEorANYProp, + udfsWithWrongParamLengthProp, udfsWithMissingBracketsProp, + udfsWithMissingDefProp1, udfsWithMissingDefProp2, + emptyUdfItemProp1, emptyUdfItemProp2, udfWithMissingEndBracketProp, + customFactoryProp, badCustomFactoryProp; @BeforeClass public static void setUp() throws Exception{ @@ -199,6 +204,21 @@ public class TestConfigurableServiceConnection { notClassPathUserIdentProp = (Properties)validProp.clone(); notClassPathUserIdentProp.setProperty(KEY_USER_IDENTIFIER, "foo"); + coordSysProp = (Properties)validProp.clone(); + coordSysProp.setProperty(KEY_COORD_SYS, "icrs * *, ICrs * (Spherical2| CARTEsian2)"); + + noneCoordSysProp = (Properties)validProp.clone(); + noneCoordSysProp.setProperty(KEY_COORD_SYS, VALUE_NONE); + + anyCoordSysProp = (Properties)validProp.clone(); + anyCoordSysProp.setProperty(KEY_COORD_SYS, VALUE_ANY); + + noneInsideCoordSysProp = (Properties)validProp.clone(); + noneInsideCoordSysProp.setProperty(KEY_COORD_SYS, " ICRS * *, none, FK4 (GEOCENTER|heliocenter) *"); + + unknownCoordSysProp = (Properties)validProp.clone(); + unknownCoordSysProp.setProperty(KEY_COORD_SYS, "ICRS foo *"); + geometriesProp = (Properties)validProp.clone(); geometriesProp.setProperty(KEY_GEOMETRIES, "point, CIRCle , cONTAins,intersECTS"); @@ -756,6 +776,52 @@ public class TestConfigurableServiceConnection { assertEquals("Unknown ADQL geometrical function: \"foo\"!", e.getMessage()); } + // Valid coordinate systems list: + try{ + ServiceConnection connection = new ConfigurableServiceConnection(coordSysProp); + assertNotNull(connection.getCoordinateSystems()); + assertEquals(2, connection.getCoordinateSystems().size()); + assertEquals("icrs * *", ((ArrayList<String>)connection.getCoordinateSystems()).get(0)); + assertEquals("ICrs * (Spherical2| CARTEsian2)", ((ArrayList<String>)connection.getCoordinateSystems()).get(1)); + }catch(Exception e){ + fail("This MUST have succeeded because the given list of coordinate systems is correct! \nCaught exception: " + getPertinentMessage(e)); + } + + // "NONE" as coordinate systems list: + try{ + ServiceConnection connection = new ConfigurableServiceConnection(noneCoordSysProp); + assertNotNull(connection.getCoordinateSystems()); + assertEquals(0, connection.getCoordinateSystems().size()); + }catch(Exception e){ + fail("This MUST have succeeded because the given list of coordinate systems is correct (reduced to only NONE)! \nCaught exception: " + getPertinentMessage(e)); + } + + // "ANY" as coordinate systems list: + try{ + ServiceConnection connection = new ConfigurableServiceConnection(anyCoordSysProp); + assertNull(connection.getCoordinateSystems()); + }catch(Exception e){ + fail("This MUST have succeeded because the given list of coordinate systems is correct (reduced to only ANY)! \nCaught exception: " + getPertinentMessage(e)); + } + + // "NONE" inside a coordinate systems list: + try{ + new ConfigurableServiceConnection(noneInsideCoordSysProp); + fail("This MUST have failed because the given coordinate systems list contains at least 3 items, whose one is NONE!"); + }catch(Exception e){ + assertEquals(TAPException.class, e.getClass()); + assertEquals("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.", e.getMessage()); + } + + // Unknown coordinate system function: + try{ + new ConfigurableServiceConnection(unknownCoordSysProp); + fail("This MUST have failed because the given coordinate systems list contains at least 1 unknown coordinate system!"); + }catch(Exception e){ + assertEquals(TAPException.class, e.getClass()); + assertEquals("Incorrect coordinate system regular expression (\"ICRS foo *\"): Wrong allowed coordinate system syntax for the 1-th item: \"ICRS foo *\"! Expected: \"frameRegExp refposRegExp flavorRegExp\" ; where each xxxRegExp = (xxx | '*' | '('xxx ('|' xxx)*')'), frame=\"" + Frame.regexp + "\", refpos=\"" + RefPos.regexp + "\" and flavor=\"" + Flavor.regexp + "\" ; an empty string is also allowed and will be interpreted as '*' (so all possible values).", e.getMessage()); + } + // "ANY" as UDFs list: try{ ServiceConnection connection = new ConfigurableServiceConnection(anyUdfsProp);