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");