Commit d708278c authored by gmantele's avatar gmantele
Browse files

[TAP] Add the possibility to wrap a TAPMetadata instance created automatically

by the TAP configuration file in order to add/remove/change some metadata or
to change the output of the TAP resource '/tables'.
parent f8978304
Loading
Loading
Loading
Loading
+51 −3
Original line number Diff line number Diff line
@@ -124,7 +124,7 @@ import adql.query.operand.function.UserDefinedFunction;
 * </p>
 * 
 * @author Gr&eacute;gory Mantelet (ARI)
 * @version 2.0 (04/2015)
 * @version 2.1 (10/2015)
 * @since 2.0
 */
public final class ConfigurableServiceConnection implements ServiceConnection {
@@ -435,7 +435,19 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
		// Get the fetching method to use:
		String metaFetchType = getProperty(tapConfig, KEY_METADATA);
		if (metaFetchType == null)
			throw new TAPException("The property \"" + KEY_METADATA + "\" is missing! It is required to create a TAP Service. Three possible values: " + VALUE_XML + " (to get metadata from a TableSet XML document), " + VALUE_DB + " (to fetch metadata from the database schema TAP_SCHEMA) or the name (between {}) of a class extending TAPMetadata.");
			throw new TAPException("The property \"" + KEY_METADATA + "\" is missing! It is required to create a TAP Service. Three possible values: " + VALUE_XML + " (to get metadata from a TableSet XML document), " + VALUE_DB + " (to fetch metadata from the database schema TAP_SCHEMA) or the name (between {}) of a class extending TAPMetadata. Only " + VALUE_XML + " and " + VALUE_DB + " can be followed by the path of a class extending TAPMetadata.");

		// Extract a custom class suffix if any for XML and DB options:
		String customMetaClass = null;
		if (metaFetchType.toLowerCase().matches("(" + VALUE_XML + "|" + VALUE_DB + ").*")){
			int indSep = metaFetchType.toLowerCase().startsWith(VALUE_XML) ? 3 : 2;
			customMetaClass = metaFetchType.substring(indSep).trim();
			metaFetchType = metaFetchType.substring(0, indSep);
			if (customMetaClass.length() == 0)
				customMetaClass = null;
			else if (!isClassName(customMetaClass))
				throw new TAPException("Unexpected string after the fetching method \"" + metaFetchType + "\": \"" + customMetaClass + "\"! The full name of a class extending TAPMetadata was expected. If it is a class name, then it must be specified between {}.");
		}

		TAPMetadata metadata = null;

@@ -522,7 +534,43 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
		}
		// INCORRECT VALUE => ERROR!
		else
			throw new TAPException("Unsupported value for the property \"" + KEY_METADATA + "\": \"" + metaFetchType + "\"! Only two values are allowed: " + VALUE_XML + " (to get metadata from a TableSet XML document) or " + VALUE_DB + " (to fetch metadata from the database schema TAP_SCHEMA).");
			throw new TAPException("Unsupported value for the property \"" + KEY_METADATA + "\": \"" + metaFetchType + "\"! Only two values are allowed: " + VALUE_XML + " (to get metadata from a TableSet XML document) or " + VALUE_DB + " (to fetch metadata from the database schema TAP_SCHEMA). Only " + VALUE_XML + " and " + VALUE_DB + " can be followed by the path of a class extending TAPMetadata.");

		// Create the custom TAPMetadata extension if any is provided (THEORETICALLY, JUST FOR XML and DB):
		if (customMetaClass != null){
			// get the class:
			Class<? extends TAPMetadata> metaClass = fetchClass(customMetaClass, KEY_METADATA, TAPMetadata.class);
			if (metaClass == TAPMetadata.class)
				throw new TAPException("Wrong class for the property \"" + KEY_METADATA + "\": \"" + metaClass.getName() + "\"! The class provided in this property MUST EXTEND tap.metadata.TAPMetadata.");
			try{
				// get one of the expected constructors:
				try{
					// (TAPMetadata, UWSFileManager, TAPFactory, TAPLog):
					Constructor<? extends TAPMetadata> constructor = metaClass.getConstructor(TAPMetadata.class, UWSFileManager.class, TAPFactory.class, TAPLog.class);
					// create the TAP metadata:
					metadata = constructor.newInstance(metadata, fileManager, tapFactory, logger);
				}catch(NoSuchMethodException nsme){
					// (TAPMetadata):
					Constructor<? extends TAPMetadata> constructor = metaClass.getConstructor(TAPMetadata.class);
					// create the TAP metadata:
					metadata = constructor.newInstance(metadata);
				}
			}catch(NoSuchMethodException nsme){
				throw new TAPException("Missing constructor by copy tap.metadata.TAPMetadata(tap.metadata.TAPMetadata) or tap.metadata.TAPMetadata(tap.metadata.TAPMetadata, uws.service.file.UWSFileManager, tap.TAPFactory, tap.log.TAPLog)! See the value \"" + metaFetchType + "\" of the property \"" + KEY_METADATA + "\".");
			}catch(InstantiationException ie){
				throw new TAPException("Impossible to create an instance of an abstract class: \"" + metaClass.getName() + "\"! See the value \"" + metaFetchType + "\" of the property \"" + KEY_METADATA + "\".");
			}catch(InvocationTargetException ite){
				if (ite.getCause() != null){
					if (ite.getCause() instanceof TAPException)
						throw (TAPException)ite.getCause();
					else
						throw new TAPException(ite.getCause());
				}else
					throw new TAPException(ite);
			}catch(Exception ex){
				throw new TAPException("Impossible to create an instance of tap.metadata.TAPMetadata as specified in the property \"" + KEY_METADATA + "\": \"" + metaFetchType + "\"!", ex);
			}
		}

		return metadata;
	}
