Commit 62a44426 authored by gmantele's avatar gmantele
Browse files

[TAP] Add a property in the configuration file to set a custom TAPFactory (in...

[TAP] Add a property in the configuration file to set a custom TAPFactory (in replacement of ConfigurableTAPFactory.
parent c790223e
Loading
Loading
Loading
Loading
+11 −2
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import static tap.config.TAPConfiguration.KEY_MIN_LOG_LEVEL;
import static tap.config.TAPConfiguration.KEY_OUTPUT_FORMATS;
import static tap.config.TAPConfiguration.KEY_PROVIDER_NAME;
import static tap.config.TAPConfiguration.KEY_SERVICE_DESCRIPTION;
import static tap.config.TAPConfiguration.KEY_TAP_FACTORY;
import static tap.config.TAPConfiguration.KEY_UDFS;
import static tap.config.TAPConfiguration.KEY_UPLOAD_ENABLED;
import static tap.config.TAPConfiguration.KEY_UPLOAD_MAX_FILE_SIZE;
@@ -93,7 +94,7 @@ public final class ConfigurableServiceConnection implements ServiceConnection {

	private TAPLog logger;

	private ConfigurableTAPFactory tapFactory;
	private TAPFactory tapFactory;

	private final TAPMetadata metadata;

@@ -136,7 +137,7 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
		initLogger(tapConfig);

		// 3. BUILD THE TAP FACTORY:
		tapFactory = new ConfigurableTAPFactory(this, tapConfig);
		initFactory(tapConfig);

		// 4. GET THE METADATA:
		metadata = initMetadata(tapConfig);
@@ -236,6 +237,14 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
		logger.info(buf.toString());
	}

	private void initFactory(final Properties tapConfig) throws TAPException{
		String propValue = getProperty(tapConfig, KEY_TAP_FACTORY);
		if (propValue == null)
			tapFactory = new ConfigurableTAPFactory(this, tapConfig);
		else
			tapFactory = newInstance(propValue, KEY_TAP_FACTORY, TAPFactory.class, new Class<?>[]{ServiceConnection.class}, new Object[]{this});
	}

	private TAPMetadata initMetadata(final Properties tapConfig) throws TAPException{
		// Get the fetching method to use:
		String metaFetchType = getProperty(tapConfig, KEY_METADATA);
+3 −0
Original line number Diff line number Diff line
@@ -115,6 +115,9 @@ public final class TAPConfiguration {
	/* ADDITIONAL TAP RESOURCES */
	public final static String KEY_ADD_TAP_RESOURCES = "additional_resources";

	/* CUSTOM FACTORY */
	public final static String KEY_TAP_FACTORY = "tap_factory";

	/**
	 * <p>Read the asked property from the given Properties object.</p>
	 * <ul>
+19 −2
Original line number Diff line number Diff line
@@ -146,7 +146,7 @@
				<td></td>
			</tr>
			
			<tr><td colspan="5">Database</td></tr>
			<tr><td colspan="5">Database (only if tap_factory = ø)</td></tr>
			<tr class="mandatory">
				<td class="done">database_access</td>
				<td></td>
@@ -374,7 +374,7 @@
				<td><ul><li>D 6 30</li><li>W 2 6 30</li><li>M 2 6 30</li><li>H 10</li><li>m</li></ul></td>
			</tr>
			
			<tr><td colspan="5">UWS Backup</td></tr>
			<tr><td colspan="5">UWS Backup (only if tap_factory = ø)</td></tr>
			<tr class="optional">
				<td class="done">backup_frequency</td>
				<td></td>
@@ -622,6 +622,23 @@
				<td>{aPackage.QuickADQLValidator}</td>
			</tr>
			
			<tr><td colspan="5">Custom TAP Factory</td></tr>
			<tr class="optional">
				<td class="done">tap_factory</td>
				<td></td>
				<td>text</td>
				<td>
					<p>Class to use in replacement of the default TAPFactory.</p>
					<p>
						This property must be a class name (given between {...}). It must reference an extension of the abstract TAPFactory.
						This extension must have at least one constructor with exactly one parameter of type ServiceConnection.
					</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>
				</td>
				<td>{aPackage.MyTAPFactory}</td>
			</tr>
			
		</table>
		<script type="text/javascript">
			var nb = document.getElementsByClassName("mandatory").length;
+16 −2
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
#             FULL TAP CONFIGURATION FILE                #
#                                                        #
# TAP Version: 2.0                                       #
# Date: 18 Feb. 2015                                     #
# Date: 19 Feb. 2015                                     #
# Author: Gregory Mantelet (ARI)                         #
#                                                        #
########################################################## 
@@ -464,3 +464,17 @@ udfs =
# 
# By default, this list is empty ; only the standard TAP resources exist.
additional_resources = 

######################
# CUSTOM TAP_FACTORY #
######################

# [OPTIONAL]
# Class to use in replacement of the default TAPFactory.
# 
# This property must be a class name (given between {...}). It must reference an extension of the abstract TAPFactory.
# This extension must have at least one constructor with exactly one parameter of type ServiceConnection.
# 
# 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.
tap_factory = 
+89 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ import static tap.config.TAPConfiguration.KEY_METADATA;
import static tap.config.TAPConfiguration.KEY_METADATA_FILE;
import static tap.config.TAPConfiguration.KEY_MIN_LOG_LEVEL;
import static tap.config.TAPConfiguration.KEY_OUTPUT_FORMATS;
import static tap.config.TAPConfiguration.KEY_TAP_FACTORY;
import static tap.config.TAPConfiguration.KEY_UDFS;
import static tap.config.TAPConfiguration.KEY_USER_IDENTIFIER;
import static tap.config.TAPConfiguration.VALUE_ANY;
@@ -44,9 +45,13 @@ import javax.servlet.http.HttpServletRequest;
import org.junit.BeforeClass;
import org.junit.Test;

import tap.AbstractTAPFactory;
import tap.ServiceConnection;
import tap.ServiceConnection.LimitUnit;
import tap.TAPException;
import tap.db.DBConnection;
import tap.db.DBException;
import tap.db.JDBCConnection;
import tap.formatter.OutputFormat;
import tap.formatter.VOTableFormat;
import uk.ac.starlink.votable.DataFormat;
@@ -61,6 +66,7 @@ import uws.service.log.DefaultUWSLog;
import uws.service.log.UWSLog.LogLevel;
import adql.db.FunctionDef;
import adql.db.TestDBChecker.UDFToto;
import adql.translator.PostgreSQLTranslator;

public class TestConfigurableServiceConnection {

@@ -83,7 +89,8 @@ public class TestConfigurableServiceConnection {
			udfsListWithNONEorANYProp, udfsWithWrongParamLengthProp,
			udfsWithMissingBracketsProp, udfsWithMissingDefProp1,
			udfsWithMissingDefProp2, emptyUdfItemProp1, emptyUdfItemProp2,
			udfWithMissingEndBracketProp;
			udfWithMissingEndBracketProp, customFactoryProp,
			badCustomFactoryProp;

	@BeforeClass
	public static void setUp() throws Exception{
@@ -242,6 +249,12 @@ public class TestConfigurableServiceConnection {

		udfWithMissingEndBracketProp = (Properties)validProp.clone();
		udfWithMissingEndBracketProp.setProperty(KEY_UDFS, "[toto(a string)->VARCHAR");

		customFactoryProp = (Properties)validProp.clone();
		customFactoryProp.setProperty(KEY_TAP_FACTORY, "{tap.config.TestConfigurableServiceConnection$CustomTAPFactory}");

		badCustomFactoryProp = (Properties)validProp.clone();
		badCustomFactoryProp.setProperty(KEY_TAP_FACTORY, "{tap.config.TestConfigurableServiceConnection$BadCustomTAPFactory}");
	}

	/**
@@ -855,6 +868,24 @@ public class TestConfigurableServiceConnection {
			assertEquals(TAPException.class, e.getClass());
			assertEquals("Wrong UDF declaration syntax: missing closing bracket at position 24!", e.getMessage());
		}

		// Valid custom TAPFactory:
		try{
			ServiceConnection connection = new ConfigurableServiceConnection(customFactoryProp);
			assertNotNull(connection.getFactory());
			assertEquals(CustomTAPFactory.class, connection.getFactory().getClass());
		}catch(Exception e){
			fail("This MUST have succeeded because the given custom TAPFactory exists and have the required constructor! \nCaught exception: " + getPertinentMessage(e));
		}

		// Bad custom TAPFactory (required constructor missing):
		try{
			new ConfigurableServiceConnection(badCustomFactoryProp);
			fail("This MUST have failed because the specified TAPFactory extension does not have a constructor with ServiceConnection!");
		}catch(Exception e){
			assertEquals(TAPException.class, e.getClass());
			assertEquals("Missing constructor tap.config.TestConfigurableServiceConnection$BadCustomTAPFactory(tap.ServiceConnection)! See the value \"{tap.config.TestConfigurableServiceConnection$BadCustomTAPFactory}\" of the property \"" + KEY_TAP_FACTORY + "\".", e.getMessage());
		}
	}

	public static final String getPertinentMessage(final Exception ex){
@@ -898,4 +929,61 @@ public class TestConfigurableServiceConnection {

	}

	/**
	 * TAPFactory just to test whether the property tap_factory works well.
	 * 
	 * @author Gr&eacute;gory Mantelet (ARI)
	 * @version 02/2015
	 */
	private static class CustomTAPFactory extends AbstractTAPFactory {

		private final JDBCConnection dbConn;

		public CustomTAPFactory(final ServiceConnection conn) throws DBException{
			super(conn);
			dbConn = new JDBCConnection("", "jdbc:postgresql:gmantele", "gmantele", null, new PostgreSQLTranslator(), "TheOnlyConnection", conn.getLogger());
		}

		@Override
		public DBConnection getConnection(final String jobID) throws TAPException{
			return dbConn;
		}

		@Override
		public void freeConnection(final DBConnection conn){}

		@Override
		public void destroy(){
			try{
				dbConn.getInnerConnection().close();
			}catch(Exception ex){}
		}

	}

	/**
	 * TAPFactory just to test whether the property tap_factory is rejected when no constructor with a single parameter of type ServiceConnection exists.
	 * 
	 * @author Gr&eacute;gory Mantelet (ARI)
	 * @version 02/2015
	 */
	private static class BadCustomTAPFactory extends AbstractTAPFactory {

		public BadCustomTAPFactory() throws DBException{
			super(null);
		}

		@Override
		public DBConnection getConnection(final String jobID) throws TAPException{
			return null;
		}

		@Override
		public void freeConnection(final DBConnection conn){}

		@Override
		public void destroy(){}

	}

}