private static void bind()

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