TAPServices.java 5.51 KB
/**
 * 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
 * <http://www.gnu.org/licenses/>.
 */

package eu.omp.irap.vespa.epntapclient.controller;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.logging.Level;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import com.google.gson.Gson;

import eu.omp.irap.vespa.epntapclient.model.TAPField;
import eu.omp.irap.vespa.epntapclient.model.TAPService;
import eu.omp.irap.vespa.epntapclient.model.VOTableTags;
import eu.omp.irap.vespa.epntapclient.utils.Const;
import eu.omp.irap.vespa.epntapclient.utils.Err;
import eu.omp.irap.vespa.epntapclient.utils.Log;

/**
 * This class provide methods to get and use TAP services.
 * 
 * @author N. Jourdane
 **/
public class TAPServices {
	/** The list of all fields (ie. columns VOTABLE). */
	private List<TAPField> fields;

	/** The list of all services returned by the query. */
	private List<TAPService> tapServices;

	/** The byte array representation of the stream data stored in the XML document. */
	private byte[] byteArray;

	/**
	 * Method constructor
	 * 
	 * @param xmlFileName The name of XML file to parse in order to get the list of services.
	 */
	public TAPServices(String xmlFileName) {

		// Get document
		Document doc = null;
		try {
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
			doc = dBuilder.parse(new File(xmlFileName));
			doc.getDocumentElement().normalize();
		} catch (FileNotFoundException e1) {
			Log.LOGGER.log(Level.SEVERE, Err.NOT_FOUND + xmlFileName, e1);
			return;
		} catch (Exception e2) {
			Log.LOGGER.log(Level.SEVERE, Err.BAD_XML_DOC + xmlFileName, e2);
			return;
		}

		// Get fields
		NodeList nodeList = doc.getElementsByTagName(VOTableTags.TAG_NAME_FIELD);
		fields = new ArrayList<>();
		for (int i = 0; i < nodeList.getLength(); i++) {
			fields.add(new TAPField(nodeList.item(i)));
		}

		// Get byte array
		String stream = doc.getElementsByTagName(VOTableTags.TAG_NAME_STREAM).item(0)
				.getTextContent()
				.replaceAll("(\\r|\\n)", ""); //$NON-NLS-1$ //$NON-NLS-2$
		byteArray = Base64.getDecoder().decode(stream);
	}

	/**
	 * Fill the services list from the byte array.
	 */
	public void fillServices() {
		List<TAPService> services = new ArrayList<>();
		TAPService service = new TAPService();

		for (int cursor = 0, nValue = 0; cursor < byteArray.length; nValue++) {
			TAPField column = fields.get(nValue % fields.size());
			Object value = null;

			if (column.getDatatype().equals(VOTableTags.SHORT_TYPE)) {
				byte[] shortArray = { byteArray[cursor + 0], byteArray[cursor + 1] };
				value = Integer.valueOf(shortArray[0] * (2 ^ 8) + shortArray[1]);
				cursor += shortArray.length;
			} else {
				byte[] head = { byteArray[cursor + 0], byteArray[cursor + 1], byteArray[cursor + 2],
						byteArray[cursor + 3] };
				int charSize = column.getDatatype().equals(VOTableTags.UNICODE_CHAR_TYPE) ? 2 : 1;
				int stringLength = ByteBuffer.wrap(head).getInt() * charSize;
				cursor += head.length;

				value = new String();
				for (int j = 0; j < stringLength
						&& cursor < byteArray.length; cursor += charSize, j += charSize) {
					int c = (0xFF) & (charSize == 2
							? (int) (byteArray[cursor] * (2 ^ 8) + byteArray[cursor + 1])
							: byteArray[cursor]);
					value = value + Character.toString((char) c);
				}
			}

			if (nValue % fields.size() == 0) {
				service = new TAPService();
			} else if (nValue % fields.size() == fields.size() - 1) {
				services.add(service);
			} else {
				service.setProperty(column.getName(), value);
			}
		}

		tapServices = services;
	}

	/**
	 * @return The list of services.
	 */
	public List<TAPService> getServices() {
		return tapServices;
	}

	/**
	 * @return The list of VOTable columns.
	 */
	public List<TAPField> getFileds() {
		return fields;
	}

	/**
	 * Print the content of all the services in the specified file in JSON format.
	 * 
	 * @param fileName The name of the file where the services lists is printed.
	 */
	public void printToFile(String fileName) {
		PrintWriter writer;
		String json = new Gson().toJson(tapServices);
		try {
			writer = new PrintWriter(fileName, Const.CHARACTER_SET);
			writer.println(json);
			writer.close();
		} catch (FileNotFoundException e1) {
			Log.LOGGER.log(Level.SEVERE, Err.NOT_FOUND, e1);
		} catch (UnsupportedEncodingException e2) {
			Log.LOGGER.log(Level.SEVERE, Err.WRONG_ENCODING, e2);
		}
	}
}