Author: davsclaus
Date: Mon Jul 25 19:47:06 2011
New Revision: 1150865

URL: http://svn.apache.org/viewvc?rev=1150865&view=rev
Log:
CAMEL-3961: Bean component supports parameter values directly in the method 
name option.

Added:
    
camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanHelper.java
Modified:
    
camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java
    
camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java
    
camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/BeanOverloadedMethodParameterValueTest.java

Added: 
camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanHelper.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanHelper.java?rev=1150865&view=auto
==============================================================================
--- 
camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanHelper.java
 (added)
+++ 
camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanHelper.java
 Mon Jul 25 19:47:06 2011
@@ -0,0 +1,115 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.bean;
+
+import org.apache.camel.language.simple.SimpleLanguage;
+import org.apache.camel.spi.ClassResolver;
+import org.apache.camel.util.ObjectHelper;
+
+/**
+ *
+ */
+public final class BeanHelper {
+
+    private BeanHelper() {
+        // utility class
+    }
+
+    /**
+     * Determines if the given value is valid according to the supported
+     * values by the bean component.
+     *
+     * @param value the value
+     * @return <tt>true</tt> if valid, <tt>false</tt> otherwise
+     */
+    public static boolean isValidParameterValue(String value) {
+        if (ObjectHelper.isEmpty(value)) {
+            // empty value is valid
+            return true;
+        }
+
+        // trim value
+        value = value.trim();
+
+        // single quoted is valid
+        if (value.startsWith("'") && value.endsWith("'")) {
+            return true;
+        }
+
+        // double quoted is valid
+        if (value.startsWith("\"") && value.endsWith("\"")) {
+            return true;
+        }
+
+        // true or false is valid (boolean)
+        if (value.equals("true") || value.equals("false")) {
+            return true;
+        }
+
+        // simple language tokens is valid
+        if (SimpleLanguage.hasStartToken(value)) {
+            return true;
+        }
+
+        // numeric is valid
+        boolean numeric = true;
+        for (char ch : value.toCharArray()) {
+            if (!Character.isDigit(ch)) {
+                numeric = false;
+                break;
+            }
+        }
+        return numeric;
+    }
+
+    /**
+     * Determines if the given parameter type is assignable to the expected 
type.
+     * <p/>
+     * This implementation will check if the given parameter type matches the 
expected type as class using either
+     * <ul>
+     *     <li>FQN class name - com.foo.MyOrder</li>
+     *     <li>Simple class name - MyOrder</li>
+     * </ul>
+     * If the given parameter type is <b>not</b> a class, then <tt>false</tt> 
is returned
+     *
+     * @param resolver          the class resolver
+     * @param parameterType     the parameter type as a String, can be a FQN 
or a simple name of the class
+     * @param expectedType      the expected type
+     * @return <tt>null</tt> if parameter type is <b>not</b> a class, 
<tt>true</tt> if parameter type is assignable, <tt>false</tt> otherwise
+     */
+    public static Boolean isAssignableToExpectedType(ClassResolver resolver, 
String parameterType, Class<?> expectedType) {
+        // if its a class, then it should be assignable
+        Class<?> parameterClass = resolver.resolveClass(parameterType);
+        if (parameterClass == null && 
parameterType.equals(expectedType.getSimpleName())) {
+            // it was not the FQN class name, but the simple name instead, so 
we can infer the type
+            parameterClass = expectedType;
+        }
+
+        // if there was a class, then it must be assignable to match
+        if (parameterClass != null) {
+            if (!parameterClass.isAssignableFrom(expectedType)) {
+                return false;
+            } else {
+                return true;
+            }
+        }
+
+        // not a class so return null
+        return null;
+    }
+
+}

Modified: 
camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java?rev=1150865&r1=1150864&r2=1150865&view=diff
==============================================================================
--- 
camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java
 (original)
+++ 
camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java
 Mon Jul 25 19:47:06 2011
