From 50a31ac0aa2553f6be60bf10ddb7d277d69ab435 Mon Sep 17 00:00:00 2001
From: gmantele <gmantele@ari.uni-heidelberg.de>
Date: Mon, 8 Feb 2016 14:29:24 +0100
Subject: [PATCH] [TAP] Allow usage of a custom TAPFactory extending
 ConfigurableTAPFactory with a constructor having a Properties object loaded
 with the content of the current configuration file.

---
 .../config/ConfigurableServiceConnection.java |  7 ++-
 src/tap/config/TAPConfiguration.java          | 44 +++++++++++++++++--
 2 files changed, 45 insertions(+), 6 deletions(-)

diff --git a/src/tap/config/ConfigurableServiceConnection.java b/src/tap/config/ConfigurableServiceConnection.java
index 9ed6d13..341f577 100644
--- a/src/tap/config/ConfigurableServiceConnection.java
+++ b/src/tap/config/ConfigurableServiceConnection.java
@@ -16,7 +16,7 @@ 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 2016 - Astronomisches Rechen Institut (ARI)
  */
 
 import static tap.config.TAPConfiguration.DEFAULT_ASYNC_FETCH_SIZE;
@@ -73,6 +73,7 @@ import static tap.config.TAPConfiguration.VALUE_VOTABLE;
 import static tap.config.TAPConfiguration.VALUE_XML;
 import static tap.config.TAPConfiguration.fetchClass;
 import static tap.config.TAPConfiguration.getProperty;
+import static tap.config.TAPConfiguration.hasConstructor;
 import static tap.config.TAPConfiguration.isClassName;
 import static tap.config.TAPConfiguration.newInstance;
 import static tap.config.TAPConfiguration.parseLimit;
@@ -124,7 +125,7 @@ import adql.query.operand.function.UserDefinedFunction;
  * </p>
  * 
  * @author Gr&eacute;gory Mantelet (ARI)
- * @version 2.1 (10/2015)
+ * @version 2.1 (02/2016)
  * @since 2.0
  */
 public final class ConfigurableServiceConnection implements ServiceConnection {
@@ -412,6 +413,8 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
 		String propValue = getProperty(tapConfig, KEY_TAP_FACTORY);
 		if (propValue == null)
 			tapFactory = new ConfigurableTAPFactory(this, tapConfig);
+		else if (hasConstructor(propValue, KEY_TAP_FACTORY, TAPFactory.class, new Class<?>[]{ServiceConnection.class,Properties.class}))
+			tapFactory = newInstance(propValue, KEY_TAP_FACTORY, TAPFactory.class, new Class<?>[]{ServiceConnection.class,Properties.class}, new Object[]{this,tapConfig});
 		else
 			tapFactory = newInstance(propValue, KEY_TAP_FACTORY, TAPFactory.class, new Class<?>[]{ServiceConnection.class}, new Object[]{this});
 	}
diff --git a/src/tap/config/TAPConfiguration.java b/src/tap/config/TAPConfiguration.java
index cd67040..7e3e39f 100644
--- a/src/tap/config/TAPConfiguration.java
+++ b/src/tap/config/TAPConfiguration.java
@@ -187,7 +187,7 @@ public final class TAPConfiguration {
 	/** Name/Key of the property specifying the MIME type of the set home page.
 	 * By default, "text/html" is set. */
 	public final static String KEY_HOME_PAGE_MIME_TYPE = "home_page_mime_type";
-	
+
 	/* EXAMPLES KEY */
 	/** <p>Name/Key of the property specifying the content of the <code>/examples</code> endpoint.
 	 * It can be a file or a URL. If null, the TAP service will not have any
@@ -332,7 +332,8 @@ public final class TAPConfiguration {
 	 * 
 	 * @return	The corresponding Class object.
 	 * 
-	 * @throws TAPException	If the class name is incorrect or if its type is not compatible with the parameterized type C (represented by the parameter "expectedType").
+	 * @throws TAPException	If the class name is incorrect
+	 *                     	or if its type is not compatible with the parameterized type C (represented by the parameter "expectedType").
 	 * 
 	 * @see #isClassName(String)
 	 */
@@ -358,13 +359,48 @@ public final class TAPConfiguration {
 		}
 	}
 
+	/**
+	 * Test whether the specified class has a constructor with the specified parameters.
+	 * 
+	 * @param propValue		Value which is supposed to contain the class name between brackets (see {@link #isClassName(String)} for more details)
+	 * @param propName		Name of the property associated with the parameter "propValue".
+	 * @param expectedType	Type of the class expected to be returned ; it is also the type which parameterizes this function: C.
+	 * @param pTypes		List of each constructor parameter type. Each type MUST be exactly the type declared in the class constructor to select. <i>NULL or empty array if no parameter.</i>
+	 * 
+	 * @return	<code>true</code> if the specified class has a constructor with the specified parameters,
+	 *        	<code>false</code> otherwise.
+	 * 
+	 * @throws TAPException	If the class name is incorrect
+	 *                     	or if its type is not compatible with the parameterized type C (represented by the parameter "expectedType").
+	 * 
+	 * @since 2.1
+	 */
+	public final static < C > boolean hasConstructor(final String propValue, final String propName, final Class<C> expectedType, final Class<?>[] pTypes) throws TAPException{
+		// Ensure the given name is a class name specification:
+		if (!isClassName(propValue))
+			throw new TAPException("Class name expected for the property \"" + propName + "\" instead of: \"" + propValue + "\"! The specified class must extend/implement " + expectedType.getName() + ".");
+
+		// Fetch the class object:
+		Class<? extends C> classObj = fetchClass(propValue, propName, expectedType);
+		try{
+
+			// Get a constructor matching the given parameters list:
+			classObj.getConstructor((pTypes == null) ? new Class<?>[0] : pTypes);
+
+			return true;
+
+		}catch(Exception e){
+			return false;
+		}
+	}
+
 	/**
 	 * <p>Create an instance of the specified class. The class name is expected to be surrounded by {} in the given value.</p>
 	 * 
 	 * <p>The instance is created using the empty constructor of the specified class.</p>
 	 * 
 	 * @param propValue		Value which is supposed to contain the class name between brackets (see {@link #isClassName(String)} for more details)
-	 * @param propName		Name of the property associated with the parameter "value".
+	 * @param propName		Name of the property associated with the parameter "propValue".
 	 * @param expectedType	Type of the class expected to be returned ; it is also the type which parameterizes this function: C.
 	 * 
 	 * @return	The corresponding instance.
@@ -390,7 +426,7 @@ public final class TAPConfiguration {
 	 * </p>
 	 * 
 	 * @param propValue		Value which is supposed to contain the class name between brackets (see {@link #isClassName(String)} for more details)
-	 * @param propName		Name of the property associated with the parameter "value".
+	 * @param propName		Name of the property associated with the parameter "propValue".
 	 * @param expectedType	Type of the class expected to be returned ; it is also the type which parameterizes this function: C.
 	 * @param pTypes		List of each constructor parameter type. Each type MUST be exactly the type declared in the class constructor to select. <i>NULL or empty array if no parameter.</i>
 	 * @param parameters	List of all constructor parameters. The number of object MUST match exactly the number of classes provided in the parameter pTypes. <i>NULL or empty array if no parameter.</i>
-- 
GitLab