in core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java [539:698]
private static void bind(BeanFactoryDefinition<?, ?> beanFactory, RouteTemplateContext routeTemplateContext)
throws Exception {
final Map<String, Object> props = new HashMap<>();
if (beanFactory.getProperties() != null) {
props.putAll(beanFactory.getProperties());
}
if (beanFactory.getPropertyDefinitions() != null) {
beanFactory.getPropertyDefinitions().forEach(p -> props.put(p.getKey(), p.getValue()));
}
if (beanFactory.getBeanSupplier() != null) {
if (props.isEmpty()) {
// bean class is optional for supplier
if (beanFactory.getBeanClass() != null) {
routeTemplateContext.bind(beanFactory.getName(), beanFactory.getBeanClass(), beanFactory.getBeanSupplier());
} else {
routeTemplateContext.bind(beanFactory.getName(), beanFactory.getBeanSupplier());
}
}
} else if (beanFactory.getScript() != null) {
final String script = beanFactory.getScript();
final CamelContext camelContext = routeTemplateContext.getCamelContext();
final Language lan = camelContext.resolveLanguage(beanFactory.getType());
final Class<?> clazz;
if (beanFactory.getBeanType() != null) {
clazz = camelContext.getClassResolver().resolveMandatoryClass(beanFactory.getBeanType());
} else {
if (beanFactory.getBeanClass() != null) {
clazz = beanFactory.getBeanClass();
} else {
clazz = Object.class;
}
}
final ScriptingLanguage slan = lan instanceof ScriptingLanguage ? (ScriptingLanguage) lan : null;
if (slan != null) {
// scripting language should be evaluated with route template context as binding
// and memorize so the script is only evaluated once and the local bean is the same
// if a route template refers to the local bean multiple times
routeTemplateContext.bind(beanFactory.getName(), clazz, Suppliers.memorize(() -> {
Map<String, Object> bindings = new HashMap<>();
// use rtx as the short-hand name, as context would imply its CamelContext
bindings.put("rtc", routeTemplateContext);
Object local = slan.evaluate(script, bindings, clazz);
if (!props.isEmpty()) {
PropertyBindingSupport.setPropertiesOnTarget(camelContext, local, props);
}
return local;
}));
} else {
// exchange based languages needs a dummy exchange to be evaluated
// and memorize so the script is only evaluated once and the local bean is the same
// if a route template refers to the local bean multiple times
routeTemplateContext.bind(beanFactory.getName(), clazz, Suppliers.memorize(() -> {
ExchangeFactory ef = camelContext.getCamelContextExtension().getExchangeFactory();
Exchange dummy = ef.create(false);
try {
String text = ScriptHelper.resolveOptionalExternalScript(camelContext, dummy, script);
if (text != null) {
Expression exp = lan.createExpression(text);
Object local = exp.evaluate(dummy, clazz);
if (!props.isEmpty()) {
PropertyBindingSupport.setPropertiesOnTarget(camelContext, local, props);
}
return local;
} else {
return null;
}
} finally {
ef.release(dummy);
}
}));
}
} else if (beanFactory.getBeanClass() != null
|| beanFactory.getType() != null && beanFactory.getType().startsWith("#class:")) {
// if there is a factory method then the class/bean should be created in a different way
String className = null;
String factoryMethod = null;
String parameters = null;
if (beanFactory.getType() != null) {
className = beanFactory.getType().substring(7);
if (className.endsWith(")") && className.indexOf('(') != -1) {
parameters = StringHelper.after(className, "(");
parameters = parameters.substring(0, parameters.length() - 1); // clip last )
className = StringHelper.before(className, "(");
}
if (className != null && className.indexOf('#') != -1) {
factoryMethod = StringHelper.after(className, "#");
className = StringHelper.before(className, "#");
}
}
if (className != null && (factoryMethod != null || parameters != null)) {
final CamelContext camelContext = routeTemplateContext.getCamelContext();
final Class<?> clazz = camelContext.getClassResolver().resolveMandatoryClass(className);
final String fqn = className;
final String fm = factoryMethod;
final String fp = parameters;
routeTemplateContext.bind(beanFactory.getName(), Object.class, Suppliers.memorize(() -> {
// resolve placeholders in parameters
String params = camelContext.resolvePropertyPlaceholders(fp);
try {
Object local;
if (fm != null) {
if (fp != null) {
// special to support factory method parameters
local = PropertyBindingSupport.newInstanceFactoryParameters(camelContext, clazz, fm, params);
} else {
local = camelContext.getInjector().newInstance(clazz, fm);
}
if (local == null) {
throw new IllegalStateException(
"Cannot create bean instance using factory method: " + fqn + "#" + fm);
}
} else {
// special to support constructor parameters
local = PropertyBindingSupport.newInstanceConstructorParameters(camelContext, clazz, params);
}
if (!props.isEmpty()) {
PropertyBindingSupport.setPropertiesOnTarget(camelContext, local, props);
}
return local;
} catch (Exception e) {
throw new IllegalStateException(
"Cannot create bean: " + beanFactory.getType());
}
}));
} else {
final CamelContext camelContext = routeTemplateContext.getCamelContext();
Class<?> clazz = beanFactory.getBeanClass() != null
? beanFactory.getBeanClass() : camelContext.getClassResolver().resolveMandatoryClass(className);
// we only have the bean class so we use that to create a new bean via the injector
// and memorize so the bean is only created once and the local bean is the same
// if a route template refers to the local bean multiple times
routeTemplateContext.bind(beanFactory.getName(), clazz,
Suppliers.memorize(() -> {
Object local = camelContext.getInjector().newInstance(clazz);
if (!props.isEmpty()) {
PropertyBindingSupport.setPropertiesOnTarget(camelContext, local, props);
}
return local;
}));
}
} else if (beanFactory.getType() != null && beanFactory.getType().startsWith("#type:")) {
final CamelContext camelContext = routeTemplateContext.getCamelContext();
Class<?> clazz = camelContext.getClassResolver().resolveMandatoryClass(beanFactory.getType().substring(6));
Set<?> found = camelContext.getRegistry().findByType(clazz);
if (found == null || found.isEmpty()) {
throw new NoSuchBeanException(null, clazz.getName());
} else if (found.size() > 1) {
throw new NoSuchBeanException(
"Found " + found.size() + " beans of type: " + clazz + ". Only one bean expected.");
} else {
// do not set properties when using #type as it uses an existing shared bean
routeTemplateContext.bind(beanFactory.getName(), clazz, found.iterator().next());
}
} else {
// invalid syntax for the local bean, so lets report an exception
throw new IllegalArgumentException(
"Route template local bean: " + beanFactory.getName() + " has invalid type syntax: " + beanFactory.getType()
+ ". To refer to a class then prefix the value with #class such as: #class:fullyQualifiedClassName");
}
}