From 484ce70eaf891a5706f0c8bea183559d90433aba Mon Sep 17 00:00:00 2001
From: gmantele <gmantele@ari.uni-heidelberg.de>
Date: Mon, 18 Jul 2016 11:44:08 +0200
Subject: [PATCH] [TAP] Allow setting an XSLT stylesheet for /capabilities and
 /tables.

---
 src/tap/config/ConfigurableTAPServlet.java | 34 +++++++++++++++---
 src/tap/config/TAPConfiguration.java       | 10 ++++--
 src/tap/config/tap_configuration_file.html | 20 +++++++++++
 src/tap/config/tap_full.properties         | 14 +++++++-
 src/tap/metadata/TAPMetadata.java          | 38 ++++++++++++++++++++
 src/tap/resource/Capabilities.java         | 41 ++++++++++++++++++++--
 6 files changed, 146 insertions(+), 11 deletions(-)

diff --git a/src/tap/config/ConfigurableTAPServlet.java b/src/tap/config/ConfigurableTAPServlet.java
index 91865ac..a1a9d44 100644
--- a/src/tap/config/ConfigurableTAPServlet.java
+++ b/src/tap/config/ConfigurableTAPServlet.java
@@ -16,14 +16,16 @@ package tap.config;
  * 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 2015 - Astronomisches Rechen Institut (ARI)
+ * Copyright 2015-2016 - Astronomisches Rechen Institut (ARI)
  */
 
 import static tap.config.TAPConfiguration.DEFAULT_TAP_CONF_FILE;
 import static tap.config.TAPConfiguration.KEY_ADD_TAP_RESOURCES;
+import static tap.config.TAPConfiguration.KEY_CAPABILITIES_STYLESHEET;
 import static tap.config.TAPConfiguration.KEY_EXAMPLES;
 import static tap.config.TAPConfiguration.KEY_HOME_PAGE;
 import static tap.config.TAPConfiguration.KEY_HOME_PAGE_MIME_TYPE;
+import static tap.config.TAPConfiguration.KEY_TABLES_STYLESHEET;
 import static tap.config.TAPConfiguration.TAP_CONF_PARAMETER;
 import static tap.config.TAPConfiguration.getProperty;
 import static tap.config.TAPConfiguration.isClassName;
@@ -58,7 +60,7 @@ import tap.resource.TAPResource;
  * </p>
  * 
  * @author Gr&eacute;gory Mantelet (ARI)
- * @version 2.1 (11/2015)
+ * @version 2.1 (07/2016)
  * @since 2.0
  */
 public class ConfigurableTAPServlet extends HttpServlet {
@@ -150,8 +152,11 @@ public class ConfigurableTAPServlet extends HttpServlet {
 					tap.setHomePageMimeType(propValue);
 			}
 		}
-		
-		/* 4Ter. SET THE EXAMPLES ENDPOINT (if any) */
+
+		/* 4Ter. SET THE XSLT for /capabilities and /tables */
+		initXSLTStylesheet(tapConf);
+
+		/* 4Quater. SET THE EXAMPLES ENDPOINT (if any) */
 		propValue = getProperty(tapConf, KEY_EXAMPLES);
 		if (propValue != null)
 			tap.addResource(new Examples(tap, propValue));