+7 −1
Original line number Diff line number Diff line
@@ -280,8 +280,14 @@
						<li>Build yourself the metadata of your service by creating an extension of tap.metadata.TAPMetadata. This extension must have either an empty constructor
							or a constructor with exactly 3 parameters of type UWSFileManager, TAPFactory and TAPLog ; if both constructor are provided, only the one with parameters will be used.</li>
					</ol>
					<p>
						For the two first methods, it is also possible to specify an extension of tap.metadata.TAPMetadata which will wrap a default TAPMetadata objects created using the specified
						methods (i.e. XML tableset or TAP_SCHEMA). In this way, it is possible to get the "default" metadata from an XML file or the database
						and then add/remove/modify some of them, or to change the output of the 'tables' resource. The extension of tap.metadata.TAPMetadata must have at least
						one constructor with the following parameters: (TAPMetadata) or (TAPMetadata, UWSFileManager, TAPFactory, TAPLog).
					</p>
				</td>
				<td><ul><li>xml</li><li>db</li><li>{apackage.MyTAPMetadata}</li></ul>
				<td><ul><li>xml</li><li>xml {myTAPMetadata}</li><li>db</li><li>db {myTAPMetadata}</li><li>{apackage.MyTAPMetadata}</li></ul>
			</tr>
			<tr class="optional">
				<td class="done">metadata_file</td>
+8 −3
Original line number Diff line number Diff line
##########################################################
#             FULL TAP CONFIGURATION FILE                #
#                                                        #
# TAP Version: 2.0                                       #
# Date: 13 April 2015                                    #
# TAP Version: 2.1                                       #
# Date: 22 Oct. 2015                                     #
# Author: Gregory Mantelet (ARI)                         #
#                                                        #
########################################################## 
@@ -152,7 +152,12 @@ db_password =
#    3/ Build yourself the metadata of your service by creating an extension of tap.metadata.TAPMetadata. This extension must have either an empty constructor
#       or a constructor with exactly 3 parameters of type UWSFileManager, TAPFactory and TAPLog ; if both constructor are provided, only the one with parameters will be used.
# 
# Allowed values: xml, db or a full class name (between {}).
# For the two first methods, it is also possible to specify an extension of tap.metadata.TAPMetadata which will wrap a default TAPMetadata objects created using the specified
# methods (i.e. XML tableset or TAP_SCHEMA). In this way, it is possible to get the "default" metadata from an XML file or the database
# and then add/remove/modify some of them, or to change the output of the 'tables' resource. The extension of tap.metadata.TAPMetadata must have at least
# one constructor with the following parameters: (TAPMetadata) or (TAPMetadata, UWSFileManager, TAPFactory, TAPLog).
#  
# Allowed values: xml, xml {myTAPMetadata}, db, db {myTAPMetadata} or a full class name (between {}).
metadata =  

