From 1dd786a4a7038e3047daa33fe1df1658babe0874 Mon Sep 17 00:00:00 2001 From: Dustin Jenkins Date: Mon, 25 Jul 2022 14:55:57 -0700 Subject: [PATCH 01/10] Initial commit. --- cadc-conesearch/README.md | 38 +++ cadc-conesearch/build.gradle | 30 +++ .../conesearch/NumberParameterValidator.java | 127 ++++++++++ .../opencadc/conesearch/ParameterNames.java | 84 +++++++ .../conesearch/SimpleTAPQueryGenerator.java | 94 ++++++++ .../conesearch/TAPQueryGenerator.java | 222 ++++++++++++++++++ .../conesearch/config/ConeSearchConfig.java | 158 +++++++++++++ .../config/ConfigurationParameterNames.java | 85 +++++++ .../NumberParameterValidatorTest.java | 135 +++++++++++ .../conesearch/TAPQueryGeneratorTest.java | 206 ++++++++++++++++ .../config/ConeSearchConfigTest.java | 73 ++++++ 11 files changed, 1252 insertions(+) create mode 100644 cadc-conesearch/README.md create mode 100644 cadc-conesearch/build.gradle create mode 100644 cadc-conesearch/src/main/java/org/opencadc/conesearch/NumberParameterValidator.java create mode 100644 cadc-conesearch/src/main/java/org/opencadc/conesearch/ParameterNames.java create mode 100644 cadc-conesearch/src/main/java/org/opencadc/conesearch/SimpleTAPQueryGenerator.java create mode 100644 cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java create mode 100644 cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConeSearchConfig.java create mode 100644 cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConfigurationParameterNames.java create mode 100644 cadc-conesearch/src/test/java/org/opencadc/conesearch/NumberParameterValidatorTest.java create mode 100644 cadc-conesearch/src/test/java/org/opencadc/conesearch/TAPQueryGeneratorTest.java create mode 100644 cadc-conesearch/src/test/java/org/opencadc/conesearch/config/ConeSearchConfigTest.java diff --git a/cadc-conesearch/README.md b/cadc-conesearch/README.md new file mode 100644 index 00000000..4cd9adf8 --- /dev/null +++ b/cadc-conesearch/README.md @@ -0,0 +1,38 @@ +# cadc-conesearch (1.0.0) + +Library containing logic to help implementors support the [Simple Cone Search Working Draft (1.1)](https://www.ivoa.net/documents/ConeSearch/20200828/WD-ConeSearch-1.1-20200828.html). + +## Building it + +Gradle 6 or higher is required. The DAL repository comes with a Gradle Wrapper. + +```shell +/workdir/dal $ ./gradlew -i -b cadc-conesearch/build.gradle clean build test +``` + +## Installing it + +Gradle 6 or higher is required. The DAL repository comes with a Gradle Wrapper. + +```shell +/workdir/dal $ ./gradlew -i -b cadc-conesearch/build.gradle clean build test install +``` + +## Implementing it + +Your `build.gradle` file should include it as a dependency from Maven Central: + +```groovy +(build.gradle) + +repositories { + mavenCentral() + mavenLocal() +} + +dependencies { + implementation 'org.opencadc:cadc-conesearch:1.0.0' +} +``` + + diff --git a/cadc-conesearch/build.gradle b/cadc-conesearch/build.gradle new file mode 100644 index 00000000..704ab8e5 --- /dev/null +++ b/cadc-conesearch/build.gradle @@ -0,0 +1,30 @@ +plugins { + id 'java-library' + id 'maven' + id 'maven-publish' + id 'checkstyle' +} + +repositories { + mavenCentral() + mavenLocal() +} + +sourceCompatibility = 1.8 +group = 'org.opencadc' +version = '1.0.0' + +description = 'OpenCADC Simple Cone Search Java API' +def git_url = 'https://github.com/opencadc/dal.git' + +dependencies { + implementation 'org.opencadc:cadc-dali:[1.2.4,2.0)' + implementation 'org.opencadc:cadc-rest:[1.3.12,2.0)' + implementation 'org.opencadc:cadc-util:[1.6.4,2.0)' + implementation 'org.opencadc:cadc-vosi:[1.4.4,2.0)' + + // Use JUnit test framework. + testImplementation 'junit:junit:4.13' +} + +apply from: '../opencadc.gradle' diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/NumberParameterValidator.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/NumberParameterValidator.java new file mode 100644 index 00000000..0c03edb9 --- /dev/null +++ b/cadc-conesearch/src/main/java/org/opencadc/conesearch/NumberParameterValidator.java @@ -0,0 +1,127 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2022. (c) 2022. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package org.opencadc.conesearch; + +import ca.nrc.cadc.util.StringUtil; + +public class NumberParameterValidator { + private final boolean capValue; + private final int minValue; + private final int maxValue; + private final int defaultValue; + + + /** + * Constructor. + * + * @param capValue Set to true to cap the upper value to the max + */ + public NumberParameterValidator(final boolean capValue, final int minValue, final int maxValue, + final int defaultValue) { + + if (minValue > maxValue) { + throw new IllegalArgumentException("Min value must be less than or equal to Max value."); + } else if (defaultValue > maxValue || defaultValue < minValue) { + throw new IllegalArgumentException("Default value does not fall between specified min and max values (" + + minValue + " and " + maxValue + ")."); + } + + this.capValue = capValue; + this.minValue = minValue; + this.maxValue = maxValue; + this.defaultValue = defaultValue; + } + + public int validate(final String parameterNumberValue) { + final int integerValue; + if (StringUtil.hasText(parameterNumberValue)) { + try { + final int parsedValue = Integer.parseInt(parameterNumberValue); + if (parsedValue > maxValue && capValue) { + integerValue = maxValue; + } else if (parsedValue < minValue && capValue) { + integerValue = minValue; + } else { + integerValue = parsedValue; + } + } catch (NumberFormatException numberFormatException) { + throw new IllegalArgumentException("Cannot parse number value (not a valid number)"); + } + + if (integerValue < minValue || integerValue > maxValue) { + throw new IllegalArgumentException( + "Input MUST be a value between " + minValue + " and " + maxValue + "."); + } + } else { + integerValue = defaultValue; + } + + return integerValue; + } +} diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/ParameterNames.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/ParameterNames.java new file mode 100644 index 00000000..6728555a --- /dev/null +++ b/cadc-conesearch/src/main/java/org/opencadc/conesearch/ParameterNames.java @@ -0,0 +1,84 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2022. (c) 2022. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package org.opencadc.conesearch; + +public enum ParameterNames { + DEC(true), RA(true), SR(true), + MAXREC(false), RESPONSEFORMAT(false), TIME(false), VERB(false); + + private final boolean required; + + ParameterNames(final boolean required) { + this.required = required; + } + + public boolean isRequired() { + return required; + } +} diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/SimpleTAPQueryGenerator.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/SimpleTAPQueryGenerator.java new file mode 100644 index 00000000..664c4821 --- /dev/null +++ b/cadc-conesearch/src/main/java/org/opencadc/conesearch/SimpleTAPQueryGenerator.java @@ -0,0 +1,94 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2022. (c) 2022. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package org.opencadc.conesearch; + +/** + * Basic concrete implementation of the TAP Query Generator. This will provide all columns for each VERB level. + */ +public class SimpleTAPQueryGenerator extends TAPQueryGenerator { + private final static String RETURN_ALL = "*"; + public SimpleTAPQueryGenerator(final String catalog) { + super(catalog); + } + + @Override + public String getLowVerbositySelectList() { + return RETURN_ALL; + } + + @Override + public String getMidVerbositySelectList() { + return RETURN_ALL; + } + + @Override + public String getHighVerbositySelectList() { + return RETURN_ALL; + } +} diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java new file mode 100644 index 00000000..98dd31dd --- /dev/null +++ b/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java @@ -0,0 +1,222 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2022. (c) 2022. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package org.opencadc.conesearch; + +import ca.nrc.cadc.dali.Circle; +import ca.nrc.cadc.dali.CommonParamValidator; +import ca.nrc.cadc.dali.tables.votable.VOTableWriter; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +/** + * Class to produce an ADQL query from a set of Parameters + */ +public abstract class TAPQueryGenerator extends CommonParamValidator { + private static final int DEF_MAXREC = 1000; + private static final int MAX_MAXREC = Integer.MAX_VALUE; + private static final int MIN_VERB_VALUE = 1; + private static final int MID_VERB_VALUE = 2; + private static final int MAX_VERB_VALUE = 3; + private final static Logger LOGGER = LogManager.getLogger(TAPQueryGenerator.class); + + protected final String catalog; + + public TAPQueryGenerator(final String catalog) { + this.catalog = catalog; + } + + /** + * Map with the REQUEST, LANG, and QUERY parameters. + * + * @param positionColumnName The name of the positional column to compare against the cone's position, + * preferably spatially indexed. + * @return map of parameter names and values + */ + public Map getParameterMap(final String positionColumnName, + final Map> parameters) { + final Map queryParameterMap = new HashMap<>(); + + // Obtain and, if necessary, provide a default RESPONSEFORMAT. + final String requestedResponseFormat = getFirstParameter(ParameterNames.RESPONSEFORMAT.name(), parameters, + VOTableWriter.CONTENT_TYPE); + queryParameterMap.put(ParameterNames.RESPONSEFORMAT.name(), requestedResponseFormat); + + // Obtain and validate the VERB (verbosity) output. + final String requestedOutputVerbosity = getFirstParameter(ParameterNames.VERB.name(), parameters, + Integer.toString(MID_VERB_VALUE)); + final NumberParameterValidator outputVerbosityValidator = + new NumberParameterValidator(false, TAPQueryGenerator.MIN_VERB_VALUE, + TAPQueryGenerator.MAX_VERB_VALUE, TAPQueryGenerator.MID_VERB_VALUE); + final int outputVerbosity = outputVerbosityValidator.validate(requestedOutputVerbosity); + + // Obtain and validate the MAXREC value with a default if necessary. + final String requestedMaxRecords = getFirstParameter(ParameterNames.MAXREC.name(), parameters, + Integer.toString(TAPQueryGenerator.DEF_MAXREC)); + final NumberParameterValidator maxRecordsValidator = + new NumberParameterValidator(true, 0, TAPQueryGenerator.MAX_MAXREC, + TAPQueryGenerator.DEF_MAXREC); + final int maxRecordCount = maxRecordsValidator.validate(requestedMaxRecords); + queryParameterMap.put(ParameterNames.MAXREC.name(), maxRecordCount); + + queryParameterMap.put("LANG", "ADQL"); + final String query = getQuery(positionColumnName, outputVerbosity, validateConePositionCenter(parameters)); + LOGGER.debug("Cone Search TAP query:\n" + query); + queryParameterMap.put("QUERY", query); + return queryParameterMap; + } + + private String getQuery(final String positionColumnName, final int outputVerbosity, final Circle circle) { + return "SELECT " + + getSelectList(outputVerbosity) + + " FROM " + + this.catalog + + " WHERE 1 = CONTAINS(" + + positionColumnName + + ", " + + "CIRCLE(" + + circle.getCenter().getLongitude() + + ", " + + circle.getCenter().getLatitude() + + ", " + + circle.getRadius() + + "))"; + } + + private String getFirstParameter(final String key, final Map> requestParameters, + final String defaultValue) { + final List values = requestParameters.get(key); + return (values == null || values.isEmpty()) ? defaultValue : values.get(0); + } + + private Circle validateConePositionCenter(final Map> requestParameters) { + final String raValue = getFirstParameter(ParameterNames.RA.name(), requestParameters, null); + final String decValue = getFirstParameter(ParameterNames.DEC.name(), requestParameters, null); + final String searchRadiusValue = getFirstParameter(ParameterNames.SR.name(), requestParameters, null); + final Map> circleValidateParams = new HashMap<>(); + circleValidateParams.put(CommonParamValidator.CIRCLE, Collections.singletonList( + String.format("%s %s %s", raValue, decValue, searchRadiusValue))); + + try { + final List validCircles = super.validateCircle(circleValidateParams); + + if (validCircles.isEmpty()) { + throw new IllegalArgumentException("No valid input cone position center provided."); + } else { + return validCircles.get(0); + } + } catch (NumberFormatException numberFormatException) { + throw new IllegalArgumentException("Cannot create cone position center from non-numeric input."); + } + } + + + private String getSelectList(final int outputVerbosity) { + switch (outputVerbosity) { + case TAPQueryGenerator.MIN_VERB_VALUE: { + return getLowVerbositySelectList(); + } + + case TAPQueryGenerator.MAX_VERB_VALUE: { + return getHighVerbositySelectList(); + } + + // Default output is MID (2) + default: { + return getMidVerbositySelectList(); + } + } + } + + /** + * Obtain a select list for the Low Verbosity (1). + * @return String select columns, or "*", never null. + * Example: "ra, dec, footprint" + */ + public abstract String getLowVerbositySelectList(); + + /** + * Obtain a select list for the Medium Verbosity (2), which is the default. + * @return String select columns, or "*", never null. + * Example: "obs_id, release_date, ra, dec, footprint" + */ + public abstract String getMidVerbositySelectList(); + + /** + * Obtain a select list for the High Verbosity (3). + * @return String select columns, or "*", never null. + * Example: "*" + */ + public abstract String getHighVerbositySelectList(); +} diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConeSearchConfig.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConeSearchConfig.java new file mode 100644 index 00000000..10b2877f --- /dev/null +++ b/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConeSearchConfig.java @@ -0,0 +1,158 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2022. (c) 2022. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package org.opencadc.conesearch.config; + +import ca.nrc.cadc.auth.AuthMethod; +import ca.nrc.cadc.auth.AuthenticationUtil; +import ca.nrc.cadc.reg.Standards; +import ca.nrc.cadc.reg.client.RegistryClient; +import ca.nrc.cadc.util.MultiValuedProperties; +import ca.nrc.cadc.util.PropertiesReader; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; + + +/** + * Configuration of this web application. + */ +public class ConeSearchConfig { + private final static String CONFIG_FILE_NAME = "cadc-conesearch.properties"; + private final static Logger LOGGER = LogManager.getLogger(ConeSearchConfig.class); + + private final MultiValuedProperties properties; + + + public ConeSearchConfig() { + this(new PropertiesReader(ConeSearchConfig.CONFIG_FILE_NAME)); + } + + /** + * Complete constructor. + * @param propertiesReader A reader on the configuration file. + * + * @throws IllegalArgumentException If the configuration file cannot be read. + */ + ConeSearchConfig(final PropertiesReader propertiesReader) { + if (propertiesReader.canRead()) { + this.properties = propertiesReader.getAllProperties(); + + if (this.properties == null) { + throw new IllegalArgumentException("No configuration in " + ConeSearchConfig.CONFIG_FILE_NAME); + } else { + LOGGER.debug("Configuration load: OK"); + this.properties.keySet().forEach(k -> LOGGER.debug(k + " -> " + this.properties.getProperty(k))); + } + } else { + throw new IllegalArgumentException("Unable to read " + ConeSearchConfig.CONFIG_FILE_NAME); + } + } + + /** + * Obtain the base TAP URL to use. This method will read in an optionally configured 'tapURI' property and if it + * appears to be a URL, then assume an unregistered TAP service was configured and treat it as the base URL, + * otherwise attempt to use it as a URI and look the URL up in the Registry. + * + * @return URL Base URL of the TAP service to use. + * + * @throws MalformedURLException If a URL cannot be created from the specified string. + */ + public URL getTapBaseURL() throws MalformedURLException { + final URI configuredTapURI = URI.create(getTapURI()); + + final AuthMethod am = AuthenticationUtil.getAuthMethod(AuthenticationUtil.getCurrentSubject()); + if (configuredTapURI.getScheme().equals("ivo")) { + final RegistryClient regClient = new RegistryClient(); + // Attempt to load the URI as a resource URI from the Registry. + return regClient.getServiceURL(configuredTapURI, Standards.TAP_10, (am == null) ? AuthMethod.ANON : am); + } else { + // Fallback and assume the URI is an absolute URL. + return configuredTapURI.toURL(); + } + } + + /** + * Obtain the (ideally) spatially indexed column name to compare the center of the cone's position to. + * @return String column name. + */ + public String getPositionColumnName() { + return properties.getFirstPropertyValue(ConfigurationParameterNames.POSITION_COLUMN_NAME.getPropertyKey()); + } + + /** + * Obtain the configured TAP URI. + * @return String URI value. Never null. + */ + String getTapURI() { + return properties.getFirstPropertyValue(ConfigurationParameterNames.TAP_URI.getPropertyKey()); + } +} diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConfigurationParameterNames.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConfigurationParameterNames.java new file mode 100644 index 00000000..de4fb5ec --- /dev/null +++ b/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConfigurationParameterNames.java @@ -0,0 +1,85 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2022. (c) 2022. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package org.opencadc.conesearch.config; + +public enum ConfigurationParameterNames { + CATALOG_NAME("catalogName"), + TAP_URI("tapURI"), + POSITION_COLUMN_NAME("positionColumnName"); + + private final String propertyKey; + + ConfigurationParameterNames(final String propertyKey) { + this.propertyKey = propertyKey; + } + + public String getPropertyKey() { + return propertyKey; + } +} diff --git a/cadc-conesearch/src/test/java/org/opencadc/conesearch/NumberParameterValidatorTest.java b/cadc-conesearch/src/test/java/org/opencadc/conesearch/NumberParameterValidatorTest.java new file mode 100644 index 00000000..4d40b233 --- /dev/null +++ b/cadc-conesearch/src/test/java/org/opencadc/conesearch/NumberParameterValidatorTest.java @@ -0,0 +1,135 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2022. (c) 2022. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package org.opencadc.conesearch; + +import org.junit.Assert; +import org.junit.Test; + + +public class NumberParameterValidatorTest { + @Test + public void testConstructor() { + try { + new NumberParameterValidator(false, 6, 1, 0); + Assert.fail("Should throw IllegalArgumentException."); + } catch (IllegalArgumentException illegalArgumentException) { + // Good! + } + + try { + new NumberParameterValidator(false, 1, 6, 0); + Assert.fail("Should throw IllegalArgumentException for default being lower than minimum."); + } catch (IllegalArgumentException illegalArgumentException) { + // Good! + } + + try { + new NumberParameterValidator(false, 1, 6, 10); + Assert.fail("Should throw IllegalArgumentException for default being higher than maximum."); + } catch (IllegalArgumentException illegalArgumentException) { + // Good! + } + } + + @Test + public void testInputNoCap() { + final NumberParameterValidator testSubject = new NumberParameterValidator(false, 1, 6, 1); + + Assert.assertEquals("Should be set to 2", 2, testSubject.validate("2")); + Assert.assertEquals("Should be set to 1", 1, testSubject.validate("1")); + Assert.assertEquals("Should be set to 6", 6, testSubject.validate("6")); + Assert.assertEquals("Should default to 0", 1, testSubject.validate(null)); + + try { + testSubject.validate("-1"); + Assert.fail("Should throw IllegalArgumentException."); + } catch (IllegalArgumentException illegalArgumentException) { + // Good! + } + + try { + testSubject.validate("9"); + Assert.fail("Should throw IllegalArgumentException."); + } catch (IllegalArgumentException illegalArgumentException) { + // Good! + } + } + + @Test + public void testInputWithCap() { + final NumberParameterValidator testSubject = new NumberParameterValidator(true, 1, 6, 1); + + Assert.assertEquals("Should be set to 2", 2, testSubject.validate("2")); + Assert.assertEquals("Should be set to 1", 1, testSubject.validate("1")); + Assert.assertEquals("Should be set to 6", 6, testSubject.validate("6")); + Assert.assertEquals("Should default to 0", 1, testSubject.validate(null)); + Assert.assertEquals("Should default to 6", 6, testSubject.validate("9")); + Assert.assertEquals("Should default to 1", 1, testSubject.validate("0")); + } +} diff --git a/cadc-conesearch/src/test/java/org/opencadc/conesearch/TAPQueryGeneratorTest.java b/cadc-conesearch/src/test/java/org/opencadc/conesearch/TAPQueryGeneratorTest.java new file mode 100644 index 00000000..d6793dc5 --- /dev/null +++ b/cadc-conesearch/src/test/java/org/opencadc/conesearch/TAPQueryGeneratorTest.java @@ -0,0 +1,206 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2022. (c) 2022. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package org.opencadc.conesearch; + +import ca.nrc.cadc.dali.tables.votable.VOTableWriter; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class TAPQueryGeneratorTest { + @Test + public void testInvalidJobParameters() { + final TAPQueryGenerator testSubject = new TestTAPQueryGenerator("badcat"); + final Map> parameters = new HashMap<>(); + + try { + testSubject.getParameterMap("my_point", parameters); + Assert.fail("Should throw IllegalArgumentException here."); + } catch (IllegalArgumentException illegalArgumentException) { + // Good + } + + parameters.put("RA", Collections.singletonList("bogus")); + parameters.put("DEC", Collections.singletonList("bogus")); + parameters.put("SR", Collections.singletonList("bogus")); + + try { + testSubject.getParameterMap("my_point_2", parameters); + Assert.fail("Should throw IllegalArgumentException here."); + } catch (IllegalArgumentException illegalArgumentException) { + // Good + } + + parameters.clear(); + parameters.put("RA", Collections.singletonList("12.3")); + parameters.put("DEC", Collections.singletonList("45.6")); + parameters.put("SR", Collections.singletonList("0.7")); + parameters.put("VERB", Collections.singletonList("9")); + + try { + testSubject.getParameterMap("my_point_3", parameters); + Assert.fail("Should throw IllegalArgumentException here for VERB."); + } catch (IllegalArgumentException illegalArgumentException) { + // Good + } + + parameters.clear(); + parameters.put("RA", Collections.singletonList("12.3")); + parameters.put("DEC", Collections.singletonList("45.6")); + parameters.put("SR", Collections.singletonList("0.7")); + parameters.put("VERB", Collections.singletonList("bogus")); + + try { + testSubject.getParameterMap("my_point_4", parameters); + Assert.fail("Should throw IllegalArgumentException here for VERB."); + } catch (IllegalArgumentException illegalArgumentException) { + // Good + } + + parameters.clear(); + parameters.put("RA", Collections.singletonList("12.3")); + parameters.put("DEC", Collections.singletonList("108.6")); + parameters.put("SR", Collections.singletonList("0.7")); + parameters.put("VERB", Collections.singletonList("1")); + + try { + testSubject.getParameterMap("my_point_5", parameters); + Assert.fail("Should throw IllegalArgumentException here for invalid circle."); + } catch (IllegalArgumentException illegalArgumentException) { + // Good (invalid circle) + } + } + + @Test + public void testValidJobParameters() { + final TAPQueryGenerator testSubject = new TestTAPQueryGenerator("goodcat"); + final Map> parameters = new HashMap<>(); + parameters.put("RA", Collections.singletonList("12.3")); + parameters.put("DEC", Collections.singletonList("45.6")); + parameters.put("SR", Collections.singletonList("0.7")); + + + final Map tapQueryParameters1 = testSubject.getParameterMap("point_col", + parameters); + Assert.assertEquals("Wrong response format.", VOTableWriter.CONTENT_TYPE, + tapQueryParameters1.get("RESPONSEFORMAT")); + Assert.assertEquals("Wrong langauge", "ADQL", tapQueryParameters1.get("LANG")); + Assert.assertEquals("Wrong query.", + "SELECT obs_id, release_date, ra, dec " + + "FROM goodcat WHERE 1 = CONTAINS(point_col, CIRCLE(12.3, 45.6, 0.7))", + tapQueryParameters1.get("QUERY")); + Assert.assertEquals("Wrong max records", 1000, tapQueryParameters1.get("MAXREC")); + + // **** Next **** + + parameters.clear(); + parameters.put("RA", Collections.singletonList("12.3")); + parameters.put("DEC", Collections.singletonList("45.6")); + parameters.put("SR", Collections.singletonList("0.7")); + parameters.put("RESPONSEFORMAT", Collections.singletonList("tsv")); + parameters.put("MAXREC", Collections.singletonList("8000")); + parameters.put("VERB", Collections.singletonList("3")); + + + final Map tapQueryParameters2 = testSubject.getParameterMap("point_col_2", + parameters); + Assert.assertEquals("Wrong response format.", "tsv", tapQueryParameters2.get("RESPONSEFORMAT")); + Assert.assertEquals("Wrong langauge", "ADQL", tapQueryParameters2.get("LANG")); + Assert.assertEquals("Wrong query.", + "SELECT * FROM goodcat WHERE 1 = CONTAINS(point_col_2, CIRCLE(12.3, 45.6, 0.7))", + tapQueryParameters2.get("QUERY")); + Assert.assertEquals("Wrong max records", 8000, tapQueryParameters2.get("MAXREC")); + } + + public static final class TestTAPQueryGenerator extends TAPQueryGenerator { + + public TestTAPQueryGenerator(final String catalog) { + super(catalog); + } + + @Override + public String getLowVerbositySelectList() { + return "ra, dec"; + } + + @Override + public String getMidVerbositySelectList() { + return "obs_id, release_date, ra, dec"; + } + + @Override + public String getHighVerbositySelectList() { + return "*"; + } + } +} diff --git a/cadc-conesearch/src/test/java/org/opencadc/conesearch/config/ConeSearchConfigTest.java b/cadc-conesearch/src/test/java/org/opencadc/conesearch/config/ConeSearchConfigTest.java new file mode 100644 index 00000000..a892499d --- /dev/null +++ b/cadc-conesearch/src/test/java/org/opencadc/conesearch/config/ConeSearchConfigTest.java @@ -0,0 +1,73 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2022. (c) 2022. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package org.opencadc.conesearch.config; + +public class ConeSearchConfigTest { + +} From fc235ede7925d4616e2b498fe2210a9c345d7525 Mon Sep 17 00:00:00 2001 From: Dustin Jenkins Date: Tue, 26 Jul 2022 09:58:09 -0700 Subject: [PATCH 02/10] cadc-conesearch library. --- cadc-conesearch/README.md | 34 ++++++- .../conesearch/SimpleTAPQueryGenerator.java | 94 ------------------- .../conesearch/TAPQueryGenerator.java | 25 +++-- .../conesearch/config/ConeSearchConfig.java | 24 +++++ .../config/ConfigurationParameterNames.java | 5 +- .../conesearch/TAPQueryGeneratorTest.java | 32 ++----- 6 files changed, 85 insertions(+), 129 deletions(-) delete mode 100644 cadc-conesearch/src/main/java/org/opencadc/conesearch/SimpleTAPQueryGenerator.java diff --git a/cadc-conesearch/README.md b/cadc-conesearch/README.md index 4cd9adf8..4ede51a9 100644 --- a/cadc-conesearch/README.md +++ b/cadc-conesearch/README.md @@ -22,9 +22,8 @@ Gradle 6 or higher is required. The DAL repository comes with a Gradle Wrapper. Your `build.gradle` file should include it as a dependency from Maven Central: +`build.gradle`: ```groovy -(build.gradle) - repositories { mavenCentral() mavenLocal() @@ -35,4 +34,35 @@ dependencies { } ``` +`${HOME}/config/cadc-conesearch.properties`: +```properties +tapURI = ivo://myhost.com/catalog_tap_service # Or an absolute URL e.g. https://myhost.com/mytap +positionColumnName = my_spatial_indexed_column # Used to compare to the Cone's Center position. Can also be a dynamic spatial object e.g. POINT('ICRS', RA_Source, DEC_Source) +lowVerbositySelectList = obs_id, ra, dec # Columns for VERB=1 +midVerbositySelectList = obs_id, ra, dec, s_region, frequency, bandwidth # Columns for VERB=2 +highVerbositySelectList = * # Columns for VERB=3 +``` + +Capture the Cone Search parameters and translate to ADQL to be sent to a TAP service. + +```java +final ConeSearchConfig coneSearchConfig = new ConeSearchConfig(); // Ensure the cadc-conesearch.properties exists. +final TAPQueryGenerator tapQueryGenerator = new TAPQueryGenerator("mycatalog", coneSearchConfig.getLowVerbositySelectList(), + coneSearchConfig.getMidVerbositySelectList(), + coneSearchConfig.getHighVerbositySelectList()); +// Create TAP parameters +final Map parameters = + tapQueryGenerator.getParameterMap(coneSearchConfig.getPositionColumnName(), + parameterExtractor.getParameters(job.getParameterList())); +// Issue a Synchronous POST request to a TAP service. +final URL tapSyncURL = new URL(coneSearchConfig.getTapBaseURL().toExternalForm() + "/sync"); + +// POST ADQL query to TAP but do not follow redirect to execute it. +final HttpPost post = new HttpPost(tapSyncURL, parameters, false); +post.run(); + +// Do something with the data. +final URL redirectURL = post.getRedirectURL(); // In the case of a redirect +final InputStream inputStream = post.getInputStream(); // Read the data +``` diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/SimpleTAPQueryGenerator.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/SimpleTAPQueryGenerator.java deleted file mode 100644 index 664c4821..00000000 --- a/cadc-conesearch/src/main/java/org/opencadc/conesearch/SimpleTAPQueryGenerator.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - ************************************************************************ - ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* - ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** - * - * (c) 2022. (c) 2022. - * Government of Canada Gouvernement du Canada - * National Research Council Conseil national de recherches - * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 - * All rights reserved Tous droits réservés - * - * NRC disclaims any warranties, Le CNRC dénie toute garantie - * expressed, implied, or énoncée, implicite ou légale, - * statutory, of any kind with de quelque nature que ce - * respect to the software, soit, concernant le logiciel, - * including without limitation y compris sans restriction - * any warranty of merchantability toute garantie de valeur - * or fitness for a particular marchande ou de pertinence - * purpose. NRC shall not be pour un usage particulier. - * liable in any event for any Le CNRC ne pourra en aucun cas - * damages, whether direct or être tenu responsable de tout - * indirect, special or general, dommage, direct ou indirect, - * consequential or incidental, particulier ou général, - * arising from the use of the accessoire ou fortuit, résultant - * software. Neither the name de l'utilisation du logiciel. Ni - * of the National Research le nom du Conseil National de - * Council of Canada nor the Recherches du Canada ni les noms - * names of its contributors may de ses participants ne peuvent - * be used to endorse or promote être utilisés pour approuver ou - * products derived from this promouvoir les produits dérivés - * software without specific prior de ce logiciel sans autorisation - * written permission. préalable et particulière - * par écrit. - * - * This file is part of the Ce fichier fait partie du projet - * OpenCADC project. OpenCADC. - * - * OpenCADC is free software: OpenCADC est un logiciel libre ; - * you can redistribute it and/or vous pouvez le redistribuer ou le - * modify it under the terms of modifier suivant les termes de - * the GNU Affero General Public la “GNU Affero General Public - * License as published by the License” telle que publiée - * Free Software Foundation, par la Free Software Foundation - * either version 3 of the : soit la version 3 de cette - * License, or (at your option) licence, soit (à votre gré) - * any later version. toute version ultérieure. - * - * OpenCADC is distributed in the OpenCADC est distribué - * hope that it will be useful, dans l’espoir qu’il vous - * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE - * without even the implied GARANTIE : sans même la garantie - * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ - * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF - * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence - * General Public License for Générale Publique GNU Affero - * more details. pour plus de détails. - * - * You should have received Vous devriez avoir reçu une - * a copy of the GNU Affero copie de la Licence Générale - * General Public License along Publique GNU Affero avec - * with OpenCADC. If not, see OpenCADC ; si ce n’est - * . pas le cas, consultez : - * . - * - * - ************************************************************************ - */ - -package org.opencadc.conesearch; - -/** - * Basic concrete implementation of the TAP Query Generator. This will provide all columns for each VERB level. - */ -public class SimpleTAPQueryGenerator extends TAPQueryGenerator { - private final static String RETURN_ALL = "*"; - public SimpleTAPQueryGenerator(final String catalog) { - super(catalog); - } - - @Override - public String getLowVerbositySelectList() { - return RETURN_ALL; - } - - @Override - public String getMidVerbositySelectList() { - return RETURN_ALL; - } - - @Override - public String getHighVerbositySelectList() { - return RETURN_ALL; - } -} diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java index 98dd31dd..6478c861 100644 --- a/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java +++ b/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java @@ -83,7 +83,7 @@ /** * Class to produce an ADQL query from a set of Parameters */ -public abstract class TAPQueryGenerator extends CommonParamValidator { +public class TAPQueryGenerator extends CommonParamValidator { private static final int DEF_MAXREC = 1000; private static final int MAX_MAXREC = Integer.MAX_VALUE; private static final int MIN_VERB_VALUE = 1; @@ -92,9 +92,16 @@ public abstract class TAPQueryGenerator extends CommonParamValidator { private final static Logger LOGGER = LogManager.getLogger(TAPQueryGenerator.class); protected final String catalog; + protected final String lowVerbositySelectList; + protected final String midVerbositySelectList; + protected final String highVerbositySelectList; - public TAPQueryGenerator(final String catalog) { + public TAPQueryGenerator(final String catalog, final String lowVerbositySelectList, + final String midVerbositySelectList, final String highVerbositySelectList) { this.catalog = catalog; + this.lowVerbositySelectList = lowVerbositySelectList; + this.midVerbositySelectList = midVerbositySelectList; + this.highVerbositySelectList = highVerbositySelectList; } /** @@ -145,7 +152,7 @@ private String getQuery(final String positionColumnName, final int outputVerbosi + " WHERE 1 = CONTAINS(" + positionColumnName + ", " - + "CIRCLE(" + + "CIRCLE('ICRS', " + circle.getCenter().getLongitude() + ", " + circle.getCenter().getLatitude() @@ -204,19 +211,25 @@ private String getSelectList(final int outputVerbosity) { * @return String select columns, or "*", never null. * Example: "ra, dec, footprint" */ - public abstract String getLowVerbositySelectList(); + public String getLowVerbositySelectList() { + return this.lowVerbositySelectList; + }; /** * Obtain a select list for the Medium Verbosity (2), which is the default. * @return String select columns, or "*", never null. * Example: "obs_id, release_date, ra, dec, footprint" */ - public abstract String getMidVerbositySelectList(); + public String getMidVerbositySelectList() { + return this.midVerbositySelectList; + } /** * Obtain a select list for the High Verbosity (3). * @return String select columns, or "*", never null. * Example: "*" */ - public abstract String getHighVerbositySelectList(); + public String getHighVerbositySelectList() { + return this.highVerbositySelectList; + } } diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConeSearchConfig.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConeSearchConfig.java index 10b2877f..fe61cbc0 100644 --- a/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConeSearchConfig.java +++ b/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConeSearchConfig.java @@ -148,6 +148,30 @@ public String getPositionColumnName() { return properties.getFirstPropertyValue(ConfigurationParameterNames.POSITION_COLUMN_NAME.getPropertyKey()); } + /** + * Obtain the configured select list for VERB=1. + * @return String comma-delimited column names (e.g. col_a, col_b, col_c). + */ + public String getLowVerbositySelectList() { + return properties.getFirstPropertyValue(ConfigurationParameterNames.LOW_VERBOSITY_SELECT_LIST.getPropertyKey()); + } + + /** + * Obtain the configured select list for VERB=2. + * @return String comma-delimited column names (e.g. col_a, col_b, col_c). + */ + public String getMidVerbositySelectList() { + return properties.getFirstPropertyValue(ConfigurationParameterNames.MID_VERBOSITY_SELECT_LIST.getPropertyKey()); + } + + /** + * Obtain the configured select list for VERB=3. + * @return String comma-delimited column names (e.g. *). + */ + public String getHighVerbositySelectList() { + return properties.getFirstPropertyValue(ConfigurationParameterNames.HIGH_VERBOSITY_SELECT_LIST.getPropertyKey()); + } + /** * Obtain the configured TAP URI. * @return String URI value. Never null. diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConfigurationParameterNames.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConfigurationParameterNames.java index de4fb5ec..5b21a12a 100644 --- a/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConfigurationParameterNames.java +++ b/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConfigurationParameterNames.java @@ -71,7 +71,10 @@ public enum ConfigurationParameterNames { CATALOG_NAME("catalogName"), TAP_URI("tapURI"), - POSITION_COLUMN_NAME("positionColumnName"); + POSITION_COLUMN_NAME("positionColumnName"), + LOW_VERBOSITY_SELECT_LIST("lowVerbositySelectList"), + MID_VERBOSITY_SELECT_LIST("midVerbositySelectList"), + HIGH_VERBOSITY_SELECT_LIST("highVerbositySelectList"); private final String propertyKey; diff --git a/cadc-conesearch/src/test/java/org/opencadc/conesearch/TAPQueryGeneratorTest.java b/cadc-conesearch/src/test/java/org/opencadc/conesearch/TAPQueryGeneratorTest.java index d6793dc5..8adc429f 100644 --- a/cadc-conesearch/src/test/java/org/opencadc/conesearch/TAPQueryGeneratorTest.java +++ b/cadc-conesearch/src/test/java/org/opencadc/conesearch/TAPQueryGeneratorTest.java @@ -80,7 +80,8 @@ public class TAPQueryGeneratorTest { @Test public void testInvalidJobParameters() { - final TAPQueryGenerator testSubject = new TestTAPQueryGenerator("badcat"); + final TAPQueryGenerator testSubject = new TAPQueryGenerator("badcat", "ra, dec", + "obs_id, release_date, ra, dec", "*"); final Map> parameters = new HashMap<>(); try { @@ -143,7 +144,8 @@ public void testInvalidJobParameters() { @Test public void testValidJobParameters() { - final TAPQueryGenerator testSubject = new TestTAPQueryGenerator("goodcat"); + final TAPQueryGenerator testSubject = new TAPQueryGenerator("goodcat", "ra, dec", + "obs_id, release_date, ra, dec", "*"); final Map> parameters = new HashMap<>(); parameters.put("RA", Collections.singletonList("12.3")); parameters.put("DEC", Collections.singletonList("45.6")); @@ -157,7 +159,7 @@ public void testValidJobParameters() { Assert.assertEquals("Wrong langauge", "ADQL", tapQueryParameters1.get("LANG")); Assert.assertEquals("Wrong query.", "SELECT obs_id, release_date, ra, dec " - + "FROM goodcat WHERE 1 = CONTAINS(point_col, CIRCLE(12.3, 45.6, 0.7))", + + "FROM goodcat WHERE 1 = CONTAINS(point_col, CIRCLE('ICRS', 12.3, 45.6, 0.7))", tapQueryParameters1.get("QUERY")); Assert.assertEquals("Wrong max records", 1000, tapQueryParameters1.get("MAXREC")); @@ -177,30 +179,8 @@ public void testValidJobParameters() { Assert.assertEquals("Wrong response format.", "tsv", tapQueryParameters2.get("RESPONSEFORMAT")); Assert.assertEquals("Wrong langauge", "ADQL", tapQueryParameters2.get("LANG")); Assert.assertEquals("Wrong query.", - "SELECT * FROM goodcat WHERE 1 = CONTAINS(point_col_2, CIRCLE(12.3, 45.6, 0.7))", + "SELECT * FROM goodcat WHERE 1 = CONTAINS(point_col_2, CIRCLE('ICRS', 12.3, 45.6, 0.7))", tapQueryParameters2.get("QUERY")); Assert.assertEquals("Wrong max records", 8000, tapQueryParameters2.get("MAXREC")); } - - public static final class TestTAPQueryGenerator extends TAPQueryGenerator { - - public TestTAPQueryGenerator(final String catalog) { - super(catalog); - } - - @Override - public String getLowVerbositySelectList() { - return "ra, dec"; - } - - @Override - public String getMidVerbositySelectList() { - return "obs_id, release_date, ra, dec"; - } - - @Override - public String getHighVerbositySelectList() { - return "*"; - } - } } From fa565be7b979b627a0f9a550950d95b4b109f3ef Mon Sep 17 00:00:00 2001 From: Dustin Jenkins Date: Tue, 26 Jul 2022 10:04:00 -0700 Subject: [PATCH 03/10] Hush the linter. --- .github/workflows/gradle.yml | 3 +++ .../java/org/opencadc/conesearch/TAPQueryGenerator.java | 9 +++++---- .../org/opencadc/conesearch/config/ConeSearchConfig.java | 9 +++++---- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 8e2e2905..e2ad5b2d 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -25,6 +25,9 @@ jobs: - name: build and test cadc-sia run: cd cadc-sia && ../gradlew --info clean build javadoc checkstyleMain install + + - name: build and test cadc-conesearch + run: cd cadc-conesearch && ../gradlew --info clean build javadoc checkstyleMain install - name: build and test cadc-datalink run: cd cadc-datalink && ../gradlew --info clean build javadoc checkstyleMain install diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java index 6478c861..929cb803 100644 --- a/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java +++ b/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java @@ -71,14 +71,15 @@ import ca.nrc.cadc.dali.Circle; import ca.nrc.cadc.dali.CommonParamValidator; import ca.nrc.cadc.dali.tables.votable.VOTableWriter; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + /** * Class to produce an ADQL query from a set of Parameters @@ -89,7 +90,7 @@ public class TAPQueryGenerator extends CommonParamValidator { private static final int MIN_VERB_VALUE = 1; private static final int MID_VERB_VALUE = 2; private static final int MAX_VERB_VALUE = 3; - private final static Logger LOGGER = LogManager.getLogger(TAPQueryGenerator.class); + private static final Logger LOGGER = LogManager.getLogger(TAPQueryGenerator.class); protected final String catalog; protected final String lowVerbositySelectList; @@ -213,7 +214,7 @@ private String getSelectList(final int outputVerbosity) { */ public String getLowVerbositySelectList() { return this.lowVerbositySelectList; - }; + } /** * Obtain a select list for the Medium Verbosity (2), which is the default. diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConeSearchConfig.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConeSearchConfig.java index fe61cbc0..8dcd7109 100644 --- a/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConeSearchConfig.java +++ b/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConeSearchConfig.java @@ -74,20 +74,21 @@ import ca.nrc.cadc.reg.client.RegistryClient; import ca.nrc.cadc.util.MultiValuedProperties; import ca.nrc.cadc.util.PropertiesReader; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + /** * Configuration of this web application. */ public class ConeSearchConfig { - private final static String CONFIG_FILE_NAME = "cadc-conesearch.properties"; - private final static Logger LOGGER = LogManager.getLogger(ConeSearchConfig.class); + private static final String CONFIG_FILE_NAME = "cadc-conesearch.properties"; + private static final Logger LOGGER = LogManager.getLogger(ConeSearchConfig.class); private final MultiValuedProperties properties; From c9a5efc94d02644f8637ff5bf076b229aa4ec814 Mon Sep 17 00:00:00 2001 From: Dustin Jenkins Date: Wed, 27 Jul 2022 10:47:43 -0700 Subject: [PATCH 04/10] Code review rework. Added CommonValidator methods as well. --- cadc-conesearch/README.md | 35 +--- cadc-conesearch/build.gradle | 2 +- ...dator.java => ConeParameterValidator.java} | 94 ++++----- .../conesearch/TAPQueryGenerator.java | 112 +++++------ .../conesearch/config/ConeSearchConfig.java | 183 ------------------ .../config/ConfigurationParameterNames.java | 88 --------- .../ConeParameterValidatorTest.java} | 38 +++- .../NumberParameterValidatorTest.java | 135 ------------- .../conesearch/TAPQueryGeneratorTest.java | 47 +++-- .../config/ConeSearchConfigTest.java | 73 ------- cadc-dali/build.gradle | 2 +- .../nrc/cadc/dali/CommonParamValidator.java | 44 +++++ .../cadc/dali/CommonParamValidatorTest.java | 53 +++++ 13 files changed, 258 insertions(+), 648 deletions(-) rename cadc-conesearch/src/main/java/org/opencadc/conesearch/{NumberParameterValidator.java => ConeParameterValidator.java} (60%) delete mode 100644 cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConeSearchConfig.java delete mode 100644 cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConfigurationParameterNames.java rename cadc-conesearch/src/{main/java/org/opencadc/conesearch/ParameterNames.java => test/java/org/opencadc/conesearch/ConeParameterValidatorTest.java} (79%) delete mode 100644 cadc-conesearch/src/test/java/org/opencadc/conesearch/NumberParameterValidatorTest.java delete mode 100644 cadc-conesearch/src/test/java/org/opencadc/conesearch/config/ConeSearchConfigTest.java diff --git a/cadc-conesearch/README.md b/cadc-conesearch/README.md index 4ede51a9..8c192385 100644 --- a/cadc-conesearch/README.md +++ b/cadc-conesearch/README.md @@ -1,4 +1,4 @@ -# cadc-conesearch (1.0.0) +# cadc-conesearch Library containing logic to help implementors support the [Simple Cone Search Working Draft (1.1)](https://www.ivoa.net/documents/ConeSearch/20200828/WD-ConeSearch-1.1-20200828.html). @@ -34,35 +34,4 @@ dependencies { } ``` -`${HOME}/config/cadc-conesearch.properties`: -```properties -tapURI = ivo://myhost.com/catalog_tap_service # Or an absolute URL e.g. https://myhost.com/mytap -positionColumnName = my_spatial_indexed_column # Used to compare to the Cone's Center position. Can also be a dynamic spatial object e.g. POINT('ICRS', RA_Source, DEC_Source) -lowVerbositySelectList = obs_id, ra, dec # Columns for VERB=1 -midVerbositySelectList = obs_id, ra, dec, s_region, frequency, bandwidth # Columns for VERB=2 -highVerbositySelectList = * # Columns for VERB=3 -``` - -Capture the Cone Search parameters and translate to ADQL to be sent to a TAP service. - -```java -final ConeSearchConfig coneSearchConfig = new ConeSearchConfig(); // Ensure the cadc-conesearch.properties exists. -final TAPQueryGenerator tapQueryGenerator = new TAPQueryGenerator("mycatalog", coneSearchConfig.getLowVerbositySelectList(), - coneSearchConfig.getMidVerbositySelectList(), - coneSearchConfig.getHighVerbositySelectList()); -// Create TAP parameters -final Map parameters = - tapQueryGenerator.getParameterMap(coneSearchConfig.getPositionColumnName(), - parameterExtractor.getParameters(job.getParameterList())); - -// Issue a Synchronous POST request to a TAP service. -final URL tapSyncURL = new URL(coneSearchConfig.getTapBaseURL().toExternalForm() + "/sync"); - -// POST ADQL query to TAP but do not follow redirect to execute it. -final HttpPost post = new HttpPost(tapSyncURL, parameters, false); -post.run(); - -// Do something with the data. -final URL redirectURL = post.getRedirectURL(); // In the case of a redirect -final InputStream inputStream = post.getInputStream(); // Read the data -``` +Implementors will want to use the `TAPQueryGenerator` class to create parameters that can be sent to a TAP service. diff --git a/cadc-conesearch/build.gradle b/cadc-conesearch/build.gradle index 704ab8e5..638e0e27 100644 --- a/cadc-conesearch/build.gradle +++ b/cadc-conesearch/build.gradle @@ -18,7 +18,7 @@ description = 'OpenCADC Simple Cone Search Java API' def git_url = 'https://github.com/opencadc/dal.git' dependencies { - implementation 'org.opencadc:cadc-dali:[1.2.4,2.0)' + implementation 'org.opencadc:cadc-dali:[1.2.17,2.0)' implementation 'org.opencadc:cadc-rest:[1.3.12,2.0)' implementation 'org.opencadc:cadc-util:[1.6.4,2.0)' implementation 'org.opencadc:cadc-vosi:[1.4.4,2.0)' diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/NumberParameterValidator.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/ConeParameterValidator.java similarity index 60% rename from cadc-conesearch/src/main/java/org/opencadc/conesearch/NumberParameterValidator.java rename to cadc-conesearch/src/main/java/org/opencadc/conesearch/ConeParameterValidator.java index 0c03edb9..6559ce60 100644 --- a/cadc-conesearch/src/main/java/org/opencadc/conesearch/NumberParameterValidator.java +++ b/cadc-conesearch/src/main/java/org/opencadc/conesearch/ConeParameterValidator.java @@ -68,60 +68,66 @@ package org.opencadc.conesearch; -import ca.nrc.cadc.util.StringUtil; +import ca.nrc.cadc.dali.Circle; +import ca.nrc.cadc.dali.CommonParamValidator; -public class NumberParameterValidator { - private final boolean capValue; - private final int minValue; - private final int maxValue; - private final int defaultValue; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +/** + * Validator for Cone Search parameters. + */ +public class ConeParameterValidator extends CommonParamValidator { + public static final String VERB_PARAM = "VERB"; + public static final String RA_PARAM = "RA"; + public static final String DEC_PARAM = "DEC"; + public static final String SR_PARAM = "SR"; + static final int MIN_VERB_VALUE = 1; + static final int MID_VERB_VALUE = 2; + static final int MAX_VERB_VALUE = 3; - /** - * Constructor. - * - * @param capValue Set to true to cap the upper value to the max - */ - public NumberParameterValidator(final boolean capValue, final int minValue, final int maxValue, - final int defaultValue) { - - if (minValue > maxValue) { - throw new IllegalArgumentException("Min value must be less than or equal to Max value."); - } else if (defaultValue > maxValue || defaultValue < minValue) { - throw new IllegalArgumentException("Default value does not fall between specified min and max values (" - + minValue + " and " + maxValue + ")."); - } + public Circle validateCone(final Map> parameters) { + final String raValue = getFirstParameter(ConeParameterValidator.RA_PARAM, parameters); + final String decValue = getFirstParameter(ConeParameterValidator.DEC_PARAM, parameters); + final String searchRadiusValue = getFirstParameter(ConeParameterValidator.SR_PARAM, parameters); + final Map> circleValidateParams = new HashMap<>(); + circleValidateParams.put(CommonParamValidator.CIRCLE, Collections.singletonList( + String.format("%s %s %s", raValue, decValue, searchRadiusValue))); - this.capValue = capValue; - this.minValue = minValue; - this.maxValue = maxValue; - this.defaultValue = defaultValue; - } + try { + final List validCircles = validateCircle(circleValidateParams); - public int validate(final String parameterNumberValue) { - final int integerValue; - if (StringUtil.hasText(parameterNumberValue)) { - try { - final int parsedValue = Integer.parseInt(parameterNumberValue); - if (parsedValue > maxValue && capValue) { - integerValue = maxValue; - } else if (parsedValue < minValue && capValue) { - integerValue = minValue; - } else { - integerValue = parsedValue; - } - } catch (NumberFormatException numberFormatException) { - throw new IllegalArgumentException("Cannot parse number value (not a valid number)"); + if (validCircles.isEmpty()) { + throw new IllegalArgumentException("No valid input cone position center provided."); + } else { + return validCircles.get(0); } + } catch (NumberFormatException numberFormatException) { + throw new IllegalArgumentException("Cannot create cone position center from non-numeric input."); + } + } - if (integerValue < minValue || integerValue > maxValue) { - throw new IllegalArgumentException( - "Input MUST be a value between " + minValue + " and " + maxValue + "."); + public int validateVERB(final Map> parameters) { + // If not VERB provided, default to 2. + if (parameters.containsKey(VERB_PARAM)) { + final List validIntegers = validateInteger(VERB_PARAM, parameters, Arrays.asList(MIN_VERB_VALUE, + MID_VERB_VALUE, + MAX_VERB_VALUE)); + if (validIntegers.isEmpty()) { + throw new IllegalArgumentException("VERB must be 1, 2, or 3."); + } else { + return validIntegers.get(0); } } else { - integerValue = defaultValue; + return MID_VERB_VALUE; } + } - return integerValue; + private String getFirstParameter(final String key, final Map> requestParameters) { + final List values = requestParameters.get(key); + return (values == null || values.isEmpty()) ? null : values.get(0); } } diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java index 929cb803..a4688832 100644 --- a/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java +++ b/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java @@ -69,14 +69,13 @@ package org.opencadc.conesearch; import ca.nrc.cadc.dali.Circle; -import ca.nrc.cadc.dali.CommonParamValidator; import ca.nrc.cadc.dali.tables.votable.VOTableWriter; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import ca.nrc.cadc.util.StringUtil; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -84,74 +83,86 @@ /** * Class to produce an ADQL query from a set of Parameters */ -public class TAPQueryGenerator extends CommonParamValidator { +public class TAPQueryGenerator { private static final int DEF_MAXREC = 1000; private static final int MAX_MAXREC = Integer.MAX_VALUE; - private static final int MIN_VERB_VALUE = 1; - private static final int MID_VERB_VALUE = 2; - private static final int MAX_VERB_VALUE = 3; private static final Logger LOGGER = LogManager.getLogger(TAPQueryGenerator.class); - protected final String catalog; + protected final String tableName; + protected final String positionColumnName; protected final String lowVerbositySelectList; protected final String midVerbositySelectList; protected final String highVerbositySelectList; + protected final Map> parameters; - public TAPQueryGenerator(final String catalog, final String lowVerbositySelectList, - final String midVerbositySelectList, final String highVerbositySelectList) { - this.catalog = catalog; + + /** + * + * @param tableName The name of the Catalog Table to query. + * @param positionColumnName The name of the positional column to compare against the cone's position, + * preferably spatially indexed.@param positionColumnName + * @param lowVerbositySelectList The query select list for VERB=1 + * @param midVerbositySelectList The query select list for VERB=2 + * @param highVerbositySelectList The query select list for VERB=3 + */ + public TAPQueryGenerator(final String tableName, final String positionColumnName, + final String lowVerbositySelectList, final String midVerbositySelectList, + final String highVerbositySelectList, final Map> parameters) { + if (!StringUtil.hasText(tableName) || !StringUtil.hasText(positionColumnName) + || !StringUtil.hasText(lowVerbositySelectList) || !StringUtil.hasText(midVerbositySelectList) + || !StringUtil.hasText(highVerbositySelectList) || parameters == null || parameters.isEmpty()) { + throw new IllegalArgumentException("tableName, positionColumnName, lowVerbositySelectList, " + + "midVerbositySelectList, highVerbositySelectList, and parameters " + + "are all required.\n" + + "(" + tableName + ", " + positionColumnName + ", " + + lowVerbositySelectList + ", " + midVerbositySelectList + ", " + + highVerbositySelectList + ", " + parameters + ")"); + } + + this.tableName = tableName; + this.positionColumnName = positionColumnName; this.lowVerbositySelectList = lowVerbositySelectList; this.midVerbositySelectList = midVerbositySelectList; this.highVerbositySelectList = highVerbositySelectList; + this.parameters = parameters; } /** - * Map with the REQUEST, LANG, and QUERY parameters. + * Map with supported Simple Cone Search 1.1 parameters. + * ... * - * @param positionColumnName The name of the positional column to compare against the cone's position, - * preferably spatially indexed. * @return map of parameter names and values */ - public Map getParameterMap(final String positionColumnName, - final Map> parameters) { + public Map getParameterMap() { final Map queryParameterMap = new HashMap<>(); + final ConeParameterValidator coneParameterValidator = new ConeParameterValidator(); // Obtain and, if necessary, provide a default RESPONSEFORMAT. - final String requestedResponseFormat = getFirstParameter(ParameterNames.RESPONSEFORMAT.name(), parameters, - VOTableWriter.CONTENT_TYPE); - queryParameterMap.put(ParameterNames.RESPONSEFORMAT.name(), requestedResponseFormat); + queryParameterMap.put(ConeParameterValidator.RESPONSEFORMAT, + coneParameterValidator.getResponseFormat(parameters, VOTableWriter.CONTENT_TYPE)); // Obtain and validate the VERB (verbosity) output. - final String requestedOutputVerbosity = getFirstParameter(ParameterNames.VERB.name(), parameters, - Integer.toString(MID_VERB_VALUE)); - final NumberParameterValidator outputVerbosityValidator = - new NumberParameterValidator(false, TAPQueryGenerator.MIN_VERB_VALUE, - TAPQueryGenerator.MAX_VERB_VALUE, TAPQueryGenerator.MID_VERB_VALUE); - final int outputVerbosity = outputVerbosityValidator.validate(requestedOutputVerbosity); + final int outputVerbosity = coneParameterValidator.validateVERB(parameters); // Obtain and validate the MAXREC value with a default if necessary. - final String requestedMaxRecords = getFirstParameter(ParameterNames.MAXREC.name(), parameters, - Integer.toString(TAPQueryGenerator.DEF_MAXREC)); - final NumberParameterValidator maxRecordsValidator = - new NumberParameterValidator(true, 0, TAPQueryGenerator.MAX_MAXREC, - TAPQueryGenerator.DEF_MAXREC); - final int maxRecordCount = maxRecordsValidator.validate(requestedMaxRecords); - queryParameterMap.put(ParameterNames.MAXREC.name(), maxRecordCount); + final int maxRecordCount = coneParameterValidator.getMaxRec(parameters, TAPQueryGenerator.DEF_MAXREC, + TAPQueryGenerator.MAX_MAXREC); + queryParameterMap.put(ConeParameterValidator.MAXREC, maxRecordCount); queryParameterMap.put("LANG", "ADQL"); - final String query = getQuery(positionColumnName, outputVerbosity, validateConePositionCenter(parameters)); + final String query = getQuery(outputVerbosity, coneParameterValidator.validateCone(parameters)); LOGGER.debug("Cone Search TAP query:\n" + query); queryParameterMap.put("QUERY", query); return queryParameterMap; } - private String getQuery(final String positionColumnName, final int outputVerbosity, final Circle circle) { + private String getQuery(final int outputVerbosity, final Circle circle) { return "SELECT " + getSelectList(outputVerbosity) + " FROM " - + this.catalog + + this.tableName + " WHERE 1 = CONTAINS(" - + positionColumnName + + this.positionColumnName + ", " + "CIRCLE('ICRS', " + circle.getCenter().getLongitude() @@ -162,41 +173,14 @@ private String getQuery(final String positionColumnName, final int outputVerbosi + "))"; } - private String getFirstParameter(final String key, final Map> requestParameters, - final String defaultValue) { - final List values = requestParameters.get(key); - return (values == null || values.isEmpty()) ? defaultValue : values.get(0); - } - - private Circle validateConePositionCenter(final Map> requestParameters) { - final String raValue = getFirstParameter(ParameterNames.RA.name(), requestParameters, null); - final String decValue = getFirstParameter(ParameterNames.DEC.name(), requestParameters, null); - final String searchRadiusValue = getFirstParameter(ParameterNames.SR.name(), requestParameters, null); - final Map> circleValidateParams = new HashMap<>(); - circleValidateParams.put(CommonParamValidator.CIRCLE, Collections.singletonList( - String.format("%s %s %s", raValue, decValue, searchRadiusValue))); - - try { - final List validCircles = super.validateCircle(circleValidateParams); - - if (validCircles.isEmpty()) { - throw new IllegalArgumentException("No valid input cone position center provided."); - } else { - return validCircles.get(0); - } - } catch (NumberFormatException numberFormatException) { - throw new IllegalArgumentException("Cannot create cone position center from non-numeric input."); - } - } - private String getSelectList(final int outputVerbosity) { switch (outputVerbosity) { - case TAPQueryGenerator.MIN_VERB_VALUE: { + case ConeParameterValidator.MIN_VERB_VALUE: { return getLowVerbositySelectList(); } - case TAPQueryGenerator.MAX_VERB_VALUE: { + case ConeParameterValidator.MAX_VERB_VALUE: { return getHighVerbositySelectList(); } diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConeSearchConfig.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConeSearchConfig.java deleted file mode 100644 index 8dcd7109..00000000 --- a/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConeSearchConfig.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - ************************************************************************ - ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* - ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** - * - * (c) 2022. (c) 2022. - * Government of Canada Gouvernement du Canada - * National Research Council Conseil national de recherches - * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 - * All rights reserved Tous droits réservés - * - * NRC disclaims any warranties, Le CNRC dénie toute garantie - * expressed, implied, or énoncée, implicite ou légale, - * statutory, of any kind with de quelque nature que ce - * respect to the software, soit, concernant le logiciel, - * including without limitation y compris sans restriction - * any warranty of merchantability toute garantie de valeur - * or fitness for a particular marchande ou de pertinence - * purpose. NRC shall not be pour un usage particulier. - * liable in any event for any Le CNRC ne pourra en aucun cas - * damages, whether direct or être tenu responsable de tout - * indirect, special or general, dommage, direct ou indirect, - * consequential or incidental, particulier ou général, - * arising from the use of the accessoire ou fortuit, résultant - * software. Neither the name de l'utilisation du logiciel. Ni - * of the National Research le nom du Conseil National de - * Council of Canada nor the Recherches du Canada ni les noms - * names of its contributors may de ses participants ne peuvent - * be used to endorse or promote être utilisés pour approuver ou - * products derived from this promouvoir les produits dérivés - * software without specific prior de ce logiciel sans autorisation - * written permission. préalable et particulière - * par écrit. - * - * This file is part of the Ce fichier fait partie du projet - * OpenCADC project. OpenCADC. - * - * OpenCADC is free software: OpenCADC est un logiciel libre ; - * you can redistribute it and/or vous pouvez le redistribuer ou le - * modify it under the terms of modifier suivant les termes de - * the GNU Affero General Public la “GNU Affero General Public - * License as published by the License” telle que publiée - * Free Software Foundation, par la Free Software Foundation - * either version 3 of the : soit la version 3 de cette - * License, or (at your option) licence, soit (à votre gré) - * any later version. toute version ultérieure. - * - * OpenCADC is distributed in the OpenCADC est distribué - * hope that it will be useful, dans l’espoir qu’il vous - * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE - * without even the implied GARANTIE : sans même la garantie - * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ - * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF - * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence - * General Public License for Générale Publique GNU Affero - * more details. pour plus de détails. - * - * You should have received Vous devriez avoir reçu une - * a copy of the GNU Affero copie de la Licence Générale - * General Public License along Publique GNU Affero avec - * with OpenCADC. If not, see OpenCADC ; si ce n’est - * . pas le cas, consultez : - * . - * - * - ************************************************************************ - */ - -package org.opencadc.conesearch.config; - -import ca.nrc.cadc.auth.AuthMethod; -import ca.nrc.cadc.auth.AuthenticationUtil; -import ca.nrc.cadc.reg.Standards; -import ca.nrc.cadc.reg.client.RegistryClient; -import ca.nrc.cadc.util.MultiValuedProperties; -import ca.nrc.cadc.util.PropertiesReader; - -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URL; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - - -/** - * Configuration of this web application. - */ -public class ConeSearchConfig { - private static final String CONFIG_FILE_NAME = "cadc-conesearch.properties"; - private static final Logger LOGGER = LogManager.getLogger(ConeSearchConfig.class); - - private final MultiValuedProperties properties; - - - public ConeSearchConfig() { - this(new PropertiesReader(ConeSearchConfig.CONFIG_FILE_NAME)); - } - - /** - * Complete constructor. - * @param propertiesReader A reader on the configuration file. - * - * @throws IllegalArgumentException If the configuration file cannot be read. - */ - ConeSearchConfig(final PropertiesReader propertiesReader) { - if (propertiesReader.canRead()) { - this.properties = propertiesReader.getAllProperties(); - - if (this.properties == null) { - throw new IllegalArgumentException("No configuration in " + ConeSearchConfig.CONFIG_FILE_NAME); - } else { - LOGGER.debug("Configuration load: OK"); - this.properties.keySet().forEach(k -> LOGGER.debug(k + " -> " + this.properties.getProperty(k))); - } - } else { - throw new IllegalArgumentException("Unable to read " + ConeSearchConfig.CONFIG_FILE_NAME); - } - } - - /** - * Obtain the base TAP URL to use. This method will read in an optionally configured 'tapURI' property and if it - * appears to be a URL, then assume an unregistered TAP service was configured and treat it as the base URL, - * otherwise attempt to use it as a URI and look the URL up in the Registry. - * - * @return URL Base URL of the TAP service to use. - * - * @throws MalformedURLException If a URL cannot be created from the specified string. - */ - public URL getTapBaseURL() throws MalformedURLException { - final URI configuredTapURI = URI.create(getTapURI()); - - final AuthMethod am = AuthenticationUtil.getAuthMethod(AuthenticationUtil.getCurrentSubject()); - if (configuredTapURI.getScheme().equals("ivo")) { - final RegistryClient regClient = new RegistryClient(); - // Attempt to load the URI as a resource URI from the Registry. - return regClient.getServiceURL(configuredTapURI, Standards.TAP_10, (am == null) ? AuthMethod.ANON : am); - } else { - // Fallback and assume the URI is an absolute URL. - return configuredTapURI.toURL(); - } - } - - /** - * Obtain the (ideally) spatially indexed column name to compare the center of the cone's position to. - * @return String column name. - */ - public String getPositionColumnName() { - return properties.getFirstPropertyValue(ConfigurationParameterNames.POSITION_COLUMN_NAME.getPropertyKey()); - } - - /** - * Obtain the configured select list for VERB=1. - * @return String comma-delimited column names (e.g. col_a, col_b, col_c). - */ - public String getLowVerbositySelectList() { - return properties.getFirstPropertyValue(ConfigurationParameterNames.LOW_VERBOSITY_SELECT_LIST.getPropertyKey()); - } - - /** - * Obtain the configured select list for VERB=2. - * @return String comma-delimited column names (e.g. col_a, col_b, col_c). - */ - public String getMidVerbositySelectList() { - return properties.getFirstPropertyValue(ConfigurationParameterNames.MID_VERBOSITY_SELECT_LIST.getPropertyKey()); - } - - /** - * Obtain the configured select list for VERB=3. - * @return String comma-delimited column names (e.g. *). - */ - public String getHighVerbositySelectList() { - return properties.getFirstPropertyValue(ConfigurationParameterNames.HIGH_VERBOSITY_SELECT_LIST.getPropertyKey()); - } - - /** - * Obtain the configured TAP URI. - * @return String URI value. Never null. - */ - String getTapURI() { - return properties.getFirstPropertyValue(ConfigurationParameterNames.TAP_URI.getPropertyKey()); - } -} diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConfigurationParameterNames.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConfigurationParameterNames.java deleted file mode 100644 index 5b21a12a..00000000 --- a/cadc-conesearch/src/main/java/org/opencadc/conesearch/config/ConfigurationParameterNames.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - ************************************************************************ - ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* - ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** - * - * (c) 2022. (c) 2022. - * Government of Canada Gouvernement du Canada - * National Research Council Conseil national de recherches - * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 - * All rights reserved Tous droits réservés - * - * NRC disclaims any warranties, Le CNRC dénie toute garantie - * expressed, implied, or énoncée, implicite ou légale, - * statutory, of any kind with de quelque nature que ce - * respect to the software, soit, concernant le logiciel, - * including without limitation y compris sans restriction - * any warranty of merchantability toute garantie de valeur - * or fitness for a particular marchande ou de pertinence - * purpose. NRC shall not be pour un usage particulier. - * liable in any event for any Le CNRC ne pourra en aucun cas - * damages, whether direct or être tenu responsable de tout - * indirect, special or general, dommage, direct ou indirect, - * consequential or incidental, particulier ou général, - * arising from the use of the accessoire ou fortuit, résultant - * software. Neither the name de l'utilisation du logiciel. Ni - * of the National Research le nom du Conseil National de - * Council of Canada nor the Recherches du Canada ni les noms - * names of its contributors may de ses participants ne peuvent - * be used to endorse or promote être utilisés pour approuver ou - * products derived from this promouvoir les produits dérivés - * software without specific prior de ce logiciel sans autorisation - * written permission. préalable et particulière - * par écrit. - * - * This file is part of the Ce fichier fait partie du projet - * OpenCADC project. OpenCADC. - * - * OpenCADC is free software: OpenCADC est un logiciel libre ; - * you can redistribute it and/or vous pouvez le redistribuer ou le - * modify it under the terms of modifier suivant les termes de - * the GNU Affero General Public la “GNU Affero General Public - * License as published by the License” telle que publiée - * Free Software Foundation, par la Free Software Foundation - * either version 3 of the : soit la version 3 de cette - * License, or (at your option) licence, soit (à votre gré) - * any later version. toute version ultérieure. - * - * OpenCADC is distributed in the OpenCADC est distribué - * hope that it will be useful, dans l’espoir qu’il vous - * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE - * without even the implied GARANTIE : sans même la garantie - * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ - * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF - * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence - * General Public License for Générale Publique GNU Affero - * more details. pour plus de détails. - * - * You should have received Vous devriez avoir reçu une - * a copy of the GNU Affero copie de la Licence Générale - * General Public License along Publique GNU Affero avec - * with OpenCADC. If not, see OpenCADC ; si ce n’est - * . pas le cas, consultez : - * . - * - * - ************************************************************************ - */ - -package org.opencadc.conesearch.config; - -public enum ConfigurationParameterNames { - CATALOG_NAME("catalogName"), - TAP_URI("tapURI"), - POSITION_COLUMN_NAME("positionColumnName"), - LOW_VERBOSITY_SELECT_LIST("lowVerbositySelectList"), - MID_VERBOSITY_SELECT_LIST("midVerbositySelectList"), - HIGH_VERBOSITY_SELECT_LIST("highVerbositySelectList"); - - private final String propertyKey; - - ConfigurationParameterNames(final String propertyKey) { - this.propertyKey = propertyKey; - } - - public String getPropertyKey() { - return propertyKey; - } -} diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/ParameterNames.java b/cadc-conesearch/src/test/java/org/opencadc/conesearch/ConeParameterValidatorTest.java similarity index 79% rename from cadc-conesearch/src/main/java/org/opencadc/conesearch/ParameterNames.java rename to cadc-conesearch/src/test/java/org/opencadc/conesearch/ConeParameterValidatorTest.java index 6728555a..4b3a05aa 100644 --- a/cadc-conesearch/src/main/java/org/opencadc/conesearch/ParameterNames.java +++ b/cadc-conesearch/src/test/java/org/opencadc/conesearch/ConeParameterValidatorTest.java @@ -68,17 +68,37 @@ package org.opencadc.conesearch; -public enum ParameterNames { - DEC(true), RA(true), SR(true), - MAXREC(false), RESPONSEFORMAT(false), TIME(false), VERB(false); +import org.junit.Assert; +import org.junit.Test; - private final boolean required; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; - ParameterNames(final boolean required) { - this.required = required; - } - public boolean isRequired() { - return required; +/** + * Test cone parameter validation. The validateCone() is tested in TAPQueryGeneratorTest. + */ +public class ConeParameterValidatorTest { + @Test + public void testValidateVerb() { + final ConeParameterValidator testSubject = new ConeParameterValidator(); + final Map> parameters = new HashMap<>(); + + Assert.assertEquals("Should be set to 2", 2, testSubject.validateVERB(parameters)); + + parameters.clear(); + parameters.put("VERB", Collections.singletonList("1")); + Assert.assertEquals("Should be set to 1", 1, testSubject.validateVERB(parameters)); + + parameters.clear(); + parameters.put("VERB", Collections.singletonList("6")); + try { + testSubject.validateVERB(parameters); + Assert.fail("6 is not a valid VERB."); + } catch (IllegalArgumentException illegalArgumentException) { + // Good + } } } diff --git a/cadc-conesearch/src/test/java/org/opencadc/conesearch/NumberParameterValidatorTest.java b/cadc-conesearch/src/test/java/org/opencadc/conesearch/NumberParameterValidatorTest.java deleted file mode 100644 index 4d40b233..00000000 --- a/cadc-conesearch/src/test/java/org/opencadc/conesearch/NumberParameterValidatorTest.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - ************************************************************************ - ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* - ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** - * - * (c) 2022. (c) 2022. - * Government of Canada Gouvernement du Canada - * National Research Council Conseil national de recherches - * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 - * All rights reserved Tous droits réservés - * - * NRC disclaims any warranties, Le CNRC dénie toute garantie - * expressed, implied, or énoncée, implicite ou légale, - * statutory, of any kind with de quelque nature que ce - * respect to the software, soit, concernant le logiciel, - * including without limitation y compris sans restriction - * any warranty of merchantability toute garantie de valeur - * or fitness for a particular marchande ou de pertinence - * purpose. NRC shall not be pour un usage particulier. - * liable in any event for any Le CNRC ne pourra en aucun cas - * damages, whether direct or être tenu responsable de tout - * indirect, special or general, dommage, direct ou indirect, - * consequential or incidental, particulier ou général, - * arising from the use of the accessoire ou fortuit, résultant - * software. Neither the name de l'utilisation du logiciel. Ni - * of the National Research le nom du Conseil National de - * Council of Canada nor the Recherches du Canada ni les noms - * names of its contributors may de ses participants ne peuvent - * be used to endorse or promote être utilisés pour approuver ou - * products derived from this promouvoir les produits dérivés - * software without specific prior de ce logiciel sans autorisation - * written permission. préalable et particulière - * par écrit. - * - * This file is part of the Ce fichier fait partie du projet - * OpenCADC project. OpenCADC. - * - * OpenCADC is free software: OpenCADC est un logiciel libre ; - * you can redistribute it and/or vous pouvez le redistribuer ou le - * modify it under the terms of modifier suivant les termes de - * the GNU Affero General Public la “GNU Affero General Public - * License as published by the License” telle que publiée - * Free Software Foundation, par la Free Software Foundation - * either version 3 of the : soit la version 3 de cette - * License, or (at your option) licence, soit (à votre gré) - * any later version. toute version ultérieure. - * - * OpenCADC is distributed in the OpenCADC est distribué - * hope that it will be useful, dans l’espoir qu’il vous - * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE - * without even the implied GARANTIE : sans même la garantie - * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ - * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF - * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence - * General Public License for Générale Publique GNU Affero - * more details. pour plus de détails. - * - * You should have received Vous devriez avoir reçu une - * a copy of the GNU Affero copie de la Licence Générale - * General Public License along Publique GNU Affero avec - * with OpenCADC. If not, see OpenCADC ; si ce n’est - * . pas le cas, consultez : - * . - * - * - ************************************************************************ - */ - -package org.opencadc.conesearch; - -import org.junit.Assert; -import org.junit.Test; - - -public class NumberParameterValidatorTest { - @Test - public void testConstructor() { - try { - new NumberParameterValidator(false, 6, 1, 0); - Assert.fail("Should throw IllegalArgumentException."); - } catch (IllegalArgumentException illegalArgumentException) { - // Good! - } - - try { - new NumberParameterValidator(false, 1, 6, 0); - Assert.fail("Should throw IllegalArgumentException for default being lower than minimum."); - } catch (IllegalArgumentException illegalArgumentException) { - // Good! - } - - try { - new NumberParameterValidator(false, 1, 6, 10); - Assert.fail("Should throw IllegalArgumentException for default being higher than maximum."); - } catch (IllegalArgumentException illegalArgumentException) { - // Good! - } - } - - @Test - public void testInputNoCap() { - final NumberParameterValidator testSubject = new NumberParameterValidator(false, 1, 6, 1); - - Assert.assertEquals("Should be set to 2", 2, testSubject.validate("2")); - Assert.assertEquals("Should be set to 1", 1, testSubject.validate("1")); - Assert.assertEquals("Should be set to 6", 6, testSubject.validate("6")); - Assert.assertEquals("Should default to 0", 1, testSubject.validate(null)); - - try { - testSubject.validate("-1"); - Assert.fail("Should throw IllegalArgumentException."); - } catch (IllegalArgumentException illegalArgumentException) { - // Good! - } - - try { - testSubject.validate("9"); - Assert.fail("Should throw IllegalArgumentException."); - } catch (IllegalArgumentException illegalArgumentException) { - // Good! - } - } - - @Test - public void testInputWithCap() { - final NumberParameterValidator testSubject = new NumberParameterValidator(true, 1, 6, 1); - - Assert.assertEquals("Should be set to 2", 2, testSubject.validate("2")); - Assert.assertEquals("Should be set to 1", 1, testSubject.validate("1")); - Assert.assertEquals("Should be set to 6", 6, testSubject.validate("6")); - Assert.assertEquals("Should default to 0", 1, testSubject.validate(null)); - Assert.assertEquals("Should default to 6", 6, testSubject.validate("9")); - Assert.assertEquals("Should default to 1", 1, testSubject.validate("0")); - } -} diff --git a/cadc-conesearch/src/test/java/org/opencadc/conesearch/TAPQueryGeneratorTest.java b/cadc-conesearch/src/test/java/org/opencadc/conesearch/TAPQueryGeneratorTest.java index 8adc429f..ca6f057f 100644 --- a/cadc-conesearch/src/test/java/org/opencadc/conesearch/TAPQueryGeneratorTest.java +++ b/cadc-conesearch/src/test/java/org/opencadc/conesearch/TAPQueryGeneratorTest.java @@ -80,12 +80,12 @@ public class TAPQueryGeneratorTest { @Test public void testInvalidJobParameters() { - final TAPQueryGenerator testSubject = new TAPQueryGenerator("badcat", "ra, dec", - "obs_id, release_date, ra, dec", "*"); final Map> parameters = new HashMap<>(); try { - testSubject.getParameterMap("my_point", parameters); + new TAPQueryGenerator("badcat", "my_point", "ra, dec", + "obs_id, release_date, ra, dec", "*", + parameters); Assert.fail("Should throw IllegalArgumentException here."); } catch (IllegalArgumentException illegalArgumentException) { // Good @@ -96,7 +96,10 @@ public void testInvalidJobParameters() { parameters.put("SR", Collections.singletonList("bogus")); try { - testSubject.getParameterMap("my_point_2", parameters); + final TAPQueryGenerator testSubject2 = new TAPQueryGenerator("badcat", "my_point", "ra, dec", + "obs_id, release_date, ra, dec", "*", + parameters); + testSubject2.getParameterMap(); Assert.fail("Should throw IllegalArgumentException here."); } catch (IllegalArgumentException illegalArgumentException) { // Good @@ -109,7 +112,10 @@ public void testInvalidJobParameters() { parameters.put("VERB", Collections.singletonList("9")); try { - testSubject.getParameterMap("my_point_3", parameters); + final TAPQueryGenerator testSubject3 = new TAPQueryGenerator("badcat", "my_point", "ra, dec", + "obs_id, release_date, ra, dec", "*", + parameters); + testSubject3.getParameterMap(); Assert.fail("Should throw IllegalArgumentException here for VERB."); } catch (IllegalArgumentException illegalArgumentException) { // Good @@ -122,7 +128,10 @@ public void testInvalidJobParameters() { parameters.put("VERB", Collections.singletonList("bogus")); try { - testSubject.getParameterMap("my_point_4", parameters); + final TAPQueryGenerator testSubject4 = new TAPQueryGenerator("badcat", "my_point", "ra, dec", + "obs_id, release_date, ra, dec", "*", + parameters); + testSubject4.getParameterMap(); Assert.fail("Should throw IllegalArgumentException here for VERB."); } catch (IllegalArgumentException illegalArgumentException) { // Good @@ -135,7 +144,10 @@ public void testInvalidJobParameters() { parameters.put("VERB", Collections.singletonList("1")); try { - testSubject.getParameterMap("my_point_5", parameters); + final TAPQueryGenerator testSubject5 = new TAPQueryGenerator("badcat", "my_point", "ra, dec", + "obs_id, release_date, ra, dec", "*", + parameters); + testSubject5.getParameterMap(); Assert.fail("Should throw IllegalArgumentException here for invalid circle."); } catch (IllegalArgumentException illegalArgumentException) { // Good (invalid circle) @@ -143,20 +155,20 @@ public void testInvalidJobParameters() { } @Test - public void testValidJobParameters() { - final TAPQueryGenerator testSubject = new TAPQueryGenerator("goodcat", "ra, dec", - "obs_id, release_date, ra, dec", "*"); + public void testValidParameters() { final Map> parameters = new HashMap<>(); parameters.put("RA", Collections.singletonList("12.3")); parameters.put("DEC", Collections.singletonList("45.6")); parameters.put("SR", Collections.singletonList("0.7")); - - final Map tapQueryParameters1 = testSubject.getParameterMap("point_col", - parameters); + final TAPQueryGenerator testSubject = new TAPQueryGenerator("goodcat", "point_col", "ra, dec", + "obs_id, release_date, ra, dec", "*", + parameters); + + final Map tapQueryParameters1 = testSubject.getParameterMap(); Assert.assertEquals("Wrong response format.", VOTableWriter.CONTENT_TYPE, tapQueryParameters1.get("RESPONSEFORMAT")); - Assert.assertEquals("Wrong langauge", "ADQL", tapQueryParameters1.get("LANG")); + Assert.assertEquals("Wrong language", "ADQL", tapQueryParameters1.get("LANG")); Assert.assertEquals("Wrong query.", "SELECT obs_id, release_date, ra, dec " + "FROM goodcat WHERE 1 = CONTAINS(point_col, CIRCLE('ICRS', 12.3, 45.6, 0.7))", @@ -172,10 +184,11 @@ public void testValidJobParameters() { parameters.put("RESPONSEFORMAT", Collections.singletonList("tsv")); parameters.put("MAXREC", Collections.singletonList("8000")); parameters.put("VERB", Collections.singletonList("3")); - - final Map tapQueryParameters2 = testSubject.getParameterMap("point_col_2", - parameters); + final TAPQueryGenerator testSubject2 = new TAPQueryGenerator("goodcat", "point_col_2", "ra, dec", + "obs_id, release_date, ra, dec", "*", + parameters); + final Map tapQueryParameters2 = testSubject2.getParameterMap(); Assert.assertEquals("Wrong response format.", "tsv", tapQueryParameters2.get("RESPONSEFORMAT")); Assert.assertEquals("Wrong langauge", "ADQL", tapQueryParameters2.get("LANG")); Assert.assertEquals("Wrong query.", diff --git a/cadc-conesearch/src/test/java/org/opencadc/conesearch/config/ConeSearchConfigTest.java b/cadc-conesearch/src/test/java/org/opencadc/conesearch/config/ConeSearchConfigTest.java deleted file mode 100644 index a892499d..00000000 --- a/cadc-conesearch/src/test/java/org/opencadc/conesearch/config/ConeSearchConfigTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - ************************************************************************ - ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* - ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** - * - * (c) 2022. (c) 2022. - * Government of Canada Gouvernement du Canada - * National Research Council Conseil national de recherches - * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 - * All rights reserved Tous droits réservés - * - * NRC disclaims any warranties, Le CNRC dénie toute garantie - * expressed, implied, or énoncée, implicite ou légale, - * statutory, of any kind with de quelque nature que ce - * respect to the software, soit, concernant le logiciel, - * including without limitation y compris sans restriction - * any warranty of merchantability toute garantie de valeur - * or fitness for a particular marchande ou de pertinence - * purpose. NRC shall not be pour un usage particulier. - * liable in any event for any Le CNRC ne pourra en aucun cas - * damages, whether direct or être tenu responsable de tout - * indirect, special or general, dommage, direct ou indirect, - * consequential or incidental, particulier ou général, - * arising from the use of the accessoire ou fortuit, résultant - * software. Neither the name de l'utilisation du logiciel. Ni - * of the National Research le nom du Conseil National de - * Council of Canada nor the Recherches du Canada ni les noms - * names of its contributors may de ses participants ne peuvent - * be used to endorse or promote être utilisés pour approuver ou - * products derived from this promouvoir les produits dérivés - * software without specific prior de ce logiciel sans autorisation - * written permission. préalable et particulière - * par écrit. - * - * This file is part of the Ce fichier fait partie du projet - * OpenCADC project. OpenCADC. - * - * OpenCADC is free software: OpenCADC est un logiciel libre ; - * you can redistribute it and/or vous pouvez le redistribuer ou le - * modify it under the terms of modifier suivant les termes de - * the GNU Affero General Public la “GNU Affero General Public - * License as published by the License” telle que publiée - * Free Software Foundation, par la Free Software Foundation - * either version 3 of the : soit la version 3 de cette - * License, or (at your option) licence, soit (à votre gré) - * any later version. toute version ultérieure. - * - * OpenCADC is distributed in the OpenCADC est distribué - * hope that it will be useful, dans l’espoir qu’il vous - * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE - * without even the implied GARANTIE : sans même la garantie - * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ - * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF - * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence - * General Public License for Générale Publique GNU Affero - * more details. pour plus de détails. - * - * You should have received Vous devriez avoir reçu une - * a copy of the GNU Affero copie de la Licence Générale - * General Public License along Publique GNU Affero avec - * with OpenCADC. If not, see OpenCADC ; si ce n’est - * . pas le cas, consultez : - * . - * - * - ************************************************************************ - */ - -package org.opencadc.conesearch.config; - -public class ConeSearchConfigTest { - -} diff --git a/cadc-dali/build.gradle b/cadc-dali/build.gradle index 99d366be..220822cd 100644 --- a/cadc-dali/build.gradle +++ b/cadc-dali/build.gradle @@ -14,7 +14,7 @@ sourceCompatibility = 1.8 group = 'org.opencadc' -version = '1.2.16' +version = '1.2.17' description = 'OpenCADC DALI library' def git_url = 'https://github.com/opencadc/dal' diff --git a/cadc-dali/src/main/java/ca/nrc/cadc/dali/CommonParamValidator.java b/cadc-dali/src/main/java/ca/nrc/cadc/dali/CommonParamValidator.java index a194a06f..07423028 100644 --- a/cadc-dali/src/main/java/ca/nrc/cadc/dali/CommonParamValidator.java +++ b/cadc-dali/src/main/java/ca/nrc/cadc/dali/CommonParamValidator.java @@ -79,6 +79,8 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.stream.Collectors; + import org.apache.log4j.Logger; /** @@ -92,6 +94,8 @@ public class CommonParamValidator { // DALI params public static final String RUNID = "RUNID"; public static final String RESPONSEFORMAT = "RESPONSEFORMAT"; + + public static final String MAXREC = "MAXREC"; // common params public static final String POS = "POS"; @@ -137,6 +141,33 @@ public String getResponseFormat(Map> params) { return values.get(0); } + public String getResponseFormat(Map> params, String defaultResponseFormat) { + final String providedResponseFormat = getResponseFormat(params); + return providedResponseFormat == null ? defaultResponseFormat : providedResponseFormat; + } + + /** + * Obtain the requested MAXREC value, or an optional default if provided. This value will be capped at the + * provided maxValue. + * @param params The parameters to pull the value from. + * @param defaultValue The default value to provide if nothing provided. + * @param maxValue The maximum value allowed. + * @return Max records count allowed, or default, or max value, or null. + */ + public Integer getMaxRec(Map> params, Integer defaultValue, Integer maxValue) { + final List validMaxRecs = validateInteger(MAXREC, params); + if (validMaxRecs.isEmpty()) { + return defaultValue; + } else { + final Integer maxRecValue = validMaxRecs.get(0); + if (maxRecValue > maxValue) { + return maxValue; + } else { + return maxRecValue; + } + } + } + private String scalarToInterval(String s) { String[] ss = s.split(" "); if (ss.length == 1) { @@ -304,6 +335,19 @@ public List validateString(String paramName, Map> p return ret; } + /** + * Validate an integer parameter against allowed set of values. + * @param paramName The parameter to look up in the params. + * @param params The map of Request parameters. + * @param allowedValues The values that are permitted. + * @return List of Integer objects, or empty List. Never null. + */ + public List validateInteger(String paramName, Map> params, + Collection allowedValues) { + final List parsedValues = this.validateInteger(paramName, params); + return parsedValues.stream().filter(allowedValues::contains).collect(Collectors.toList()); + } + public List validateInteger(String paramName, Map> params) { List ret = new ArrayList(); if (params == null) { diff --git a/cadc-dali/src/test/java/ca/nrc/cadc/dali/CommonParamValidatorTest.java b/cadc-dali/src/test/java/ca/nrc/cadc/dali/CommonParamValidatorTest.java index 00f32670..20c4414c 100644 --- a/cadc-dali/src/test/java/ca/nrc/cadc/dali/CommonParamValidatorTest.java +++ b/cadc-dali/src/test/java/ca/nrc/cadc/dali/CommonParamValidatorTest.java @@ -73,6 +73,9 @@ import ca.nrc.cadc.util.Log4jInit; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -460,6 +463,56 @@ public void testValidateID() { } } + @Test + public void testValidateInteger() { + final Map> params = new HashMap<>(); + params.put("param1", Arrays.asList("2", "4")); + params.put("param2", Arrays.asList("5", "9")); + try { + final List validIntegers = + paramValidator.validateInteger("param1", params, Arrays.asList(1, 2, 3)); + Assert.assertArrayEquals("Wrong list of ints.", new Integer[] { 2 }, validIntegers.toArray()); + } catch (Exception unexpected) { + log.error("unexpected exception", unexpected); + Assert.fail("unexpected exception: " + unexpected); + throw unexpected; + } + + try { + final List validIntegers = + paramValidator.validateInteger("param2", params, Arrays.asList(1, 2, 3)); + Assert.assertArrayEquals("Should be empty array of ints.", new Integer[] { }, + validIntegers.toArray()); + } catch (Exception unexpected) { + log.error("unexpected exception", unexpected); + Assert.fail("unexpected exception: " + unexpected); + throw unexpected; + } + } + + @Test + public void testGetResponseFormat() { + final Map> params = new HashMap<>(); + try { + Assert.assertEquals("Wrong RESPONSEFORMAT.", "tsv", + paramValidator.getResponseFormat(params, "tsv")); + } catch (Exception unexpected) { + log.error("unexpected exception", unexpected); + Assert.fail("unexpected exception: " + unexpected); + throw unexpected; + } + + try { + params.put("RESPONSEFORMAT", Collections.singletonList("votable")); + Assert.assertEquals("Wrong RESPONSEFORMAT.", "votable", + paramValidator.getResponseFormat(params, "tsv")); + } catch (Exception unexpected) { + log.error("unexpected exception", unexpected); + Assert.fail("unexpected exception: " + unexpected); + throw unexpected; + } + } + public void doValidateString(Method testMethod, String[] testParams, String[] testValues) throws Exception { if (testValues == null) { From b29b365f7cd50af74abe3c1a837fb309e4477808 Mon Sep 17 00:00:00 2001 From: Dustin Jenkins Date: Wed, 27 Jul 2022 10:52:38 -0700 Subject: [PATCH 05/10] Linter fix. --- .../main/java/org/opencadc/conesearch/TAPQueryGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java index a4688832..8e156f49 100644 --- a/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java +++ b/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java @@ -70,12 +70,12 @@ import ca.nrc.cadc.dali.Circle; import ca.nrc.cadc.dali.tables.votable.VOTableWriter; +import ca.nrc.cadc.util.StringUtil; import java.util.HashMap; import java.util.List; import java.util.Map; -import ca.nrc.cadc.util.StringUtil; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; From 04704833138162966646897088bde9d7d5e91c8a Mon Sep 17 00:00:00 2001 From: Dustin Jenkins Date: Fri, 29 Jul 2022 08:20:31 -0700 Subject: [PATCH 06/10] Handle default VERB value. --- .../java/org/opencadc/conesearch/ConeParameterValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/ConeParameterValidator.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/ConeParameterValidator.java index 6559ce60..2f951846 100644 --- a/cadc-conesearch/src/main/java/org/opencadc/conesearch/ConeParameterValidator.java +++ b/cadc-conesearch/src/main/java/org/opencadc/conesearch/ConeParameterValidator.java @@ -112,7 +112,7 @@ public Circle validateCone(final Map> parameters) { public int validateVERB(final Map> parameters) { // If not VERB provided, default to 2. - if (parameters.containsKey(VERB_PARAM)) { + if (parameters.get(VERB_PARAM) != null && !parameters.get(VERB_PARAM).isEmpty()) { final List validIntegers = validateInteger(VERB_PARAM, parameters, Arrays.asList(MIN_VERB_VALUE, MID_VERB_VALUE, MAX_VERB_VALUE)); From fffea552bc8679af78e1e1c5e97c7811e0dfcb88 Mon Sep 17 00:00:00 2001 From: Dustin Jenkins Date: Thu, 2 Feb 2023 14:11:44 -0800 Subject: [PATCH 07/10] Version increments after last release. --- cadc-conesearch/build.gradle | 2 +- cadc-dali/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cadc-conesearch/build.gradle b/cadc-conesearch/build.gradle index 638e0e27..d71c7517 100644 --- a/cadc-conesearch/build.gradle +++ b/cadc-conesearch/build.gradle @@ -18,7 +18,7 @@ description = 'OpenCADC Simple Cone Search Java API' def git_url = 'https://github.com/opencadc/dal.git' dependencies { - implementation 'org.opencadc:cadc-dali:[1.2.17,2.0)' + implementation 'org.opencadc:cadc-dali:[1.2.18,2.0)' implementation 'org.opencadc:cadc-rest:[1.3.12,2.0)' implementation 'org.opencadc:cadc-util:[1.6.4,2.0)' implementation 'org.opencadc:cadc-vosi:[1.4.4,2.0)' diff --git a/cadc-dali/build.gradle b/cadc-dali/build.gradle index 220822cd..d7151a14 100644 --- a/cadc-dali/build.gradle +++ b/cadc-dali/build.gradle @@ -14,7 +14,7 @@ sourceCompatibility = 1.8 group = 'org.opencadc' -version = '1.2.17' +version = '1.2.18' description = 'OpenCADC DALI library' def git_url = 'https://github.com/opencadc/dal' From 258a431a152a228de7fde63035254b03f0077c19 Mon Sep 17 00:00:00 2001 From: Dustin Jenkins Date: Tue, 20 Feb 2024 07:06:40 -0800 Subject: [PATCH 08/10] Revert dali dependency. --- cadc-conesearch/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cadc-conesearch/build.gradle b/cadc-conesearch/build.gradle index d71c7517..638e0e27 100644 --- a/cadc-conesearch/build.gradle +++ b/cadc-conesearch/build.gradle @@ -18,7 +18,7 @@ description = 'OpenCADC Simple Cone Search Java API' def git_url = 'https://github.com/opencadc/dal.git' dependencies { - implementation 'org.opencadc:cadc-dali:[1.2.18,2.0)' + implementation 'org.opencadc:cadc-dali:[1.2.17,2.0)' implementation 'org.opencadc:cadc-rest:[1.3.12,2.0)' implementation 'org.opencadc:cadc-util:[1.6.4,2.0)' implementation 'org.opencadc:cadc-vosi:[1.4.4,2.0)' From fab300faec52a32c76a35a29e40b475efb5f93ad Mon Sep 17 00:00:00 2001 From: Dustin Jenkins Date: Tue, 20 Feb 2024 07:28:47 -0800 Subject: [PATCH 09/10] Fix local compilation errors. --- .../conesearch/ConeParameterValidator.java | 15 +++++++++++++++ .../opencadc/conesearch/TAPQueryGenerator.java | 3 +-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/ConeParameterValidator.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/ConeParameterValidator.java index 2f951846..f02601ab 100644 --- a/cadc-conesearch/src/main/java/org/opencadc/conesearch/ConeParameterValidator.java +++ b/cadc-conesearch/src/main/java/org/opencadc/conesearch/ConeParameterValidator.java @@ -76,6 +76,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; /** * Validator for Cone Search parameters. @@ -85,6 +86,9 @@ public class ConeParameterValidator extends CommonParamValidator { public static final String RA_PARAM = "RA"; public static final String DEC_PARAM = "DEC"; public static final String SR_PARAM = "SR"; + + public static final String MAXREC = "MAXREC"; + static final int MIN_VERB_VALUE = 1; static final int MID_VERB_VALUE = 2; static final int MAX_VERB_VALUE = 3; @@ -126,6 +130,17 @@ public int validateVERB(final Map> parameters) { } } + int getMaxRec(final Map> parameters, final int defaultValue, final int maxValue) { + return validateInteger(ConeParameterValidator.MAXREC, parameters).stream().filter(i -> i > maxValue) + .findFirst().orElse(defaultValue); + } + + private List validateInteger(final String verbParam, final Map> parameters, + final List validValues) { + return super.validateInteger(verbParam, parameters).stream().filter(validValues::contains) + .collect(Collectors.toList()); + } + private String getFirstParameter(final String key, final Map> requestParameters) { final List values = requestParameters.get(key); return (values == null || values.isEmpty()) ? null : values.get(0); diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java index 8e156f49..f5f0b1f6 100644 --- a/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java +++ b/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java @@ -69,7 +69,6 @@ package org.opencadc.conesearch; import ca.nrc.cadc.dali.Circle; -import ca.nrc.cadc.dali.tables.votable.VOTableWriter; import ca.nrc.cadc.util.StringUtil; import java.util.HashMap; @@ -139,7 +138,7 @@ public Map getParameterMap() { // Obtain and, if necessary, provide a default RESPONSEFORMAT. queryParameterMap.put(ConeParameterValidator.RESPONSEFORMAT, - coneParameterValidator.getResponseFormat(parameters, VOTableWriter.CONTENT_TYPE)); + coneParameterValidator.getResponseFormat(parameters)); // Obtain and validate the VERB (verbosity) output. final int outputVerbosity = coneParameterValidator.validateVERB(parameters); From 050a8ae53dc74e319556bf31ff8a4222f5d95344 Mon Sep 17 00:00:00 2001 From: Dustin Jenkins Date: Mon, 15 Apr 2024 15:47:42 -0700 Subject: [PATCH 10/10] Compilation fixes, and remove vulnerability in Apache Commons. --- .../conesearch/ConeParameterValidator.java | 19 ++++++++++++++++--- .../conesearch/TAPQueryGenerator.java | 3 ++- cadc-pkg-server/build.gradle | 3 ++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/ConeParameterValidator.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/ConeParameterValidator.java index f02601ab..cc0f7135 100644 --- a/cadc-conesearch/src/main/java/org/opencadc/conesearch/ConeParameterValidator.java +++ b/cadc-conesearch/src/main/java/org/opencadc/conesearch/ConeParameterValidator.java @@ -131,13 +131,19 @@ public int validateVERB(final Map> parameters) { } int getMaxRec(final Map> parameters, final int defaultValue, final int maxValue) { - return validateInteger(ConeParameterValidator.MAXREC, parameters).stream().filter(i -> i > maxValue) - .findFirst().orElse(defaultValue); + return validateInteger(ConeParameterValidator.MAXREC, parameters) + .stream() + .filter(i -> i <= maxValue) + .filter(i -> i > 0) + .findFirst() + .orElse(defaultValue); } private List validateInteger(final String verbParam, final Map> parameters, final List validValues) { - return super.validateInteger(verbParam, parameters).stream().filter(validValues::contains) + return super.validateInteger(verbParam, parameters) + .stream() + .filter(validValues::contains) .collect(Collectors.toList()); } @@ -145,4 +151,11 @@ private String getFirstParameter(final String key, final Map values = requestParameters.get(key); return (values == null || values.isEmpty()) ? null : values.get(0); } + + public String getResponseFormat(final Map> parameters, final String contentType) { + return validateString(ConeParameterValidator.RESPONSEFORMAT, parameters, null) + .stream() + .findFirst() + .orElse(contentType); + } } diff --git a/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java b/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java index f5f0b1f6..8e156f49 100644 --- a/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java +++ b/cadc-conesearch/src/main/java/org/opencadc/conesearch/TAPQueryGenerator.java @@ -69,6 +69,7 @@ package org.opencadc.conesearch; import ca.nrc.cadc.dali.Circle; +import ca.nrc.cadc.dali.tables.votable.VOTableWriter; import ca.nrc.cadc.util.StringUtil; import java.util.HashMap; @@ -138,7 +139,7 @@ public Map getParameterMap() { // Obtain and, if necessary, provide a default RESPONSEFORMAT. queryParameterMap.put(ConeParameterValidator.RESPONSEFORMAT, - coneParameterValidator.getResponseFormat(parameters)); + coneParameterValidator.getResponseFormat(parameters, VOTableWriter.CONTENT_TYPE)); // Obtain and validate the VERB (verbosity) output. final int outputVerbosity = coneParameterValidator.validateVERB(parameters); diff --git a/cadc-pkg-server/build.gradle b/cadc-pkg-server/build.gradle index 6da263b7..61de2a27 100644 --- a/cadc-pkg-server/build.gradle +++ b/cadc-pkg-server/build.gradle @@ -20,7 +20,8 @@ description = 'OpenCADC CADC package server library' def git_url = 'https://github.com/opencadc/dal' dependencies { - implementation 'org.apache.commons:commons-compress:[1.12,)' + implementation 'commons-codec:commons-codec:[1.16.1,2.0)' + implementation 'org.apache.commons:commons-compress:[1.26.1,2.0)' implementation 'org.opencadc:cadc-util:[1.6,2.0)' implementation 'org.opencadc:cadc-log:[1.0,)'