@@ -181,7 +186,7 @@ public class ConfigurableTAPServlet extends HttpServlet {
 
 		/* 6. DEFAULT SERVLET INITIALIZATION */
 		super.init(config);
-		
+
 		/* 7. INITIATILIZE THE TAP SERVICE */
 		tap.init(config);
 
@@ -219,6 +224,25 @@ public class ConfigurableTAPServlet extends HttpServlet {
 		return input;
 	}
 
+	/**
+	 * Initialize the XSLT for /capabilities and /tables.
+	 * 
+	 * @param tapConfig	The content of the TAP configuration file.
+	 * 
+	 * @since 2.1
+	 */
+	protected void initXSLTStylesheet(final Properties tapConfig){
+		// Set the XSLT of /capabilities:
+		String propValue = getProperty(tapConfig, KEY_CAPABILITIES_STYLESHEET);
+		if (propValue != null)
+			tap.getCapabilities().setXSLTPath(propValue);
+
+		// Set the XSLT of /tables:
+		propValue = getProperty(tapConfig, KEY_TABLES_STYLESHEET);
+		if (propValue != null)
+			tap.getTAPMetadata().setXSLTPath(propValue);
+	}
+
 	@Override
 	public void destroy(){
 		// Free all resources used by TAP:
diff --git a/src/tap/config/TAPConfiguration.java b/src/tap/config/TAPConfiguration.java
index 7e3e39f..6bd6197 100644
--- a/src/tap/config/TAPConfiguration.java
+++ b/src/tap/config/TAPConfiguration.java
@@ -33,7 +33,7 @@ import tap.backup.DefaultTAPBackupManager;
  * <p>Utility class gathering tool functions and properties' names useful to deal with a TAP configuration file.</p>
  * 
  * <p><i>This class implements the Design Pattern "Utility": no instance of this class can be created, it can not be extended,
- * and it must be used only thanks to its static classes and attributes.</i></p> 
+ * and it must be used only thanks to its static classes and attributes.</i></p>
  * 
  * @author Gr&eacute;gory Mantelet (ARI)
  * @version 2.1 (11/2015)
@@ -272,12 +272,16 @@ public final class TAPConfiguration {
 	public final static String VALUE_ANY = "ANY";
 
 	/* ADDITIONAL TAP RESOURCES */
+	/** Name/Key of the property specifying the XSLT stylesheet to use for /capabilities. */
+	public final static String KEY_CAPABILITIES_STYLESHEET = "capabilities_stylesheet";
+	/** Name/Key of the property specifying the XSLT stylesheet to use for /tables. */
+	public final static String KEY_TABLES_STYLESHEET = "tables_stylesheet";
 	/** Name/Key of the property specifying a list of resources to add to the TAP service (e.g. a ADQL query validator).
 	 * By default, this list if empty ; only the default TAP resources exist. */
 	public final static String KEY_ADD_TAP_RESOURCES = "additional_resources";
 
 	/* CUSTOM FACTORY */
-	/** Name/Key of the property specifying the {@link TAPFactory} class to use instead of the default {@link ConfigurableTAPFactory}. 
+	/** Name/Key of the property specifying the {@link TAPFactory} class to use instead of the default {@link ConfigurableTAPFactory}.
 	 * <em>Setting a value to this property could disable several properties of the TAP configuration file.</em> */
 	public final static String KEY_TAP_FACTORY = "tap_factory";
 
@@ -324,7 +328,7 @@ public final class TAPConfiguration {
 	}
 
 	/**
-	 * Fetch the class object corresponding to the class name provided between brackets in the given value. 
+	 * Fetch the class object corresponding to the class name provided between brackets in the given value.
 	 * 
 	 * @param value			Value which is supposed to contain the class name between brackets (see {@link #isClassName(String)} for more details)
 	 * @param propertyName	Name of the property associated with the parameter "value".
diff --git a/src/tap/config/tap_configuration_file.html b/src/tap/config/tap_configuration_file.html
index 979b08c..5edc7fa 100644
--- a/src/tap/config/tap_configuration_file.html
+++ b/src/tap/config/tap_configuration_file.html
@@ -670,6 +670,26 @@
 			</tr>
 			
 			<tr><td colspan="5">Additional TAP Resources</td></tr>
+			<tr class="optional">
+				<td class="done">capabilities_stylesheet</td>
+				<td></td>
+				<td>text</td>
+				<td>
+					<p>URL of the XSLT stylesheet to link with the XML output of /capabilities.</p>
+					<p><em>By default, no XSLT stylesheet is defined.</em></p>
+				</td>
+				<td><ul><li>http://mytap.com/myCapabilities.xslt</li></ul></td>
+			</tr>
+			<tr class="optional">
+				<td class="done">tables_stylesheet</td>
+				<td></td>
+				<td>text</td>
+				<td>
+					<p>URL of the XSLT stylesheet to link with the XML output of /tables.</p>
+					<p><em>By default, no XSLT stylesheet is defined.</em></p>
+				</td>
+				<td><ul><li>http://mytap.com/myTables.xslt</li></ul></td>
+			</tr>
 			<tr class="optional">
 				<td class="done">examples</td>
 				<td></td>
diff --git a/src/tap/config/tap_full.properties b/src/tap/config/tap_full.properties
index dcf88fd..770f78e 100644
--- a/src/tap/config/tap_full.properties
+++ b/src/tap/config/tap_full.properties
@@ -2,7 +2,7 @@
 #             FULL TAP CONFIGURATION FILE                #
 #                                                        #
 # TAP Version: 2.1                                       #
-# Date: 18 Nov. 2015                                     #
+# Date: 18 July 2016                                     #
 # Author: Gregory Mantelet (ARI)                         #
 #                                                        #
 ########################################################## 
@@ -507,6 +507,18 @@ udfs =
 # ADDITIONAL RESOURCES #
 ########################
 
+# [OPTIONAL]
+# URL of the XSLT stylesheet to link with the XML output of /capabilities.
+# 
+# By default, no XSLT stylesheet is defined.
+capabilities_stylesheet = 
+
+# [OPTIONAL]
+# URL of the XSLT stylesheet to link with the XML output of /tables.
+# 
+# By default, no XSLT stylesheet is defined.
+tables_stylesheet = 
+
 # [OPTIONAL]
 # This property lets add an <code>/examples</code> endpoint by specifying an XHTML-RDFa
 # document listing TAP query examples using the syntax specified by TAPNotes 1.0 DALI 1.0.
diff --git a/src/tap/metadata/TAPMetadata.java b/src/tap/metadata/TAPMetadata.java
index 9684805..361e0ec 100644
--- a/src/tap/metadata/TAPMetadata.java
+++ b/src/tap/metadata/TAPMetadata.java
@@ -79,6 +79,10 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
 	 * By default, it is the resource name ; so here, the corresponding TAP URI would be: "/tables". */
 	protected String accessURL = getName();
 
+	/** The path of the XSLT style-sheet to apply.
+	 * @version 2.1 */
+	protected String xsltPath = null;
+
 	/**
 	 * <p>Build an empty list of metadata.</p>
 	 * 
@@ -105,6 +109,34 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
 		schemas = new LinkedHashMap<String,TAPSchema>();
 	}
 
+	/**
+	 * Gets the path/URL of the XSLT style-sheet to use.
+	 * 
+	 * @return	XSLT path/url.
+	 * 
+	 * @version 2.1
+	 */
+	public final String getXSLTPath(){
+		return xsltPath;
+	}
+
+	/**
+	 * Sets the path/URL of the XSLT style-sheet to use.
+	 * 
+	 * @param path	The new XSLT path/URL.
+	 * 
+	 * @version 2.1
+	 */
+	public final void setXSLTPath(final String path){
+		if (path == null)
+			xsltPath = null;
+		else{
+			xsltPath = path.trim();
+			if (xsltPath.isEmpty())
+				xsltPath = null;
+		}
+	}
+
 	/**
 	 * <p>Add the given schema inside this TAP metadata set.</p>
 	 * 
@@ -476,6 +508,12 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
 	public void write(final PrintWriter writer) throws IOException{
 		writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
 
+		if (xsltPath != null){
+			writer.print("<?xml-stylesheet type=\"text/xsl\" ");
+			writer.print(VOSerializer.formatAttribute("href", xsltPath));
+			writer.println("?>");
+		}
+
 		/* TODO The XSD schema for VOSITables should be fixed soon! This schema should be changed here before the library is released!
 		 * Note: the XSD schema at http://www.ivoa.net/xml/VOSITables/v1.0 contains an incorrect targetNamespace ("http://www.ivoa.net/xml/VOSICapabilities/v1.0").
 		 *       In order to make this XML document valid, a custom location toward a correct XSD schema is used: http://vo.ari.uni-heidelberg.de/docs/schemata/VOSITables-v1.0.xsd */
diff --git a/src/tap/resource/Capabilities.java b/src/tap/resource/Capabilities.java
index e8b2aa7..bb207e7 100644
--- a/src/tap/resource/Capabilities.java
+++ b/src/tap/resource/Capabilities.java
@@ -16,7 +16,7 @@ package tap.resource;
  * 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 2012-2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ * Copyright 2012-2016 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
 
@@ -39,7 +39,7 @@ import uws.UWSToolBox;
  * <p>This resource just return an XML document giving a description of the TAP service and list all its VOSI resources.</p>
  * 
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 2.0 (04/2015)
+ * @version 2.1 (07/2016)
  */
 public class Capabilities implements TAPResource, VOSIResource {
 
@@ -57,6 +57,10 @@ public class Capabilities implements TAPResource, VOSIResource {
 	 * when the TAP service base URL is communicated to its resources. Then, it is: baseTAPURL + "/" + RESOURCE_NAME.</i></p> */
 	protected String accessURL = getName();
 
+	/** The path of the XSLT style-sheet to apply.
+	 * @version 2.1 */
+	protected String xsltPath = null;
+
 	/**
 	 * Build a "/capabilities" resource.
 	 * 
@@ -66,6 +70,34 @@ public class Capabilities implements TAPResource, VOSIResource {
 		this.tap = tap;
 	}
 
+	/**
+	 * Gets the path/URL of the XSLT style-sheet to use.
+	 * 
+	 * @return	XSLT path/url.
+	 * 
+	 * @version 2.1
+	 */
+	public final String getXSLTPath(){
+		return xsltPath;
+	}
+
+	/**
+	 * Sets the path/URL of the XSLT style-sheet to use.
+	 * 
+	 * @param path	The new XSLT path/URL.
+	 * 
+	 * @version 2.1
+	 */
+	public final void setXSLTPath(final String path){
+		if (path == null)
+			xsltPath = null;
+		else{
+			xsltPath = path.trim();
+			if (xsltPath.isEmpty())
+				xsltPath = null;
+		}
+	}
+
 	@Override
 	public final void setTAPBaseURL(String baseURL){
 		accessURL = ((baseURL == null) ? "" : (baseURL + "/")) + getName();
@@ -121,6 +153,11 @@ public class Capabilities implements TAPResource, VOSIResource {
 
 		// Write the XML document header:
 		out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+		if (xsltPath != null){
+			out.print("<?xml-stylesheet type=\"text/xsl\" ");
+			out.print(VOSerializer.formatAttribute("href", xsltPath));
+			out.println("?>");
+		}
 		out.print("<vosi:capabilities xmlns:vosi=\"http://www.ivoa.net/xml/VOSICapabilities/v1.0\"");
 		out.print(" xmlns:tr=\"http://www.ivoa.net/xml/TAPRegExt/v1.0\"");
 		out.print(" xmlns:vr=\"http://www.ivoa.net/xml/VOResource/v1.0\"");
-- 
GitLab