Commit 6f154e19 authored by gmantele's avatar gmantele
Browse files

[TAP] Let specify a mapping for TAP_SCHEMA between ADQL and DB names.

This is very helpful if TAP_SCHEMA (or some of its tables and their columns)
has a different name in the database.
The mapping can be specified to JDBCConnection or directly in the configuration
file.
parent eddd2ec1
Loading
Loading
Loading
Loading
+32 −13
Original line number Diff line number Diff line
@@ -86,13 +86,19 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Properties;

import adql.db.FunctionDef;
import adql.db.STCS;
import adql.parser.ParseException;
import adql.query.operand.function.UserDefinedFunction;
import tap.ServiceConnection;
import tap.TAPException;
import tap.TAPFactory;
import tap.db.DBConnection;
import tap.db.JDBCConnection;
import tap.formatter.FITSFormat;
import tap.formatter.HTMLFormat;
import tap.formatter.JSONFormat;
@@ -111,10 +117,6 @@ import uws.service.UserIdentifier;
import uws.service.file.LocalUWSFileManager;
import uws.service.file.UWSFileManager;
import uws.service.log.UWSLog.LogLevel;
import adql.db.FunctionDef;
import adql.db.STCS;
import adql.parser.ParseException;
import adql.query.operand.function.UserDefinedFunction;

/**
 * <p>Concrete implementation of {@link ServiceConnection}, fully parameterized with a TAP configuration file.</p>
@@ -125,7 +127,7 @@ import adql.query.operand.function.UserDefinedFunction;
 * </p>
 * 
 * @author Gr&eacute;gory Mantelet (ARI)
 * @version 2.1 (02/2016)
 * @version 2.1 (09/2016)
 * @since 2.0
 */
