Tuesday, March 31, 2015

Binding Guice bindings to Camel Registry

In the previous post I showed how I was using Commons Configuration with Camel property placeholders using Camel properties functions.

In this post I address the second problem I needed to solve. Binding objects that are bound to a guice injector to the camel registry. Again I should point out that Camel has a guice component that will take care of most of this. But I wanted to experiment with a simple camel context. My camel context is very simple it extends DefaultCamelContext and currently only provides one function, that function allows the injection of the commons configuration and a custom registry.
package com.margic.pihex.camel.context;

import com.google.inject.Inject;
import org.apache.camel.component.properties.PropertiesComponent;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.spi.Registry;
import org.apache.commons.configuration.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by paulcrofts on 3/27/15.
 */
public class CustomCamelContext extends DefaultCamelContext {

    private static final Logger log = LoggerFactory.getLogger(CustomCamelContext.class);

    @Inject
    public CustomCamelContext(Registry registry, Configuration config) {
        super(registry);
        log.info("Creating Guice Camel Context");
        PropertiesComponent pc = getComponent("properties", PropertiesComponent.class);
        pc.addFunction(new ConfigurationPropertiesFunction(config));
    }
}

This allows me to inject my registry implementation into the constructor of the camel context. The main binding happens in my JNDI registry implementation. The registry takes the guice injector as an argument and then scans the bindings on the injector for annotations. My code does this manually a better option would be to use matchers but the point is still valid.
    @Inject
    public GuiceRegistry(Injector injector) {
        super();
        this.injector = injector;
        bindGuiceObjects();
    }

    /**
     * method to scan injector bindings to register objects
     * annotated with BindCamelRegistry or names
     */
    private void bindGuiceObjects() {
        if (injector != null) {
            log.debug("Binding guice objects to registry");
            Map< key>, Binding> bindings = injector.getBindings();
            for (Key key : bindings.keySet()) {
                if (key.getAnnotationType() == Named.class) {
                    log.debug("Found binding annotated with named. Should be bound to camel registry.");
                    Object object = injector.getInstance(key);
                    Named named = (Named) key.getAnnotation();
                    String name = named.value();
                    bind(name, object);
                }else {
                    javax.inject.Named annotation = (javax.inject.Named)key.getTypeLiteral().getRawType().getAnnotation(javax.inject.Named.class);
                    if(annotation != null) {
                        log.debug("Found object bound with annotation BindCamelRegistry");
                        String name = annotation.value();
                        if (name != null) {
                            Object object = injector.getInstance(key);
                            bind(name, object);
                        }
                    }
                }
            }
        }
    }


This allows me to bind beans in Guice and have them automatically bound to the camel context. I can do the same with other objects using type matchers. For example RouteBuilders. However for now I am happy to manually configure routes during this stage of development.

The following test validates the binding and shows how easy it is to bind objects.

    @Named("myBean")
    static class TestClass{
        // this is just an empty class bound to name myBean for test
    }

    @Test
    public void testBindCamelRegistryAnnotation(){
        // need injector
        Injector injector = Guice.createInjector(new AbstractModule() {
            @Override
            protected void configure() {
                bind(TestClass.class);
            }
        });

        GuiceRegistry registry = new GuiceRegistry(injector);
        Object object = registry.lookupByName("myBean");
        assertNotNull(object);
        TestClass testClass = registry.lookup("myBean", TestClass.class);
        assertNotNull(testClass);
    }

    @Test
    public void testBindCamelRegistryNamedAnnotation(){
        Injector injector = Guice.createInjector(new AbstractModule() {
            @Override
            protected void configure() {
                bind(String.class).annotatedWith(Names.named("testName")).toInstance("My String Value");
            }
        });

        GuiceRegistry registry = new GuiceRegistry(injector);
        String testString = (String)registry.lookup("testName");
        assertEquals("My String Value", testString);

        testString = registry.lookup("testName", String.class);
        assertEquals("My String Value", testString);
    }


No comments:

Post a Comment