From acb62b0b60017cb2a0c1c6cf5e308714bfc0d75f Mon Sep 17 00:00:00 2001 From: gmantele <gmantele@ari.uni-heidelberg.de> Date: Thu, 2 Oct 2014 19:08:15 +0200 Subject: [PATCH] [TAP] Add FITS as output format. --- src/tap/formatter/FITSFormat.java | 125 +++++++++++++++++++++++++++ src/tap/formatter/VOTableFormat.java | 8 +- 2 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 src/tap/formatter/FITSFormat.java diff --git a/src/tap/formatter/FITSFormat.java b/src/tap/formatter/FITSFormat.java new file mode 100644 index 0000000..42bf9fc --- /dev/null +++ b/src/tap/formatter/FITSFormat.java @@ -0,0 +1,125 @@ +package tap.formatter; + +/* + * This file is part of TAPLibrary. + * + * TAPLibrary is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * TAPLibrary 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with TAPLibrary. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2014 - Astronomisches Rechen Institut (ARI) + */ + +import java.io.IOException; +import java.io.OutputStream; + +import tap.ServiceConnection; +import tap.TAPException; +import tap.TAPExecutionReport; +import tap.data.TableIterator; +import tap.formatter.VOTableFormat.LimitedStarTable; +import uk.ac.starlink.fits.FitsTableWriter; +import uk.ac.starlink.table.ColumnInfo; +import uk.ac.starlink.table.StarTable; +import uk.ac.starlink.table.StoragePolicy; +import uws.service.log.UWSLog.LogLevel; + +/** + * Format any given query (table) result into FITS. + * + * @author Grégory Mantelet (ARI) + * @version 2.0 (10/2014) + * @since 2.0 + */ +public class FITSFormat implements OutputFormat { + + /** Indicates whether a format report (start and end date/time) must be printed in the log output. */ + private boolean logFormatReport; + + /** The {@link ServiceConnection} to use (for the log and to have some information about the service (particularly: name, description). */ + protected final ServiceConnection service; + + /** + * Creates a FITS formatter. + * + * @param service The service to use (for the log and to have some information about the service (particularly: name, description). + * + * @throws NullPointerException If the given service connection is <code>null</code>. + */ + public FITSFormat(final ServiceConnection service) throws NullPointerException{ + this(service, true); + } + + /** + * Creates a FITS formatter. + * + * @param service The service to use (for the log and to have some information about the service (particularly: name, description). + * @param logFormatReport <code>true</code> to append a format report (start and end date/time) in the log output, <code>false</code> otherwise. + * + * @throws NullPointerException If the given service connection is <code>null</code>. + */ + public FITSFormat(final ServiceConnection service, final boolean logFormatReport) throws NullPointerException{ + if (service == null) + throw new NullPointerException("The given service connection is NULL !"); + + this.service = service; + this.logFormatReport = logFormatReport; + } + + @Override + public String getMimeType(){ + return "application/fits"; + } + + @Override + public String getShortMimeType(){ + return "fits"; + } + + @Override + public String getDescription(){ + return null; + } + + @Override + public String getFileExtension(){ + return "fits"; + } + + @Override + public void writeResult(TableIterator result, OutputStream output, TAPExecutionReport execReport, Thread thread) throws TAPException, InterruptedException{ + try{ + long start = System.currentTimeMillis(); + + // Extract the columns' metadata: + ColumnInfo[] colInfos = VOTableFormat.toColumnInfos(result, execReport, thread); + + // Turns the result set into a table: + LimitedStarTable table = new LimitedStarTable(result, colInfos, execReport.parameters.getMaxRec()); + + // Copy the table on disk (or in memory if the table is short): + StarTable copyTable = StoragePolicy.PREFER_DISK.copyTable(table); + + /* Format the table in FITS (2 passes are needed for that, hence the copy on disk), + * and write it in the given output stream: */ + new FitsTableWriter().writeStarTable(copyTable, output); + + output.flush(); + + if (logFormatReport) + service.getLogger().logTAP(LogLevel.INFO, execReport, "FORMAT", "Result formatted (in FITS ; " + table.getNbReadRows() + " rows ; " + table.getColumnCount() + " columns) in " + (System.currentTimeMillis() - start) + "ms!", null); + }catch(IOException ioe){ + throw new TAPException("Error while writing a query result in FITS!", ioe); + } + } + +} diff --git a/src/tap/formatter/VOTableFormat.java b/src/tap/formatter/VOTableFormat.java index 0a34f6a..a1beb23 100644 --- a/src/tap/formatter/VOTableFormat.java +++ b/src/tap/formatter/VOTableFormat.java @@ -444,7 +444,7 @@ public class VOTableFormat implements OutputFormat { * @throws TAPException If there is any other error. * @throws InterruptedException If the given thread has been interrupted. */ - protected ColumnInfo[] toColumnInfos(final TableIterator result, final TAPExecutionReport execReport, final Thread thread) throws IOException, TAPException, InterruptedException{ + public static final ColumnInfo[] toColumnInfos(final TableIterator result, final TAPExecutionReport execReport, final Thread thread) throws IOException, TAPException, InterruptedException{ // Get the metadata extracted/guesses from the ADQL query: DBColumn[] columnsFromQuery = execReport.resultingColumns; @@ -486,7 +486,7 @@ public class VOTableFormat implements OutputFormat { * * @return The most appropriate metadata. */ - protected final TAPColumn getValidColMeta(final DBColumn typeFromQuery, final TAPColumn typeFromResult){ + protected static final TAPColumn getValidColMeta(final DBColumn typeFromQuery, final TAPColumn typeFromResult){ if (typeFromQuery != null && typeFromQuery instanceof TAPColumn) return (TAPColumn)typeFromQuery; else if (typeFromResult != null){ @@ -505,7 +505,7 @@ public class VOTableFormat implements OutputFormat { * * @return The corresponding {@link ColumnInfo}. */ - protected ColumnInfo getColumnInfo(final TAPColumn tapCol){ + protected static final ColumnInfo getColumnInfo(final TAPColumn tapCol){ // Get the VOTable type: VotType votType = tapCol.getDatatype().toVotType(); @@ -613,7 +613,7 @@ public class VOTableFormat implements OutputFormat { * @version 2.0 (10/2014) * @since 2.0 */ - private static class LimitedStarTable extends AbstractStarTable { + public static class LimitedStarTable extends AbstractStarTable { /** Number of columns to read. */ private final int nbCol; -- GitLab