public final class ConfigurableServiceConnection implements ServiceConnection {
@@ -482,7 +484,22 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
		else if (metaFetchType.equalsIgnoreCase(VALUE_DB)){
			DBConnection conn = null;
			try{
				// get a db connection:
				conn = tapFactory.getConnection("GET_TAP_SCHEMA");

				// fetch and set the ADQL<->DB mapping for all standard TAP_SCHEMA items:
				if (conn instanceof JDBCConnection){
					HashMap<String,String> dbMapping = new HashMap<String,String>(10);
					// fetch the mapping from the Property file:
					for(String key : tapConfig.stringPropertyNames()){
						if (key.trim().startsWith("TAP_SCHEMA") && tapConfig.getProperty(key) != null && tapConfig.getProperty(key).trim().length() > 0)
							dbMapping.put(key.trim(), tapConfig.getProperty(key));
					}
					// set the mapping into the DB connection:
					((JDBCConnection)conn).setDBMapping(dbMapping);
				}

				// fetch TAP_SCHEMA:
				metadata = conn.getTAPSchema();
			}finally{
				if (conn != null)
@@ -1135,10 +1152,12 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
			char c;
			int ind = 0;
			short nbComma = 0;
			boolean within_item = false, within_params = false, within_classpath = false;
			boolean within_item = false, within_params = false,
					within_classpath = false;
			StringBuffer buf = new StringBuffer();
			String signature, classpath;
			int[] posSignature = new int[]{-1,-1}, posClassPath = new int[]{-1,-1};
			int[] posSignature = new int[]{-1,-1},
					posClassPath = new int[]{-1,-1};

			signature = null;
			classpath = null;
+26 −1
Original line number Diff line number Diff line
@@ -302,6 +302,31 @@
				</td>
				<td><ul><li>/home/foo/my_metadata.xml</li><li>my_metadata.xml</li><li>WEB-INF/my_metadata.xml</li></ul></td>
			</tr>
			<tr class="optional">
				<td class="done">TAP_SCHEMA...</td>
				<td></td>
				<td>text</td>
				<td>
					<p><strong>Only used if <code>metadata = db</code></strong>.</p>
					<p>Mapping between TAP_SCHEMA ADQL names and their names in the database.</p>
					<p>
						<b>Any property named exactly (case sensitive) like TAP_SCHEMA items</b> will be considered
						as a mapping between its ADQL name and its DB name.
					</p>
					<p>
						The property value MUST be NOT qualified. Just the item name is required.
						The value will be used as provided (with the same case).
					</p>
				</td>
				<td>
					<ul>
						<li>TAP_SCHEMA = myTAPSchema</li>
						<li>TAP_SCHEMA.tables = tap_tables</li>
						<li>TAP_SCHEMA.columns.column_name = name</li>
						<li>...</li>
					</ul>
				</td>
			</tr>
			
			<tr><td colspan="5">Files</td></tr>
			<tr class="mandatory">
@@ -758,7 +783,7 @@
						tap.AbstractTAPFactory or tap.config.ConfigurableTAPFactory.
					</p>
					<p><em>By default, the default TAPFactory (tap.config.ConfigurableTAPFactory) is used and may use all properties related to the backup management,
					the database access and the ADQL translation.</em></p>
					the database access, the TAP_SCHEMA mapping and the ADQL translation.</em></p>
				</td>
				<td>{aPackage.MyTAPFactory}</td>
			</tr>
+19 −4
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
#             FULL TAP CONFIGURATION FILE                #
#                                                        #
# TAP Version: 2.1                                       #
# Date: 18 July 2016                                     #
# Date: 1 Sept. 2016                                     #
# Author: Gregory Mantelet (ARI)                         #
#                                                        #
########################################################## 
@@ -167,6 +167,21 @@ metadata =
# The file path must be either an absolute local file path or a file path relative to WebContent (i.e. the web application directory in which there are WEB-INF and META-INF).
metadata_file =   

# [OPTIONAL]
# [ONLY USED IF metadata = db]
#
# Mapping between TAP_SCHEMA ADQL names and their names in the database.
# 
# Any property named exactly (case sensitive) like TAP_SCHEMA items will be considered
# as a mapping between its ADQL name and its DB name.
#
# Examples: "TAP_SCHEMA = TAP_SCHEMA2" or "TAP_SCHEMA.columns.column_name = name"
#
# The property value MUST be NOT qualified. Just the item name is required.
# The value will be used as provided (with the same case).
#
# TAP_SCHEMA = 

#########
# FILES #
#########
@@ -568,5 +583,5 @@ additional_resources =
# tap.AbstractTAPFactory or tap.config.ConfigurableTAPFactory.
# 
# By default, the default TAPFactory (tap.config.ConfigurableTAPFactory) is used and may use all properties related to the backup management,
# the database access and the ADQL translation.
# the database access, the TAP_SCHEMA mapping and the ADQL translation.
tap_factory = 
+84 −2
Original line number Diff line number Diff line
@@ -177,7 +177,7 @@ import uws.service.log.UWSLog.LogLevel;
 * </i></p>
 * 
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @version 2.1 (07/2016)
 * @version 2.1 (09/2016)
 * @since 2.0
 */
public class JDBCConnection implements DBConnection {
@@ -302,6 +302,17 @@ public class JDBCConnection implements DBConnection {
	 * <p><i>Note 2: if this feature is enabled (i.e. has a value &gt; 0), the AutoCommit will be disabled.</i></p> */
	protected int fetchSize = DEFAULT_FETCH_SIZE;

	/* TAP_SCHEMA MAPPING */

	/** Mapping of the TAP_SCHEMA items between their ADQL name and their name in the database.
	 * <p><b>IMPORTANT:</b>
	 * 	Keys of the map MUST be the full ADQL name of an item (e.g. TAP_SCHEMA, TAP_SCHEMA.tables, TAP_SCHEMA.columns.ucd).
	 * 	Values MUST be the name of the corresponding item in the database.
	 * 	Keys and values are case sensitive.
	 * </p>
	 * @since 2.1 */
	protected Map<String,String> dbMapping = null;

	/**
	 * <p>Creates a JDBC connection to the specified database and with the specified JDBC driver.
	 * This connection is established using the given user name and password.<p>
@@ -792,6 +803,77 @@ public class JDBCConnection implements DBConnection {
		}
	}

	/**
	 * Let specify for all item of the standard TAP_SCHEMA a different name in the database.
	 * <p><i>
	 * 	For instance: if in the database "TAP_SCHEMA" is called "MY_TAP_SCHEMA".
	 * </i></p>
	 * 
	 * <p><b>IMPORTANT:</b>
	 * 	TAP_SCHEMA items (i.e. keys in the map) MUST be fully qualified ADQL names (e.g. TAP_SCHEMA.columns.name).
	 * 	The values MUST be single database names (i.e. no catalogue, schema or table prefix).
	 * 	Both keys and values are case sensitive.
	 * </p>
	 * 
	 * <p><i>Note:</i>
	 * 	TAP_SCHEMA items keeping the same name in the database than in ADQL do not need to
	 * 	be listed in the given map.
	 * </p>
	 * 
	 * @param mapping	Mapping between ADQL names and DB names.
	 *               	If <code>null</code>, DB names will be considered equals to the ADQL names.
	 * 
	 * @since 2.1
	 */
	public void setDBMapping(final Map<String,String> mapping){
		if (mapping == null)
			dbMapping = null;
		else{
			if (dbMapping == null)
				dbMapping = new HashMap<String,String>(mapping.size());
			else
				dbMapping.clear();
			dbMapping.putAll(mapping);
			if (dbMapping.size() == 0)
				dbMapping = null;
		}
	}

	/**
	 * Get the standard definition of TAP_SCHEMA with eventually DB names provided by the set mapping (see {@link #setDBMapping(Map)}).
	 * 
	 * @return	The standard schema as it should be detected in the database.
	 * 
	 * @since 2.1
	 */
	protected TAPSchema getStdSchema(){
		TAPSchema tap_schema = TAPMetadata.getStdSchema(supportsSchema);

		if (dbMapping != null){
			// Update the TAP_SCHEMA DB name, if needed:
			if (dbMapping.containsKey(tap_schema.getADQLName()))
				tap_schema.setDBName(dbMapping.get(tap_schema.getADQLName()));

			// For each table...
			for(TAPTable t : tap_schema){
				// ...update the table DB name, if needed:
				if (dbMapping.containsKey(t.getFullName()))
					t.setDBName(dbMapping.get(t.getFullName()));

				// For each column...
				String fullName;
				for(DBColumn c : t){
					fullName = t.getFullName() + "." + c.getADQLName();
					// ...update the column DB name, if needed:
					if (dbMapping.containsKey(fullName))
						((TAPColumn)c).setDBName(dbMapping.get(fullName));
				}
			}
		}

		return tap_schema;
	}

	/* ************************************ */
	/* GETTING TAP_SCHEMA FROM THE DATABASE */
	/* ************************************ */
@@ -822,7 +904,7 @@ public class JDBCConnection implements DBConnection {
		TAPMetadata metadata = new TAPMetadata();

		// Get the definition of the standard TAP_SCHEMA tables:
		TAPSchema tap_schema = TAPMetadata.getStdSchema(supportsSchema);
		TAPSchema tap_schema = getStdSchema();

		// LOAD ALL METADATA FROM THE STANDARD TAP TABLES:
		try{