Camel in CDI context

Hi

It looks like the CamelBehavior class expects a SpringProcessEngineConfiguration, as per below.

Is there any way to get it working in a CDI context?

            // Convert it to a SpringProcessEngineConfiguration. If this doesn't work, throw a RuntimeException.
            try {
                SpringProcessEngineConfiguration springConfiguration = (SpringProcessEngineConfiguration) engineConfiguration;
                if (StringUtils.isEmpty(camelContextValue) && camelContextObj == null) {
                    camelContextValue = springConfiguration.getDefaultCamelContext();
                }

                // Get the CamelContext object and set the super's member variable.
                Object ctx = springConfiguration.getApplicationContext().getBean(camelContextValue);
                if (!(ctx instanceof CamelContext)) {
                    throw new FlowableException("Could not find CamelContext named " + camelContextValue + ".");

thanks

The Camel integration runs from the same Spring configuration as the Flowable Engine, that’s why a SpringProcessEngineConfiguration is expected. When using it from a CDI context, you could use Camel in a separate context and communicate via VM queues for example. But then you need to create a custom CamelBehavior to use the VM queues instead of default implementation.

Best regards,

Tijs

Thanks, I did indeed implement a custom CamelBehaviour and overrode the DefaultActivityBehaviorFactory.

I used the spring option for configuring the CdiJtaProcessEngineConfiguration as per section 16.2.1 in the manual (but hope to remove dependency on spring context).

<bean id="processEngineConfiguration"
    class="org.flowable.cdi.CdiJtaProcessEngineConfiguration">
    ....
    <property name="activityBehaviorFactory" ref="cdiActivityBehaviourFactory"/>
</bean>

BehaviorFactory (oops British spelling on my side):

public class CdiActivityBehaviourFactory extends DefaultActivityBehaviorFactory {

    @Override
    protected ActivityBehavior createCamelActivityBehavior(TaskWithFieldExtensions task,
            List<FieldExtension> fieldExtensions) {
        try {
            Class<?> theClass = null;
            FieldExtension behaviorExtension = null;
            for (FieldExtension fieldExtension : fieldExtensions) {
                if ("camelBehaviorClass".equals(fieldExtension.getFieldName())
                        && StringUtils.isNotEmpty(fieldExtension.getStringValue())) {
                    theClass = Class.forName(fieldExtension.getStringValue());
                    behaviorExtension = fieldExtension;
                    break;
                }
            }

            if (behaviorExtension != null) {
                fieldExtensions.remove(behaviorExtension);
            }

            if (theClass == null) {
                // Default Camel behavior class
                theClass = Class.forName("some.pkg.flowable.CdiCamelBehavior");
            }

            List<FieldDeclaration> fieldDeclarations = createFieldDeclarations(fieldExtensions);
            addExceptionMapAsFieldDeclaration(fieldDeclarations, task.getMapExceptions());
            return (ActivityBehavior) ClassDelegate.defaultInstantiateDelegate(theClass, fieldDeclarations);

        } catch (ClassNotFoundException e) {
            throw new FlowableException("Could not find some.pkg.flowable.CdiCamelBehavior: ", e);
        }
    }

    private void addExceptionMapAsFieldDeclaration(List<FieldDeclaration> fieldDeclarations,
            List<MapExceptionEntry> mapExceptions) {
        FieldDeclaration exceptionMapsFieldDeclaration = new FieldDeclaration(EXCEPTION_MAP_FIELD,
                mapExceptions.getClass().toString(), mapExceptions);
        fieldDeclarations.add(exceptionMapsFieldDeclaration);
    }

}

The behaviour factory actually only needs the class name for the custom behaviour. A small change to the DefaultBehaviorFactory could make the class name a property or a retrievable via a protected method and then the above would be a very small class.

I only created one behaviour implementation for now, instead of the 3 available for spring (not sure about caching the BeanManager:

public class CdiCamelBehavior extends CamelBehavior {
    private static final long serialVersionUID = 1L;
    BeanManager beanManager = null;

    public CdiCamelBehavior() {
        try {
            InitialContext context = new InitialContext();
            beanManager = (BeanManager) context.lookup("java:comp/BeanManager");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void setPropertTargetVariable(FlowableEndpoint endpoint) {
        toTargetType = TargetType.PROPERTIES;
    }

    @Override
    protected void setAppropriateCamelContext(DelegateExecution execution) {
        String camelContextValue = getStringFromField(camelContext, execution);
        if (StringUtils.isEmpty(camelContextValue) && camelContextObj != null) {
            // already set no further processing needed
        } else {
            if (StringUtils.isEmpty(camelContextValue) && camelContextObj == null) {
                camelContextValue = "camelContext";
            }
            camelContextObj = get(camelContextValue);
        }
    }

    @SuppressWarnings("unchecked")
    protected CamelContext get(String name) {
        Bean<CamelContext> bean = (Bean<CamelContext>) beanManager.getBeans(name).iterator().next();
        CreationalContext<CamelContext> ctx = beanManager.createCreationalContext(bean);
        return (CamelContext) beanManager.getReference(bean, CamelContext.class, ctx);
    }
}

I wouldn’t mind working on a proper contribution here, but would need some guidance as I am not that familiar with the code base or processes around contributions.