Repository: nifi Updated Branches: refs/heads/master 8b2c5b724 -> 9cd0aab69
NIFI-4918: looping over several methods to try and fit the dynamic attribute. If failed, use first method and throw error if not working. Array.length can never be less then 0 This closes #2499. Signed-off-by: Mark Payne <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/nifi/repo Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/9cd0aab6 Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/9cd0aab6 Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/9cd0aab6 Branch: refs/heads/master Commit: 9cd0aab696971d00b4ca32defde1b60cafb21d27 Parents: 8b2c5b7 Author: Julian Gimbel <[email protected]> Authored: Wed Feb 28 13:39:32 2018 +0100 Committer: Mark Payne <[email protected]> Committed: Fri Mar 16 14:40:59 2018 -0400 ---------------------------------------------------------------------- .../jms/cf/JMSConnectionFactoryProvider.java | 40 +++++++++++--------- .../main/java/org/apache/nifi/jms/cf/Utils.java | 35 ++++++++++++++++- 2 files changed, 56 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd0aab6/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/java/org/apache/nifi/jms/cf/JMSConnectionFactoryProvider.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/java/org/apache/nifi/jms/cf/JMSConnectionFactoryProvider.java b/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/java/org/apache/nifi/jms/cf/JMSConnectionFactoryProvider.java index 85d5ffb..5c822be 100644 --- a/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/java/org/apache/nifi/jms/cf/JMSConnectionFactoryProvider.java +++ b/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/java/org/apache/nifi/jms/cf/JMSConnectionFactoryProvider.java @@ -64,8 +64,8 @@ import org.slf4j.LoggerFactory; + "ConnectionFactory can be served once this service is configured successfully") @DynamicProperty(name = "The name of a Connection Factory configuration property.", value = "The value of a given Connection Factory configuration property.", description = "The properties that are set following Java Beans convention where a property name is derived from the 'set*' method of the vendor " - + "specific ConnectionFactory's implementation. For example, 'com.ibm.mq.jms.MQConnectionFactory.setChannel(String)' would imply 'channel' " - + "property and 'com.ibm.mq.jms.MQConnectionFactory.setTransportType(int)' would imply 'transportType' property.") + + "specific ConnectionFactory's implementation. For example, 'com.ibm.mq.jms.MQConnectionFactory.setChannel(String)' would imply 'channel' " + + "property and 'com.ibm.mq.jms.MQConnectionFactory.setTransportType(int)' would imply 'transportType' property.") @SeeAlso(classNames = {"org.apache.nifi.jms.processors.ConsumeJMS", "org.apache.nifi.jms.processors.PublishJMS"}) public class JMSConnectionFactoryProvider extends AbstractControllerService implements JMSConnectionFactoryProviderDefinition { @@ -138,7 +138,6 @@ public class JMSConnectionFactoryProvider extends AbstractControllerService impl } /** - * * @return new instance of {@link ConnectionFactory} */ @Override @@ -187,7 +186,7 @@ public class JMSConnectionFactoryProvider extends AbstractControllerService impl * service configuration. For example, 'channel' property will correspond to * 'setChannel(..) method and 'queueManager' property will correspond to * setQueueManager(..) method with a single argument. - * + * <p> * There are also few adjustments to accommodate well known brokers. For * example ActiveMQ ConnectionFactory accepts address of the Message Broker * in a form of URL while IBMs in the form of host/port pair (more common). @@ -243,7 +242,7 @@ public class JMSConnectionFactoryProvider extends AbstractControllerService impl * 'propertyName'. For example, 'channel' property will correspond to * 'setChannel(..) method and 'queueManager' property will correspond to * setQueueManager(..) method with a single argument. - * + * <p> * NOTE: There is a limited type conversion to accommodate property value * types since all NiFi configuration properties comes as String. It is * accomplished by checking the argument type of the method and executing @@ -257,21 +256,26 @@ public class JMSConnectionFactoryProvider extends AbstractControllerService impl */ private void setProperty(String propertyName, Object propertyValue) { String methodName = this.toMethodName(propertyName); - Method method = Utils.findMethod(methodName, this.connectionFactory.getClass()); - if (method != null) { + Method[] methods = Utils.findMethods(methodName, this.connectionFactory.getClass()); + if (methods != null && methods.length > 0) { try { - Class<?> returnType = method.getParameterTypes()[0]; - if (String.class.isAssignableFrom(returnType)) { - method.invoke(this.connectionFactory, propertyValue); - } else if (int.class.isAssignableFrom(returnType)) { - method.invoke(this.connectionFactory, Integer.parseInt((String) propertyValue)); - } else if (long.class.isAssignableFrom(returnType)) { - method.invoke(this.connectionFactory, Long.parseLong((String) propertyValue)); - } else if (boolean.class.isAssignableFrom(returnType)) { - method.invoke(this.connectionFactory, Boolean.parseBoolean((String) propertyValue)); - } else { - method.invoke(this.connectionFactory, propertyValue); + for (Method method : methods) { + Class<?> returnType = method.getParameterTypes()[0]; + if (String.class.isAssignableFrom(returnType)) { + method.invoke(this.connectionFactory, propertyValue); + return; + } else if (int.class.isAssignableFrom(returnType)) { + method.invoke(this.connectionFactory, Integer.parseInt((String) propertyValue)); + return; + } else if (long.class.isAssignableFrom(returnType)) { + method.invoke(this.connectionFactory, Long.parseLong((String) propertyValue)); + return; + } else if (boolean.class.isAssignableFrom(returnType)) { + method.invoke(this.connectionFactory, Boolean.parseBoolean((String) propertyValue)); + return; + } } + methods[0].invoke(this.connectionFactory, propertyValue); } catch (Exception e) { throw new IllegalStateException("Failed to set property " + propertyName, e); } http://git-wip-us.apache.org/repos/asf/nifi/blob/9cd0aab6/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/java/org/apache/nifi/jms/cf/Utils.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/java/org/apache/nifi/jms/cf/Utils.java b/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/java/org/apache/nifi/jms/cf/Utils.java index cd191c3..912f2c0 100644 --- a/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/java/org/apache/nifi/jms/cf/Utils.java +++ b/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/java/org/apache/nifi/jms/cf/Utils.java @@ -20,6 +20,9 @@ import java.io.File; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,7 +53,7 @@ public final class Utils { * Finds a method by name on the target class. If more then one method * present it will return the first one encountered. * - * @param name method name + * @param name method name * @param targetClass instance of target class * @return instance of {@link Method} */ @@ -69,6 +72,36 @@ public final class Utils { } /** + * Finds a method by name on the target class. If more then one method + * present it will return the first one encountered. + * + * @param name method name + * @param targetClass instance of target class + * @return Array of {@link Method} + */ + public static Method[] findMethods(String name, Class<?> targetClass) { + Class<?> searchType = targetClass; + ArrayList<Method> fittingMethods = new ArrayList<>(); + while (searchType != null) { + Method[] methods = (searchType.isInterface() ? searchType.getMethods() : searchType.getDeclaredMethods()); + for (Method method : methods) { + if (name.equals(method.getName())) { + fittingMethods.add(method); + } + } + searchType = searchType.getSuperclass(); + } + if (fittingMethods.isEmpty()) { + return null; + } else { + //Sort so that in case there are two methods that accept the parameter type + //as first param use the one which accepts fewer parameters in total + Collections.sort(fittingMethods, Comparator.comparing(Method::getParameterCount)); + return fittingMethods.toArray(new Method[fittingMethods.size()]); + } + } + + /** * Adds content of the directory specified with 'path' to the classpath. It * does so by creating a new instance of the {@link URLClassLoader} using * {@link URL}s created from listing the contents of the directory denoted