@@ -717,10 +717,13 @@ public class BeanInfo {
             Iterator it = ObjectHelper.createIterator(types);
             for (int i = 0; i < method.getParameterTypes().length; i++) {
                 if (it.hasNext()) {
+                    Class<?> parameterType = method.getParameterTypes()[i];
+
                     String qualifyType = (String) it.next();
                     if (ObjectHelper.isEmpty(qualifyType)) {
                         continue;
                     }
+                    // trim the time
                     qualifyType = qualifyType.trim();
 
                     if ("*".equals(qualifyType)) {
@@ -728,27 +731,16 @@ public class BeanInfo {
                         continue;
                     }
 
-                    if (qualifyType.startsWith("'") || 
qualifyType.startsWith("\"")) {
-                        // if the type starts with a quote, then its a 
parameter value instead
+                    if (BeanHelper.isValidParameterValue(qualifyType)) {
+                        // its a parameter value, so continue to next parameter
+                        // as we should only check for FQN/type parameters
                         continue;
                     }
 
-                    // so it can either be a type or a parameter value
-                    // - type: Boolean, String etc.
-                    // - value: true, 5, 'Hello World' etc
-
-                    Class<?> qualifyClass = 
getCamelContext().getClassResolver().resolveClass(qualifyType);
-                    // class resolver will return null if not a class
-                    if (qualifyClass != null) {
-                        Class<?> parameterClass = 
method.getParameterTypes()[i];
-                        if (!parameterClass.isAssignableFrom(qualifyClass)) {
-                            return false;
-                        }
-                    }
-
-                    // maybe its a FQN for simple name
-                    if 
(qualifyType.equals(method.getParameterTypes()[i].getSimpleName())) {
-                        continue;
+                    // if qualify type indeed is a class, then it must be 
assignable with the parameter type
+                    Boolean assignable = 
BeanHelper.isAssignableToExpectedType(getCamelContext().getClassResolver(), 
qualifyType, parameterType);
+                    if (assignable != null && !assignable) {
+                        return false;
                     }
 
                 } else {

Modified: 
camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java?rev=1150865&r1=1150864&r2=1150865&view=diff
==============================================================================
--- 
camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java
 (original)
+++ 
camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java
 Mon Jul 25 19:47:06 2011
@@ -403,45 +403,43 @@ public class MethodInfo {
             private Object evaluateParameterValue(Exchange exchange, int 
index, Object parameterValue, Class<?> parameterType) {
                 Object answer = null;
 
-                // at first evaluate it as a simple expression as it may 
contain references to headers, etc
+                // convert the parameter value to a String
                 String exp = 
exchange.getContext().getTypeConverter().convertTo(String.class, 
parameterValue);
                 if (exp != null) {
                     // must trim first as there may be spaces between 
parameters
                     exp = exp.trim();
+                    // check if its a valid parameter value
+                    boolean valid = BeanHelper.isValidParameterValue(exp);
 
-                    // TODO: make rule about how a parameter value should be 
defined
-                    // and use this rule to pre determine if its class or not
-                    // - boolean as true|false
-                    // - numeric such as 5, 7, 123
-                    // - string literals which must be quoted, either single 
or double
-
-                    // so it can either be a type or a parameter value
-                    // - type: Boolean, String etc.
-                    // - value: true, 5, 'Hello World' etc
-                    boolean isClass = false;
-                    if (exp.startsWith("'") || exp.startsWith("\"")) {
-                        // if the type starts with a quote, then its a 
parameter value
-                        exp = StringHelper.removeLeadingAndEndingQuotes(exp);
-                    } else {
-                        // it could be a type, so lets so if we can resolve 
the class
-                        Class<?> expClass = 
exchange.getContext().getClassResolver().resolveClass(exp);
-                        if (expClass != null) {
-                            isClass = true;
-                        } else {
-                            // lets try to match by simple name as well
-                            if (exp.equals(parameterType.getSimpleName())) {
-                                isClass = true;
-                            }
+                    if (!valid) {
+                        // it may be a parameter type instead, and if so, then 
we should return null,
+                        // as this method is only for evaluating parameter 
values
+                        Boolean isClass = 
BeanHelper.isAssignableToExpectedType(exchange.getContext().getClassResolver(), 
exp, parameterType);
+                        // the method will return a non null value if exp is a 
class
+                        if (isClass != null) {
+                            return null;
                         }
                     }
 
-                    // if its a parameter value (not a class) then use the 
simple expression language to evaluate the expression
-                    // and convert the result to the parameter type, so we can 
pass in the result to the method, when we invoke it
-                    if (!isClass) {
-                        parameterValue = 
exchange.getContext().resolveLanguage("simple").createExpression(exp).evaluate(exchange,
 Object.class);
-                        if (parameterValue != null) {
+                    // use simple language to evaluate the expression, as it 
may use the simple language to refer to message body, headers etc.
+                    parameterValue = 
exchange.getContext().resolveLanguage("simple").createExpression(exp).evaluate(exchange,
 Object.class);
+                    if (parameterValue != null) {
+                        // the parameter value was not already valid, but 
since the simple language have evaluated the expression
+                        // which may change the parameterValue, so we have to 
check it again to see if its now valid
+                        exp = 
exchange.getContext().getTypeConverter().convertTo(String.class, 
parameterValue);
+                        // String values from the simple language is always 
valid
+                        if (!valid) {
+                            // re validate if the parameter was not valid the 
first time (String values should be accepted)
+                            valid = parameterValue instanceof String || 
BeanHelper.isValidParameterValue(exp);
+                        }
+
+                        if (valid) {
+                            // we need to unquote String parameters, as the 
enclosing quotes is there to denote a parameter value
+                            if (parameterValue instanceof String) {
+                                parameterValue = 
StringHelper.removeLeadingAndEndingQuotes((String) parameterValue);
+                            }
                             try {
-                                // we got a value now try to convert it to the 
expected type
+                                // its a valid parameter value, so convert it 
to the expected type of the parameter
                                 answer = 
exchange.getContext().getTypeConverter().mandatoryConvertTo(parameterType, 
parameterValue);
                                 if (LOG.isTraceEnabled()) {
                                     LOG.trace("Parameter #{} evaluated as: {} 
type: ", new Object[]{index, answer, ObjectHelper.type(answer)});

Modified: 
camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/BeanOverloadedMethodParameterValueTest.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/BeanOverloadedMethodParameterValueTest.java?rev=1150865&r1=1150864&r2=1150865&view=diff
==============================================================================
--- 
camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/BeanOverloadedMethodParameterValueTest.java
 (original)
+++ 
camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/BeanOverloadedMethodParameterValueTest.java
 Mon Jul 25 19:47:06 2011
@@ -149,6 +149,26 @@ public class BeanOverloadedMethodParamet
             @Override
             public void configure() throws Exception {
                 from("direct:start")
+                    .bean(MyBean.class, "times(byte[], header.times)")
+                    .to("mock:result");
+
+            }
+        });
+        context.start();
+
+        getMockEndpoint("mock:result").expectedBodiesReceived("ABC,ABC,ABC");
+
+        template.sendBodyAndHeader("direct:start", "ABC".getBytes(), "times", 
"3");
+
+        assertMockEndpointsSatisfied();
+    }
+
+
+    public void testTimesOverloadedBytesIntLanguageTokens() throws Exception {
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
                     .bean(MyBean.class, "times(byte[],${header.times})")
                     .to("mock:result");
 


Reply via email to