Commit 74010bdb0038652bc9c2a58fe15b81fdbc9891d9

Authored by Nathanael Jourdane
1 parent b549442f
Exists in master

Add the VOTable data parser.

src/main/java/eu/omp/irap/vespa/epntapclient/votable/controller/VOTableDataParser.java 0 → 100644
@@ -0,0 +1,231 @@ @@ -0,0 +1,231 @@
  1 +/**
  2 + * This file is a part of EpnTAPClient.
  3 + * This program aims to provide EPN-TAP support for software clients, like CASSIS spectrum analyzer.
  4 + * See draft specifications: https://voparis-confluence.obspm.fr/pages/viewpage.action?pageId=559861
  5 + * Copyright (C) 2016 Institut de Recherche en Astrophysique et Planétologie.
  6 + *
  7 + * This program is free software: you can
  8 + * redistribute it and/or modify it under the terms of the GNU General Public License as published
  9 + * by the Free Software Foundation, either version 3 of the License, or (at your option) any later
  10 + * version. This program is distributed in the hope that it will be useful, but WITHOUT ANY
  11 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  12 + * PURPOSE. See the GNU General Public License for more details. You should have received a copy of
  13 + * the GNU General Public License along with this program. If not, see
  14 + * <http://www.gnu.org/licenses/>.
  15 + */
  16 +package eu.omp.irap.vespa.epntapclient.votable.controller;
  17 +
  18 +import java.util.ArrayList;
  19 +import java.util.Base64;
  20 +import java.util.List;
  21 +import java.util.Vector;
  22 +
  23 +import com.google.gson.Gson;
  24 +
  25 +import eu.omp.irap.vespa.epntapclient.utils.Log;
  26 +import eu.omp.irap.vespa.epntapclient.votable.model.DataType;
  27 +import eu.omp.irap.vespa.epntapclient.votable.model.Field;
  28 +import eu.omp.irap.vespa.epntapclient.votable.model.Stream;
  29 +import eu.omp.irap.vespa.epntapclient.votable.model.Table;
  30 +import eu.omp.irap.vespa.epntapclient.votable.model.TableData;
  31 +
  32 +/**
  33 + * @author N. Jourdane
  34 + */
  35 +public class VOTableDataParser {
  36 +
  37 + /**
  38 + * A list of arrays, representing data stored in the VOTable. Each element is a VOTable row,
  39 + * where arrays elements are in the same order as `columnNames`.
  40 + */
  41 + private Vector<Object[]> data;
  42 +
  43 + /** The name of the columns. `columnNames` length is equals to `data` length */
  44 + private String[] columnsName;
  45 +
  46 + /** The byte array stored in the VOTable Table stream (if any). */
  47 + byte[] bytes;
  48 +
  49 + /** The index of the current position in the bytes array. */
  50 + private int cursor;
  51 +
  52 + /**
  53 + * In VOTables, data can be stored in 4 different serializations: BINARY, BINARY2, TABLEDATA and
  54 + * FITS. This class aims to provide a unique way to get the data table, regardless of its
  55 + * serialization type.
  56 + *
  57 + * @param table The table on which we want get the data.
  58 + * @throws Exception If the VOTable data can not be parsed.
  59 + */
  60 + public VOTableDataParser(Table table) throws Exception {
  61 + cursor = 0;
  62 +
  63 + List<Field> fields = new ArrayList<>();
  64 + for (Object obj : table.getFIELDOrPARAMOrGROUP()) {
  65 + if (obj.getClass() == Field.class) {
  66 + fields.add((Field) obj);
  67 + }
  68 + }
  69 + columnsName = new String[fields.size()];
  70 + for (int i = 0; i < fields.size(); i++) {
  71 + columnsName[i] = fields.get(i).getName();
  72 + }
  73 + Log.LOGGER.info("Columns name: \n " + new Gson().toJson(columnsName));
  74 +
  75 + data = new Vector<>();
  76 +
  77 + if (table.getDATA().getBINARY() != null) {
  78 + parseBinaryStream(table.getDATA().getBINARY().getSTREAM(), fields);
  79 + } else if (table.getDATA().getBINARY2() != null) {
  80 + parseBinary2Stream(table.getDATA().getBINARY2().getSTREAM(), fields);
  81 + } else if (table.getDATA().getTABLEDATA() != null) {
  82 + parseTableDataStream(table.getDATA().getTABLEDATA(), fields);
  83 + } else if (table.getDATA().getFITS() != null) {
  84 + parseFITSStream(table.getDATA().getFITS().getSTREAM(), fields);
  85 + }
  86 +
  87 + String logPath = Log.printObject(data);
  88 + Log.LOGGER.info("A json file representing the VOTable data has been created on " + logPath);
  89 + }
  90 +
  91 + /**
  92 + * @return the data stored in the VOTable.
  93 + */
  94 + public List<Object[]> getDataArray() {
  95 + return data;
  96 + }
  97 +
  98 + /**
  99 + * @return An array of VOTable fields name.
  100 + */
  101 + public String[] getColumnsName() {
  102 + return columnsName;
  103 + }
  104 +
  105 + /**
  106 + * get the data on its BINARY form.
  107 + *
  108 + * @param stream the data Stream in the VOTable Table.
  109 + * @param fields The Fields corresponding to the Table.
  110 + * @throws Exception If a value in the VOTable data is a array (except strings).
  111 + */
  112 + private void parseBinaryStream(Stream stream, List<Field> fields) throws Exception {
  113 + Log.LOGGER.info("Parsing data in BINARY stream...");
  114 + String strStream = stream.getValue().replaceAll("(\\r|\\n)", "");
  115 + Log.clearFile();
  116 +
  117 + bytes = Base64.getDecoder().decode(strStream);
  118 + Object[] row = new Object[columnsName.length];
  119 +
  120 + // System.out.println(strStream + " = " + new Gson().toJson(byteArray));
  121 +
  122 + Log.clearFile();
  123 + for (int nValue = 0; cursor < bytes.length; nValue++) {
  124 + int nColumn = nValue % columnsName.length;
  125 + Field column = fields.get(nColumn);
  126 + DataType dataType = column.getDatatype();
  127 +
  128 + //@noformat
  129 + int blockSize =
  130 + dataType.equals(DataType.BOOLEAN) ? 1 :
  131 + dataType.equals(DataType.UNSIGNED_BYTE) ? 1 :
  132 + dataType.equals(DataType.SHORT) ? 2 :
  133 + dataType.equals(DataType.INT) ? 4 :
  134 + dataType.equals(DataType.LONG) ? 8 :
  135 + dataType.equals(DataType.CHAR) ? 1 :
  136 + dataType.equals(DataType.UNICODE_CHAR) ? 2 :
  137 + dataType.equals(DataType.FLOAT) ? 4 :
  138 + dataType.equals(DataType.DOUBLE) ? 8 :
  139 + dataType.equals(DataType.FLOAT_COMPLEX) ? 8 :
  140 + dataType.equals(DataType.DOUBLE_COMPLEX) ? 16 : 0;
  141 + //@format
  142 +
  143 + int arraySize;
  144 + if (column.getArraysize() == null) {
  145 + arraySize = blockSize;
  146 + } else if (column.getArraysize().equals("*")) {
  147 + arraySize = getValue(4) * blockSize;
  148 + } else {
  149 + arraySize = Integer.parseInt(column.getArraysize()) * blockSize;
  150 + }
  151 +
  152 + if ((arraySize != blockSize) && !(dataType.equals(DataType.CHAR)
  153 + || dataType.equals(DataType.UNICODE_CHAR))) {
  154 + throw new Exception("Data values as arrays are not supported yet.");
  155 + }
  156 +
  157 + if (nColumn == 0) {
  158 + row = new Object[columnsName.length];
  159 + }
  160 +
  161 + if (dataType.equals(DataType.CHAR) || dataType.equals(DataType.UNICODE_CHAR)) {
  162 + String value = "";
  163 + for (int i = 0; i < arraySize && cursor < bytes.length; i += blockSize) {
  164 + value += (char) getValue(blockSize);
  165 + }
  166 + row[nColumn] = value.trim();
  167 + } else if (dataType.equals(DataType.BOOLEAN) || dataType.equals(DataType.BIT)) {
  168 + row[nColumn] = new Boolean(getValue(blockSize) == 0 ? false : true);
  169 + } else if (dataType.equals(DataType.UNSIGNED_BYTE) || dataType.equals(DataType.SHORT)) {
  170 + row[nColumn] = new Short((short) getValue(blockSize));
  171 + } else if (dataType.equals(DataType.INT)) {
  172 + row[nColumn] = new Integer(getValue(blockSize));
  173 + } else if (dataType.equals(DataType.LONG)) {
  174 + row[nColumn] = new Long(getValue(blockSize));
  175 + } else { // float
  176 + row[nColumn] = new Float(getValue(blockSize));
  177 + }
  178 +
  179 + Log.logInFile("**" + columnsName[nColumn] + "**: " + row[nColumn]);
  180 +
  181 + row[nColumn] = row[nColumn];
  182 + if (nColumn == columnsName.length - 1) {
  183 + data.add(row);
  184 + }
  185 + }
  186 +
  187 + }
  188 +
  189 + /**
  190 + * @param stream the data Stream in the VOTable Table.
  191 + * @param fields The Fields corresponding to the Table.
  192 + */
  193 + private static void parseBinary2Stream(Stream stream, List<Field> fields) {
  194 + Log.LOGGER.info("Parsing data in BINARY2 stream...");
  195 + // TODO Implémenter parseBinary2Stream()
  196 + }
  197 +
  198 + /**
  199 + * @param tabledata the TableData of the VOTable Table.
  200 + * @param fields The Fields corresponding to the Table.
  201 + */
  202 + private static void parseTableDataStream(TableData tabledata, List<Field> fields) {
  203 + Log.LOGGER.info("Parsing data in TABLEDATA stream...");
  204 + // TODO Implémenter parseTableDataStream()
  205 + }
  206 +
  207 + /**
  208 + * @param stream the data Stream in the VOTable Table.
  209 + * @param fields The Fields corresponding to the Table.
  210 + */
  211 + private static void parseFITSStream(Stream stream, List<Field> fields) {
  212 + Log.LOGGER.info("Parsing data in FITS stream...");
  213 + // TODO Implémenter parseFITSStream()
  214 + }
  215 +
  216 + /**
  217 + * Get the integer value of a bytes block. For example, [0x01, 0x05] returns 230, and increment
  218 + * the cursor.
  219 + *
  220 + * @param blockSize The size of the bytes block to get
  221 + * @return The integer value of the bytes block.
  222 + */
  223 + private int getValue(int blockSize) {
  224 + int intVal = 0;
  225 + for (int i = 0; i < blockSize; i++) {
  226 + intVal += 0xFF & (bytes[cursor + i] << ((blockSize - 1 - i) * 8));
  227 + }
  228 + cursor += blockSize;
  229 + return intVal;
  230 + }
  231 +}