From 6764621cef0628cf7c84cb841fd263945ba308a3 Mon Sep 17 00:00:00 2001 From: Nathanael Jourdane Date: Thu, 21 Apr 2016 18:02:55 +0200 Subject: [PATCH] move and rename some files --- src/main/java/eu/omp/irap/vespa/epntapclient/votable/Consts.java | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/eu/omp/irap/vespa/epntapclient/votable/VOTableException.java | 311 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableDataParser.java | 298 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableException.java | 311 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- src/main/java/eu/omp/irap/vespa/epntapclient/votable/data/VOTableDataCtrl.java | 298 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/eu/omp/irap/vespa/epntapclient/votable/utils/Consts.java | 49 ------------------------------------------------- 6 files changed, 658 insertions(+), 658 deletions(-) create mode 100644 src/main/java/eu/omp/irap/vespa/epntapclient/votable/Consts.java create mode 100644 src/main/java/eu/omp/irap/vespa/epntapclient/votable/VOTableException.java delete mode 100644 src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableDataParser.java delete mode 100644 src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableException.java create mode 100644 src/main/java/eu/omp/irap/vespa/epntapclient/votable/data/VOTableDataCtrl.java delete mode 100644 src/main/java/eu/omp/irap/vespa/epntapclient/votable/utils/Consts.java diff --git a/src/main/java/eu/omp/irap/vespa/epntapclient/votable/Consts.java b/src/main/java/eu/omp/irap/vespa/epntapclient/votable/Consts.java new file mode 100644 index 0000000..2bf2c1c --- /dev/null +++ b/src/main/java/eu/omp/irap/vespa/epntapclient/votable/Consts.java @@ -0,0 +1,49 @@ +/* + * This file is a part of EpnTAPClient. + * This program aims to provide EPN-TAP support for software clients, like CASSIS spectrum analyzer. + * See draft specifications: https://voparis-confluence.obspm.fr/pages/viewpage.action?pageId=559861 + * Copyright (C) 2016 Institut de Recherche en Astrophysique et Planétologie. + * + * This program is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or (at your option) any later + * version. This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. You should have received a copy of + * the GNU General Public License along with this program. If not, see + * . + */ + +package eu.omp.irap.vespa.epntapclient.votable.utils; + +/** + * This class defines widely-used constants. + * + * @author N. Jourdane + */ +public class Consts { + + /** The character set used (for http requests, writing in files, etc.). */ + public static final String ENCODING = "UTF-8"; + + /** The temporary directory path. */ + public static final String TMP_DIR = System.getProperty("java.io.tmpdir"); + + /** The URL of the registry used by default to get the services. */ + public static final String DEFAULT_REGISTRY_URL = "http://gavo.aip.de/tap"; + // http://reg.g-vo.org/tap + // http://dc.zah.uni-heidelberg.de/tap + // http://gavo.aip.de/tap + // http://voparis-cdpp.obspm.fr/tap + + public static final String QUERY_LANG = "ADQL"; + + public static final String QUERY_REQUEST = "doQuery"; + + public static final String QUERY_FORMAT = "votable"; + + + /** Constructor to hide the implicit public one. */ + private Consts() { + } +} diff --git a/src/main/java/eu/omp/irap/vespa/epntapclient/votable/VOTableException.java b/src/main/java/eu/omp/irap/vespa/epntapclient/votable/VOTableException.java new file mode 100644 index 0000000..c4a4f53 --- /dev/null +++ b/src/main/java/eu/omp/irap/vespa/epntapclient/votable/VOTableException.java @@ -0,0 +1,311 @@ +/* + * This file is a part of EpnTAPClient. + * This program aims to provide EPN-TAP support for software clients, like CASSIS spectrum analyzer. + * See draft specifications: https://voparis-confluence.obspm.fr/pages/viewpage.action?pageId=559861 + * Copyright (C) 2016 Institut de Recherche en Astrophysique et Planétologie. + * + * This program is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or (at your option) any later + * version. This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. You should have received a copy of + * the GNU General Public License along with this program. If not, see + * . + */ + +package eu.omp.irap.vespa.epntapclient.votable.controller; + +import java.io.IOException; + +/** + * VOTableException is the global exception for all the VOTable application. All other exceptions + * should extend it. + * + * @author N. Jourdane + */ +public abstract class VOTableException extends Exception { + + /** The serial version UID. */ + private static final long serialVersionUID = 1L; + + + /** + * @param message The message describing the exception displayed in the error dialog. + */ + public VOTableException(String message) { + super(message); + } + + /** + * @param message The message describing the exception displayed in the error dialog. + * @param e The exception thrown. + */ + public VOTableException(String message, Exception e) { + super(message, e); + } + + + /** Abstract exception for when the application can not send the query. */ + public abstract static class CantSendQueryException extends VOTableException { + + /** */ + private static final long serialVersionUID = 1L; + + + /** + * @param message The message describing the exception displayed in the error dialog. + */ + public CantSendQueryException(String message) { + super(message); + } + + /** + * @param message The message describing the exception displayed in the error dialog. + * @param e The exception thrown. + */ + public CantSendQueryException(String message, Exception e) { + super(message, e); + } + + + /** The URL is not correctly formated. */ + public static class MalformedURLException extends CantSendQueryException { + + /** */ + private static final long serialVersionUID = 1L; + + + /** + * @param url The url sent to the server. + * @param e The exception thrown. + */ + public MalformedURLException(String url, Exception e) { + super("The URL " + url + " is not correctly formated.", e); + } + } + + /** The URL is not correctly formated. */ + public static class CantWriteQueryResultException extends CantSendQueryException { + + /** */ + private static final long serialVersionUID = 1L; + + + /** + * @param url The url sent to the server. + * @param e The exception thrown. + */ + public CantWriteQueryResultException(String path, Exception e) { + super("Can not write the query result in " + path + ".", e); + } + } + + /** The URL is not correctly formated. */ + public static class UnsupportedParamEncodingException extends CantSendQueryException { + + /** */ + private static final long serialVersionUID = 1L; + + + /** + * @param url The url sent to the server. + * @param e The exception thrown. + */ + public UnsupportedParamEncodingException(String key, String value, Exception e) { + super("The URL parameter " + key + " with value '" + value + + "' is not correctly encoded.", e); + } + } + + /** Can not print the result in the file. */ + public static class CantPrintRequestResultException extends CantSendQueryException { + + /** */ + private static final long serialVersionUID = 1L; + + + /** + * @param resultFilePath The path of the file where the query results should be stored. + * @param e The exception thrown. + */ + public CantPrintRequestResultException(String resultFilePath, IOException e) { + super("Can not print the result in the file " + resultFilePath, e); + } + } + + /** Can not open an HTTP connection to the specified URL. */ + public static class CantOpenConnectionException extends CantSendQueryException { + + /** */ + private static final long serialVersionUID = 1L; + + + /** + * @param url The url sent to the server. + * @param e The exception thrown. + */ + public CantOpenConnectionException(String url, IOException e) { + super("Can not open an HTTP connection to " + url, e); + } + } + + /** Can not get the server response code for the request. */ + public static class CantGetResponseCode extends CantSendQueryException { + + /** */ + private static final long serialVersionUID = 1L; + + + /** + * @param url The url sent to the server. + * @param e The exception thrown. + */ + public CantGetResponseCode(String url, IOException e) { + super("Can not get the server response code for the request " + url, e); + } + } + + /** The server returned the bad response code (but not 400). */ + public static class BadResponseCodeException extends CantSendQueryException { + + /** */ + private static final long serialVersionUID = 1L; + + + /** + * @param url The url sent to the server. + * @param responseCode The HTTP GET response code, which is bad. + */ + public BadResponseCodeException(String url, int responseCode) { + super("The server returned the bad response code `" + responseCode + + "` for the request " + url); + } + } + + /** Can not get the input stream of the result, neither the error stream. */ + public static class CantGetErrorStream extends CantSendQueryException { + + /** */ + private static final long serialVersionUID = 1L; + + + /** + * @param url The url sent to the server. + * @param e The exception thrown. + */ + public CantGetErrorStream(String url, IOException e) { + super("Can not get the input stream of the result, neither the error stream " + + "for the request " + url, e); + } + } + + } + + /** Abstract exception for when the application can not display the VOTable. */ + public abstract static class CantDisplayVOTableException extends VOTableException { + + /** */ + private static final long serialVersionUID = 1L; + + + /** + * @param message The message describing the exception displayed in the error dialog. + * @param e The exception thrown. + */ + public CantDisplayVOTableException(String message, Exception e) { + super(message, e); + } + + /** + * @param message The message describing the exception displayed in the error dialog. + */ + public CantDisplayVOTableException(String message) { + super(message); + } + + + /** Can not parse the VOTable because it doesn't match with the VOTable schema. */ + public static class VOTableIsNotValidException extends CantDisplayVOTableException { + + /** */ + private static final long serialVersionUID = 1L; + + + /** + * @param voTablePath The path of the VOTable. + * @param e The exception thrown. + */ + public VOTableIsNotValidException(String voTablePath, Exception e) { + super("Can not parse the VOTable because it doesn't match with the VOTable schema." + + "\n See the VOTable file for more details: " + voTablePath, e); + } + } + + /** VOTable with more than one resource are not yet supported. */ + public static class SeveralResourcesException extends CantDisplayVOTableException { + + /** */ + private static final long serialVersionUID = 1L; + + + /** + * @param voTablePath The path of the VOTable. + */ + public SeveralResourcesException(String voTablePath) { + super("VOTable with more than one resource are not yet supported. \n" + + "See VOTable file for more informations: " + voTablePath); + } + } + + /** VOTable with more than one resource are not yet supported. */ + public static class SeveralTablesException extends CantDisplayVOTableException { + + /** */ + private static final long serialVersionUID = 1L; + + + /** + * @param voTablePath The path of the VOTable. + */ + public SeveralTablesException(String voTablePath) { + super("VOTable with more than one resource are not yet supported. \n" + + "See VOTable file for more informations: " + voTablePath); + } + } + + /** Can not change schema location on the VOTable file. */ + public static class CantModifyVOTableException extends CantDisplayVOTableException { + + /** */ + private static final long serialVersionUID = 1L; + + + /** + * @param voTablePath The path of the VOTable. + * @param e The exception thrown. + */ + public CantModifyVOTableException(String voTablePath, Exception e) { + super("Can not change schema location on the VOTable file: " + voTablePath, e); + } + } + + /** There is an error in the VOTable. */ + public static class ErrorMessageInVOTableException extends CantDisplayVOTableException { + + /** */ + private static final long serialVersionUID = 1L; + + + /** + * @param errorInfo The information about the error, which comes from the VOTable itself + * from the "INFO" node. + */ + public ErrorMessageInVOTableException(String errorInfo) { + super("There is an error in the VOTable:\n" + errorInfo + + "\nPlease check your ADQL query."); + } + } + } + +} diff --git a/src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableDataParser.java b/src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableDataParser.java deleted file mode 100644 index a47d892..0000000 --- a/src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableDataParser.java +++ /dev/null @@ -1,298 +0,0 @@ -/* - * This file is a part of EpnTAPClient. - * This program aims to provide EPN-TAP support for software clients, like CASSIS spectrum analyzer. - * See draft specifications: https://voparis-confluence.obspm.fr/pages/viewpage.action?pageId=559861 - * Copyright (C) 2016 Institut de Recherche en Astrophysique et Planétologie. - * - * This program is free software: you can - * redistribute it and/or modify it under the terms of the GNU General Public License as published - * by the Free Software Foundation, either version 3 of the License, or (at your option) any later - * version. This program is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. You should have received a copy of - * the GNU General Public License along with this program. If not, see - * . - */ - -package eu.omp.irap.vespa.epntapclient.votable.controller; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Logger; - -import javax.xml.bind.DatatypeConverter; - -import com.google.gson.Gson; - -import eu.omp.irap.vespa.epntapclient.votable.model.DataType; -import eu.omp.irap.vespa.epntapclient.votable.model.Field; -import eu.omp.irap.vespa.epntapclient.votable.model.Stream; -import eu.omp.irap.vespa.epntapclient.votable.model.Table; -import eu.omp.irap.vespa.epntapclient.votable.model.TableData; -import eu.omp.irap.vespa.epntapclient.votable.utils.Debug; - -/** - * @author N. Jourdane - */ -public class VOTableDataParser { - - /** The logger for the class VOTableDataParser. */ - private static final Logger logger = Logger.getLogger(VOTableDataParser.class.getName()); - - /** - * A list of arrays, representing data stored in the VOTable. Each element is a VOTable row, - * where arrays elements are in the same order as `columnNames`. - */ - private List data; - - /** The name of the columns. `columnNames` length is equals to `data` length */ - private String[] columnsName; - - /** The byte array stored in the VOTable Table stream (if any). */ - private ByteBuffer stream; - - /** The index of the current position in the bytes array. */ - private int cursor; - - - /** - * In VOTables, data can be stored in 4 different serializations: BINARY, BINARY2, TABLEDATA and - * FITS. This class aims to provide a unique way to get the data table, regardless of its - * serialization type. - * - * @param table The table on which we want get the data. - * @throws IOException If the VOTable data can not be parsed. - */ - public VOTableDataParser(Table table) throws IOException { - cursor = 0; - - List fields = new ArrayList<>(); - for (Object obj : table.getFIELDOrPARAMOrGROUP()) { - if (obj.getClass() == Field.class) { - fields.add((Field) obj); - } - } - columnsName = new String[fields.size()]; - for (int i = 0; i < fields.size(); i++) { - columnsName[i] = fields.get(i).getName(); - } - VOTableDataParser.logger.info("Columns name: " + new Gson().toJson(columnsName)); - - data = new ArrayList<>(); - - if (table.getDATA().getBINARY() != null) { - parseBinaryStream(table.getDATA().getBINARY().getSTREAM(), fields); - } else if (table.getDATA().getBINARY2() != null) { - VOTableDataParser.parseBinary2Stream(table.getDATA().getBINARY2().getSTREAM(), fields); - } else if (table.getDATA().getTABLEDATA() != null) { - VOTableDataParser.parseTableDataStream(table.getDATA().getTABLEDATA(), fields); - } else if (table.getDATA().getFITS() != null) { - VOTableDataParser.parseFITSStream(table.getDATA().getFITS().getSTREAM(), fields); - } - - Debug.printObject("voTableData", data); - } - - /** - * @return the data stored in the Table. - */ - public List getDataArray() { - return data; - } - - /** - * @return An array of Table fields name. - */ - public String[] getColumnsName() { - return columnsName; - } - - /** - * @param column The name of the column to get. - * @return An array of Table fields name. - * @throws IllegalArgumentException Column name not found in the table. - */ - public int getColumnIndex(String column) { - int i = 0; - while (!column.equals(columnsName[i])) { - i++; - if (i > columnsName.length) { - throw new IllegalArgumentException("Column " + column + " not found in the table."); - } - } - return i; - } - - /** - * @return The number of rows in the Table. - */ - public int getNbRows() { - return data.size(); - } - - /** - * @return The number of columns in the Table. - */ - public int getNbColumns() { - return columnsName.length; - } - - /** - * @param rowIndex The index of the row to get. - * @return The Table row at the specified index. - */ - public Object[] getRowByIndex(int rowIndex) { - return data.get(rowIndex); - } - - /** - * @param rowIndex The index of the row to get. - * @return A dictionary representing the row, where each key is a column name. - */ - public Map getDicRowByIndex(int rowIndex) { - Map row = new HashMap<>(); - for (int i = 0; i < columnsName.length; i++) { - row.put(columnsName[i], data.get(rowIndex)[i]); - } - return row; - } - - /** - * @param columnIndex A UNIQUE column (as SQL sense) to identify a row. - * @param value The value at `columnName`, in order to get the full row. - * @return A Table row, identified by a unique `value` in the `columnName` column. - * @throws IndexOutOfBoundsException If the value is not found at the specified column. - */ - public Object[] getRowByValue(int columnIndex, Object value) { - for (Object[] row : data) { - if (value.equals(row[columnIndex])) { - return row; - } - } - throw new IndexOutOfBoundsException( - "The value " + value + " is not found on the table at the column " + columnIndex); - } - - /** - * get the data on its BINARY form. - * - * @param voStream the data Stream in the VOTable Table. - * @param fields The Fields corresponding to the Table. - * @throws UnsupportedOperationException Data as arrays are not supported yet. - */ - private void parseBinaryStream(Stream voStream, List fields) { - VOTableDataParser.logger.info("Parsing data in BINARY stream..."); - String strStream = voStream.getValue().replaceAll("(\\r|\\n)", ""); - - stream = ByteBuffer.wrap(DatatypeConverter.parseBase64Binary(strStream)); - Object[] row = new Object[columnsName.length]; - - int nValue = 0; - while (stream.hasRemaining()) { - int nColumn = nValue % columnsName.length; - Field column = fields.get(nColumn); - DataType dataType = column.getDatatype(); - - //@noformat - int blockSize = - dataType.equals(DataType.BOOLEAN) ? 1 : - dataType.equals(DataType.UNSIGNED_BYTE) ? 1 : - dataType.equals(DataType.SHORT) ? 2 : - dataType.equals(DataType.INT) ? 4 : - dataType.equals(DataType.LONG) ? 8 : - dataType.equals(DataType.CHAR) ? 1 : - dataType.equals(DataType.UNICODE_CHAR) ? 2 : - dataType.equals(DataType.FLOAT) ? 4 : - dataType.equals(DataType.DOUBLE) ? 8 : - dataType.equals(DataType.FLOAT_COMPLEX) ? 8 : - dataType.equals(DataType.DOUBLE_COMPLEX) ? 16 : 0; - //@format - - int arraySize; - if (column.getArraysize() == null) { - arraySize = blockSize; - } else if ("*".equals(column.getArraysize())) { - arraySize = stream.getInt() * blockSize; - } else { - arraySize = Integer.parseInt(column.getArraysize()) * blockSize; - } - if (arraySize != blockSize && !(dataType.equals(DataType.CHAR) - || dataType.equals(DataType.UNICODE_CHAR))) { - throw new UnsupportedOperationException("Numeric data as array are not supported."); - } - - if (nColumn == 0) { - row = new Object[columnsName.length]; - } - - if (dataType.equals(DataType.BOOLEAN)) { - row[nColumn] = new Boolean(stream.getInt() == 0 ? false : true); - } else if (dataType.equals(DataType.UNSIGNED_BYTE)) { - row[nColumn] = stream.get(); - } else if (dataType.equals(DataType.SHORT)) { - row[nColumn] = stream.getShort(); - } else if (dataType.equals(DataType.INT)) { - row[nColumn] = stream.getInt(); - } else if (dataType.equals(DataType.LONG)) { - row[nColumn] = stream.getLong(); - } else if (dataType.equals(DataType.CHAR)) { - String value = new String(); - for (int i = 0; i < arraySize && cursor < stream.capacity(); i++) { - value += (char) stream.get(); - } - row[nColumn] = value.trim(); - } else if (dataType.equals(DataType.UNICODE_CHAR)) { - String value = new String(); - for (int i = 0; i < arraySize && cursor < stream.capacity(); i += 2) { - value += stream.getChar(); - } - row[nColumn] = value.trim(); - } else if (dataType.equals(DataType.FLOAT)) { - float value = stream.getFloat(); - row[nColumn] = Float.isNaN(value) ? null : value; - } else if (dataType.equals(DataType.DOUBLE)) { - double value = stream.getDouble(); - row[nColumn] = Double.isNaN(value) ? null : value; - } else { - VOTableDataParser.logger.warning("Data type " + dataType + " is not supported."); - } - - // logger.debug(columnsName[nColumn] + ": " + row[nColumn]) - - row[nColumn] = row[nColumn]; - if (nColumn == columnsName.length - 1) { - data.add(row); - } - nValue++; - } - - } - - /** - * @param stream the data Stream in the VOTable Table. - * @param fields The Fields corresponding to the Table. - */ - private static void parseBinary2Stream(Stream stream, List fields) { - VOTableDataParser.logger.info("Parsing data in BINARY2 stream..."); - } - - /** - * @param tabledata the TableData of the VOTable Table. - * @param fields The Fields corresponding to the Table. - */ - private static void parseTableDataStream(TableData tabledata, List fields) { - VOTableDataParser.logger.info("Parsing data in TABLEDATA stream..."); - } - - /** - * @param stream the data Stream in the VOTable Table. - * @param fields The Fields corresponding to the Table. - */ - private static void parseFITSStream(Stream stream, List fields) { - VOTableDataParser.logger.info("Parsing data in FITS stream..."); - } -} diff --git a/src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableException.java b/src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableException.java deleted file mode 100644 index c4a4f53..0000000 --- a/src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableException.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * This file is a part of EpnTAPClient. - * This program aims to provide EPN-TAP support for software clients, like CASSIS spectrum analyzer. - * See draft specifications: https://voparis-confluence.obspm.fr/pages/viewpage.action?pageId=559861 - * Copyright (C) 2016 Institut de Recherche en Astrophysique et Planétologie. - * - * This program is free software: you can - * redistribute it and/or modify it under the terms of the GNU General Public License as published - * by the Free Software Foundation, either version 3 of the License, or (at your option) any later - * version. This program is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. You should have received a copy of - * the GNU General Public License along with this program. If not, see - * . - */ - -package eu.omp.irap.vespa.epntapclient.votable.controller; - -import java.io.IOException; - -/** - * VOTableException is the global exception for all the VOTable application. All other exceptions - * should extend it. - * - * @author N. Jourdane - */ -public abstract class VOTableException extends Exception { - - /** The serial version UID. */ - private static final long serialVersionUID = 1L; - - - /** - * @param message The message describing the exception displayed in the error dialog. - */ - public VOTableException(String message) { - super(message); - } - - /** - * @param message The message describing the exception displayed in the error dialog. - * @param e The exception thrown. - */ - public VOTableException(String message, Exception e) { - super(message, e); - } - - - /** Abstract exception for when the application can not send the query. */ - public abstract static class CantSendQueryException extends VOTableException { - - /** */ - private static final long serialVersionUID = 1L; - - - /** - * @param message The message describing the exception displayed in the error dialog. - */ - public CantSendQueryException(String message) { - super(message); - } - - /** - * @param message The message describing the exception displayed in the error dialog. - * @param e The exception thrown. - */ - public CantSendQueryException(String message, Exception e) { - super(message, e); - } - - - /** The URL is not correctly formated. */ - public static class MalformedURLException extends CantSendQueryException { - - /** */ - private static final long serialVersionUID = 1L; - - - /** - * @param url The url sent to the server. - * @param e The exception thrown. - */ - public MalformedURLException(String url, Exception e) { - super("The URL " + url + " is not correctly formated.", e); - } - } - - /** The URL is not correctly formated. */ - public static class CantWriteQueryResultException extends CantSendQueryException { - - /** */ - private static final long serialVersionUID = 1L; - - - /** - * @param url The url sent to the server. - * @param e The exception thrown. - */ - public CantWriteQueryResultException(String path, Exception e) { - super("Can not write the query result in " + path + ".", e); - } - } - - /** The URL is not correctly formated. */ - public static class UnsupportedParamEncodingException extends CantSendQueryException { - - /** */ - private static final long serialVersionUID = 1L; - - - /** - * @param url The url sent to the server. - * @param e The exception thrown. - */ - public UnsupportedParamEncodingException(String key, String value, Exception e) { - super("The URL parameter " + key + " with value '" + value - + "' is not correctly encoded.", e); - } - } - - /** Can not print the result in the file. */ - public static class CantPrintRequestResultException extends CantSendQueryException { - - /** */ - private static final long serialVersionUID = 1L; - - - /** - * @param resultFilePath The path of the file where the query results should be stored. - * @param e The exception thrown. - */ - public CantPrintRequestResultException(String resultFilePath, IOException e) { - super("Can not print the result in the file " + resultFilePath, e); - } - } - - /** Can not open an HTTP connection to the specified URL. */ - public static class CantOpenConnectionException extends CantSendQueryException { - - /** */ - private static final long serialVersionUID = 1L; - - - /** - * @param url The url sent to the server. - * @param e The exception thrown. - */ - public CantOpenConnectionException(String url, IOException e) { - super("Can not open an HTTP connection to " + url, e); - } - } - - /** Can not get the server response code for the request. */ - public static class CantGetResponseCode extends CantSendQueryException { - - /** */ - private static final long serialVersionUID = 1L; - - - /** - * @param url The url sent to the server. - * @param e The exception thrown. - */ - public CantGetResponseCode(String url, IOException e) { - super("Can not get the server response code for the request " + url, e); - } - } - - /** The server returned the bad response code (but not 400). */ - public static class BadResponseCodeException extends CantSendQueryException { - - /** */ - private static final long serialVersionUID = 1L; - - - /** - * @param url The url sent to the server. - * @param responseCode The HTTP GET response code, which is bad. - */ - public BadResponseCodeException(String url, int responseCode) { - super("The server returned the bad response code `" + responseCode - + "` for the request " + url); - } - } - - /** Can not get the input stream of the result, neither the error stream. */ - public static class CantGetErrorStream extends CantSendQueryException { - - /** */ - private static final long serialVersionUID = 1L; - - - /** - * @param url The url sent to the server. - * @param e The exception thrown. - */ - public CantGetErrorStream(String url, IOException e) { - super("Can not get the input stream of the result, neither the error stream " - + "for the request " + url, e); - } - } - - } - - /** Abstract exception for when the application can not display the VOTable. */ - public abstract static class CantDisplayVOTableException extends VOTableException { - - /** */ - private static final long serialVersionUID = 1L; - - - /** - * @param message The message describing the exception displayed in the error dialog. - * @param e The exception thrown. - */ - public CantDisplayVOTableException(String message, Exception e) { - super(message, e); - } - - /** - * @param message The message describing the exception displayed in the error dialog. - */ - public CantDisplayVOTableException(String message) { - super(message); - } - - - /** Can not parse the VOTable because it doesn't match with the VOTable schema. */ - public static class VOTableIsNotValidException extends CantDisplayVOTableException { - - /** */ - private static final long serialVersionUID = 1L; - - - /** - * @param voTablePath The path of the VOTable. - * @param e The exception thrown. - */ - public VOTableIsNotValidException(String voTablePath, Exception e) { - super("Can not parse the VOTable because it doesn't match with the VOTable schema." - + "\n See the VOTable file for more details: " + voTablePath, e); - } - } - - /** VOTable with more than one resource are not yet supported. */ - public static class SeveralResourcesException extends CantDisplayVOTableException { - - /** */ - private static final long serialVersionUID = 1L; - - - /** - * @param voTablePath The path of the VOTable. - */ - public SeveralResourcesException(String voTablePath) { - super("VOTable with more than one resource are not yet supported. \n" - + "See VOTable file for more informations: " + voTablePath); - } - } - - /** VOTable with more than one resource are not yet supported. */ - public static class SeveralTablesException extends CantDisplayVOTableException { - - /** */ - private static final long serialVersionUID = 1L; - - - /** - * @param voTablePath The path of the VOTable. - */ - public SeveralTablesException(String voTablePath) { - super("VOTable with more than one resource are not yet supported. \n" - + "See VOTable file for more informations: " + voTablePath); - } - } - - /** Can not change schema location on the VOTable file. */ - public static class CantModifyVOTableException extends CantDisplayVOTableException { - - /** */ - private static final long serialVersionUID = 1L; - - - /** - * @param voTablePath The path of the VOTable. - * @param e The exception thrown. - */ - public CantModifyVOTableException(String voTablePath, Exception e) { - super("Can not change schema location on the VOTable file: " + voTablePath, e); - } - } - - /** There is an error in the VOTable. */ - public static class ErrorMessageInVOTableException extends CantDisplayVOTableException { - - /** */ - private static final long serialVersionUID = 1L; - - - /** - * @param errorInfo The information about the error, which comes from the VOTable itself - * from the "INFO" node. - */ - public ErrorMessageInVOTableException(String errorInfo) { - super("There is an error in the VOTable:\n" + errorInfo - + "\nPlease check your ADQL query."); - } - } - } - -} diff --git a/src/main/java/eu/omp/irap/vespa/epntapclient/votable/data/VOTableDataCtrl.java b/src/main/java/eu/omp/irap/vespa/epntapclient/votable/data/VOTableDataCtrl.java new file mode 100644 index 0000000..a47d892 --- /dev/null +++ b/src/main/java/eu/omp/irap/vespa/epntapclient/votable/data/VOTableDataCtrl.java @@ -0,0 +1,298 @@ +/* + * This file is a part of EpnTAPClient. + * This program aims to provide EPN-TAP support for software clients, like CASSIS spectrum analyzer. + * See draft specifications: https://voparis-confluence.obspm.fr/pages/viewpage.action?pageId=559861 + * Copyright (C) 2016 Institut de Recherche en Astrophysique et Planétologie. + * + * This program is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or (at your option) any later + * version. This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. You should have received a copy of + * the GNU General Public License along with this program. If not, see + * . + */ + +package eu.omp.irap.vespa.epntapclient.votable.controller; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import javax.xml.bind.DatatypeConverter; + +import com.google.gson.Gson; + +import eu.omp.irap.vespa.epntapclient.votable.model.DataType; +import eu.omp.irap.vespa.epntapclient.votable.model.Field; +import eu.omp.irap.vespa.epntapclient.votable.model.Stream; +import eu.omp.irap.vespa.epntapclient.votable.model.Table; +import eu.omp.irap.vespa.epntapclient.votable.model.TableData; +import eu.omp.irap.vespa.epntapclient.votable.utils.Debug; + +/** + * @author N. Jourdane + */ +public class VOTableDataParser { + + /** The logger for the class VOTableDataParser. */ + private static final Logger logger = Logger.getLogger(VOTableDataParser.class.getName()); + + /** + * A list of arrays, representing data stored in the VOTable. Each element is a VOTable row, + * where arrays elements are in the same order as `columnNames`. + */ + private List data; + + /** The name of the columns. `columnNames` length is equals to `data` length */ + private String[] columnsName; + + /** The byte array stored in the VOTable Table stream (if any). */ + private ByteBuffer stream; + + /** The index of the current position in the bytes array. */ + private int cursor; + + + /** + * In VOTables, data can be stored in 4 different serializations: BINARY, BINARY2, TABLEDATA and + * FITS. This class aims to provide a unique way to get the data table, regardless of its + * serialization type. + * + * @param table The table on which we want get the data. + * @throws IOException If the VOTable data can not be parsed. + */ + public VOTableDataParser(Table table) throws IOException { + cursor = 0; + + List fields = new ArrayList<>(); + for (Object obj : table.getFIELDOrPARAMOrGROUP()) { + if (obj.getClass() == Field.class) { + fields.add((Field) obj); + } + } + columnsName = new String[fields.size()]; + for (int i = 0; i < fields.size(); i++) { + columnsName[i] = fields.get(i).getName(); + } + VOTableDataParser.logger.info("Columns name: " + new Gson().toJson(columnsName)); + + data = new ArrayList<>(); + + if (table.getDATA().getBINARY() != null) { + parseBinaryStream(table.getDATA().getBINARY().getSTREAM(), fields); + } else if (table.getDATA().getBINARY2() != null) { + VOTableDataParser.parseBinary2Stream(table.getDATA().getBINARY2().getSTREAM(), fields); + } else if (table.getDATA().getTABLEDATA() != null) { + VOTableDataParser.parseTableDataStream(table.getDATA().getTABLEDATA(), fields); + } else if (table.getDATA().getFITS() != null) { + VOTableDataParser.parseFITSStream(table.getDATA().getFITS().getSTREAM(), fields); + } + + Debug.printObject("voTableData", data); + } + + /** + * @return the data stored in the Table. + */ + public List getDataArray() { + return data; + } + + /** + * @return An array of Table fields name. + */ + public String[] getColumnsName() { + return columnsName; + } + + /** + * @param column The name of the column to get. + * @return An array of Table fields name. + * @throws IllegalArgumentException Column name not found in the table. + */ + public int getColumnIndex(String column) { + int i = 0; + while (!column.equals(columnsName[i])) { + i++; + if (i > columnsName.length) { + throw new IllegalArgumentException("Column " + column + " not found in the table."); + } + } + return i; + } + + /** + * @return The number of rows in the Table. + */ + public int getNbRows() { + return data.size(); + } + + /** + * @return The number of columns in the Table. + */ + public int getNbColumns() { + return columnsName.length; + } + + /** + * @param rowIndex The index of the row to get. + * @return The Table row at the specified index. + */ + public Object[] getRowByIndex(int rowIndex) { + return data.get(rowIndex); + } + + /** + * @param rowIndex The index of the row to get. + * @return A dictionary representing the row, where each key is a column name. + */ + public Map getDicRowByIndex(int rowIndex) { + Map row = new HashMap<>(); + for (int i = 0; i < columnsName.length; i++) { + row.put(columnsName[i], data.get(rowIndex)[i]); + } + return row; + } + + /** + * @param columnIndex A UNIQUE column (as SQL sense) to identify a row. + * @param value The value at `columnName`, in order to get the full row. + * @return A Table row, identified by a unique `value` in the `columnName` column. + * @throws IndexOutOfBoundsException If the value is not found at the specified column. + */ + public Object[] getRowByValue(int columnIndex, Object value) { + for (Object[] row : data) { + if (value.equals(row[columnIndex])) { + return row; + } + } + throw new IndexOutOfBoundsException( + "The value " + value + " is not found on the table at the column " + columnIndex); + } + + /** + * get the data on its BINARY form. + * + * @param voStream the data Stream in the VOTable Table. + * @param fields The Fields corresponding to the Table. + * @throws UnsupportedOperationException Data as arrays are not supported yet. + */ + private void parseBinaryStream(Stream voStream, List fields) { + VOTableDataParser.logger.info("Parsing data in BINARY stream..."); + String strStream = voStream.getValue().replaceAll("(\\r|\\n)", ""); + + stream = ByteBuffer.wrap(DatatypeConverter.parseBase64Binary(strStream)); + Object[] row = new Object[columnsName.length]; + + int nValue = 0; + while (stream.hasRemaining()) { + int nColumn = nValue % columnsName.length; + Field column = fields.get(nColumn); + DataType dataType = column.getDatatype(); + + //@noformat + int blockSize = + dataType.equals(DataType.BOOLEAN) ? 1 : + dataType.equals(DataType.UNSIGNED_BYTE) ? 1 : + dataType.equals(DataType.SHORT) ? 2 : + dataType.equals(DataType.INT) ? 4 : + dataType.equals(DataType.LONG) ? 8 : + dataType.equals(DataType.CHAR) ? 1 : + dataType.equals(DataType.UNICODE_CHAR) ? 2 : + dataType.equals(DataType.FLOAT) ? 4 : + dataType.equals(DataType.DOUBLE) ? 8 : + dataType.equals(DataType.FLOAT_COMPLEX) ? 8 : + dataType.equals(DataType.DOUBLE_COMPLEX) ? 16 : 0; + //@format + + int arraySize; + if (column.getArraysize() == null) { + arraySize = blockSize; + } else if ("*".equals(column.getArraysize())) { + arraySize = stream.getInt() * blockSize; + } else { + arraySize = Integer.parseInt(column.getArraysize()) * blockSize; + } + if (arraySize != blockSize && !(dataType.equals(DataType.CHAR) + || dataType.equals(DataType.UNICODE_CHAR))) { + throw new UnsupportedOperationException("Numeric data as array are not supported."); + } + + if (nColumn == 0) { + row = new Object[columnsName.length]; + } + + if (dataType.equals(DataType.BOOLEAN)) { + row[nColumn] = new Boolean(stream.getInt() == 0 ? false : true); + } else if (dataType.equals(DataType.UNSIGNED_BYTE)) { + row[nColumn] = stream.get(); + } else if (dataType.equals(DataType.SHORT)) { + row[nColumn] = stream.getShort(); + } else if (dataType.equals(DataType.INT)) { + row[nColumn] = stream.getInt(); + } else if (dataType.equals(DataType.LONG)) { + row[nColumn] = stream.getLong(); + } else if (dataType.equals(DataType.CHAR)) { + String value = new String(); + for (int i = 0; i < arraySize && cursor < stream.capacity(); i++) { + value += (char) stream.get(); + } + row[nColumn] = value.trim(); + } else if (dataType.equals(DataType.UNICODE_CHAR)) { + String value = new String(); + for (int i = 0; i < arraySize && cursor < stream.capacity(); i += 2) { + value += stream.getChar(); + } + row[nColumn] = value.trim(); + } else if (dataType.equals(DataType.FLOAT)) { + float value = stream.getFloat(); + row[nColumn] = Float.isNaN(value) ? null : value; + } else if (dataType.equals(DataType.DOUBLE)) { + double value = stream.getDouble(); + row[nColumn] = Double.isNaN(value) ? null : value; + } else { + VOTableDataParser.logger.warning("Data type " + dataType + " is not supported."); + } + + // logger.debug(columnsName[nColumn] + ": " + row[nColumn]) + + row[nColumn] = row[nColumn]; + if (nColumn == columnsName.length - 1) { + data.add(row); + } + nValue++; + } + + } + + /** + * @param stream the data Stream in the VOTable Table. + * @param fields The Fields corresponding to the Table. + */ + private static void parseBinary2Stream(Stream stream, List fields) { + VOTableDataParser.logger.info("Parsing data in BINARY2 stream..."); + } + + /** + * @param tabledata the TableData of the VOTable Table. + * @param fields The Fields corresponding to the Table. + */ + private static void parseTableDataStream(TableData tabledata, List fields) { + VOTableDataParser.logger.info("Parsing data in TABLEDATA stream..."); + } + + /** + * @param stream the data Stream in the VOTable Table. + * @param fields The Fields corresponding to the Table. + */ + private static void parseFITSStream(Stream stream, List fields) { + VOTableDataParser.logger.info("Parsing data in FITS stream..."); + } +} diff --git a/src/main/java/eu/omp/irap/vespa/epntapclient/votable/utils/Consts.java b/src/main/java/eu/omp/irap/vespa/epntapclient/votable/utils/Consts.java deleted file mode 100644 index 2bf2c1c..0000000 --- a/src/main/java/eu/omp/irap/vespa/epntapclient/votable/utils/Consts.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is a part of EpnTAPClient. - * This program aims to provide EPN-TAP support for software clients, like CASSIS spectrum analyzer. - * See draft specifications: https://voparis-confluence.obspm.fr/pages/viewpage.action?pageId=559861 - * Copyright (C) 2016 Institut de Recherche en Astrophysique et Planétologie. - * - * This program is free software: you can - * redistribute it and/or modify it under the terms of the GNU General Public License as published - * by the Free Software Foundation, either version 3 of the License, or (at your option) any later - * version. This program is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. You should have received a copy of - * the GNU General Public License along with this program. If not, see - * . - */ - -package eu.omp.irap.vespa.epntapclient.votable.utils; - -/** - * This class defines widely-used constants. - * - * @author N. Jourdane - */ -public class Consts { - - /** The character set used (for http requests, writing in files, etc.). */ - public static final String ENCODING = "UTF-8"; - - /** The temporary directory path. */ - public static final String TMP_DIR = System.getProperty("java.io.tmpdir"); - - /** The URL of the registry used by default to get the services. */ - public static final String DEFAULT_REGISTRY_URL = "http://gavo.aip.de/tap"; - // http://reg.g-vo.org/tap - // http://dc.zah.uni-heidelberg.de/tap - // http://gavo.aip.de/tap - // http://voparis-cdpp.obspm.fr/tap - - public static final String QUERY_LANG = "ADQL"; - - public static final String QUERY_REQUEST = "doQuery"; - - public static final String QUERY_FORMAT = "votable"; - - - /** Constructor to hide the implicit public one. */ - private Consts() { - } -} -- libgit2 0.21.2