# [MANDATORY]
+8 −3
Original line number Diff line number Diff line
##########################################################
#            MINIMUM TAP CONFIGURATION FILE              #
#                                                        #
# TAP Version: 2.0                                       #
# Date: 27 Feb. 2015                                     #
# TAP Version: 2.1                                       #
# Date: 22 Oct. 2015                                     #
# Author: Gregory Mantelet (ARI)                         #
#                                                        #
########################################################## 
@@ -80,7 +80,12 @@ db_password =
#    3/ Build yourself the metadata of your service by creating an extension of tap.metadata.TAPMetadata. This extension must have either an empty constructor
#       or a constructor with exactly 3 parameters of type UWSFileManager, TAPFactory and TAPLog ; if both constructor are provided, only the one with parameters will be used.
# 
# Allowed values: xml, db or a full class name (between {}).
# For the two first methods, it is also possible to specify an extension of tap.metadata.TAPMetadata which will wrap a default TAPMetadata objects created using the specified
# methods (i.e. XML tableset or TAP_SCHEMA). In this way, it is possible to get the "default" metadata from an XML file or the database
# and then add/remove/modify some of them, or to change the output of the 'tables' resource. The extension of tap.metadata.TAPMetadata must have at least
# one constructor with the following parameters: (TAPMetadata) or (TAPMetadata, UWSFileManager, TAPFactory, TAPLog).
#  
# Allowed values: xml, xml {myTAPMetadata}, db, db {myTAPMetadata} or a full class name (between {}).
metadata =  

# Mandatory if the value of "metadata" is "xml".
+6 −6
Original line number Diff line number Diff line
@@ -64,7 +64,7 @@ import adql.db.DBType.DBDatatype;
 * </p>
 * 
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @version 2.0 (03/2015)
 * @version 2.1 (10/2015)
 */
public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResource {

@@ -514,7 +514,7 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
	 * 
	 * @see #writeTable(TAPTable, PrintWriter)
	 */
	private void writeSchema(TAPSchema s, PrintWriter writer) throws IOException{
	protected void writeSchema(TAPSchema s, PrintWriter writer) throws IOException{
		final String prefix = "\t\t";
		writer.println("\t<schema>");

@@ -577,7 +577,7 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
	 * 
	 * @return	The total number of written columns.
	 */
	private int writeTable(TAPTable t, PrintWriter writer){
	protected int writeTable(TAPTable t, PrintWriter writer){
		final String prefix = "\t\t\t";

		writer.print("\t\t<table");
@@ -635,7 +635,7 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
	 * @param c			The column to format and to write in XML.
	 * @param writer	Output in which the XML serialization of the given column must be written.
	 */
	private void writeColumn(TAPColumn c, PrintWriter writer){
	protected void writeColumn(TAPColumn c, PrintWriter writer){
		final String prefix = "\t\t\t\t";

		writer.print("\t\t\t<column");
@@ -696,7 +696,7 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
	 * @param fk		The foreign key to format and to write in XML.
	 * @param writer	Output in which the XML serialization of the given foreign key must be written.
	 */
	private void writeForeignKey(TAPForeignKey fk, PrintWriter writer){
	protected void writeForeignKey(TAPForeignKey fk, PrintWriter writer){
		final String prefix = "\t\t\t\t";

		writer.println("\t\t\t<foreignKey>");
@@ -728,7 +728,7 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
	 *                      	<i>false</i> otherwise (here, if the value is NULL or an empty string, the XML item will be written with an empty string as value). 
	 * @param writer			Output in which the XML node must be written.
	 */
	private void writeAtt(String prefix, String attributeName, String attributeValue, boolean isOptionalAttr, PrintWriter writer){
	protected final void writeAtt(String prefix, String attributeName, String attributeValue, boolean isOptionalAttr, PrintWriter writer){
		if (attributeValue != null && attributeValue.trim().length() > 0){
			StringBuffer xml = new StringBuffer(prefix);
			xml.append('<').append(attributeName).append('>').append(VOSerializer.formatText(attributeValue)).append("</").append(attributeName).append('>');
Loading