Loan Broker Example

This example shows how to use Camel to implement the EIP's loan broker example.

The example has two versions,one for JMS, one for webservice one.
The JMS version which leverages the message queue to connect the credit agency and bank loan quote processors together, it just uses the InOnly exchange pattern to handle the message asynchronously;
the webservice version which shows how to integrate the credit agency and bank web services together by using the InOut exchange pattern synchronously.

Implementation with message queue (JMS)

The queue version of loan broker is based on the camel-jms component, and it shows how to using the message queue to connect the different service models (such as the credit agency , and banks).

The example should run if you type

mvn exec:java -PQueue.LoanBroker

mvn exec:java -PQueue.Client

To stop the example hit ctrl + c

let's take a look how this service modules are put together.

Error formatting macro: snippet: java.lang.IndexOutOfBoundsException: Index: 20, Size: 20

The CreditAgency , Bank and Translator are all the implementation of Processor interface. We implement the business logical in the void process(Exchange exchange) method.

CreditAgency

Error formatting macro: snippet: java.lang.IndexOutOfBoundsException: Index: 20, Size: 20

Bank

Error formatting macro: snippet: java.lang.IndexOutOfBoundsException: Index: 20, Size: 20

Translator

Error formatting macro: snippet: java.lang.IndexOutOfBoundsException: Index: 20, Size: 20

You may found we set a custom aggregation strategy to find out the lowest loan rate from bank response message.

public class BankResponseAggregationStrategy implements AggregationStrategy {

    @Override
    public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
        // the first time we only have the new exchange
        if (oldExchange == null) {
            return newExchange;
        }

        Double oldQuote = oldExchange.getIn().getHeader(Constants.PROPERTY_RATE, Double.class);
        Double newQuote = newExchange.getIn().getHeader(Constants.PROPERTY_RATE, Double.class);

        // return the winner with the lowest rate
        if (oldQuote.doubleValue() <= newQuote.doubleValue()) {
            return oldExchange;
        } else {
            return newExchange;
        }
    }

}

We start the loan broker after we start up the ActiveMq broker and the connection factory of Camel-JMS component.

public static void main(String... args) throws Exception {
    // setup an embedded JMS broker
    JmsBroker broker = new JmsBroker();
    broker.start();

    // create a camel context
    CamelContext context = new DefaultCamelContext();

    // Set up the ActiveMQ JMS Components
    ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:51616");
    // Note we can explicitly name the component
    context.addComponent("jms", JmsComponent.jmsComponentAutoAcknowledge(connectionFactory));

    // add the route
    context.addRoutes(new LoanBrokerRoute());

    // start Camel
    context.start();
    System.out.println("Server is ready");

    // let it run for 5 minutes before shutting down
    Thread.sleep(5 * 60 * 1000);
    context.stop();
    Thread.sleep(1000);
    broker.stop();
}

Now we can send the request from client and pull the response message back

public final class Client {

    private Client() {
    }

    public static void main(String args[]) throws Exception {
        CamelContext context = new DefaultCamelContext();
        // Set up the ActiveMQ JMS Components
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:51616");
        // Note we can explicit name of the component
        context.addComponent("jms", JmsComponent.jmsComponentAutoAcknowledge(connectionFactory));
        context.start();

        ProducerTemplate template = context.createProducerTemplate();

        String out = template.requestBodyAndHeader("jms:queue:loan", null, Constants.PROPERTY_SSN, "Client-A", String.class);
        System.out.println(out);

        template.stop();
        context.stop();
    }

}

Implementation with web service

The web service version of loan broker is based on the camel-cxf component which can produce and consume the SOAP message on the wire. It uses the InOut Message exchange pattern, when the client send out the message to the router , it can get the response message back from the same endpoint.
When we send out the quote message to the three different banks, we could choice to call the bank service one by one or send out the message parallelly(one request thread per request).
You can compare the response time after you run the sample.

The example should run if you type

mvn exec:java -PWS.LoanBroker

mvn exec:java -PWS.Client

To stop the example hit ctrl + c

First, let's go through the SEI (Service Endpoint Interface) for LoanBroker, CreditAgency and Bank.

LoanBroker

// This SEI has no @WebService annotation, we use the simple frontend API to create client and server
public interface LoanBrokerWS {

    String getLoanQuote(String ssn, Double loanAmount, Integer loanDuration);

}

CreditAgency

@WebService
public interface CreditAgencyWS {

    int getCreditScore(String ssn);

    int getCreditHistoryLength(String ssn);

}

Bank

// Since we use @WebServices here, please make sure to use JaxWs frontend API create the client and server
@WebService
public interface BankWS {

    String getBankName();

    BankQuote getQuote(String ssn, double loanAmount, int loanDuration, int creditHistory, int creditScore);

}

Here are two routing rules in DSL , one is for routing the request to bank sequentially, the other is for calling the bank service parallely.

Error formatting macro: snippet: java.lang.IndexOutOfBoundsException: Index: 20, Size: 20

We use the CreditScoreProcessor to send two request to credit agency to get the credit history length and the credit score and prepare the request message for the bank.

Error formatting macro: snippet: java.lang.IndexOutOfBoundsException: Index: 20, Size: 20

Now we implement the Bank and CreditAgency SEI with the business logical codes.

Bank

public class Bank implements BankWS {
    private String bankName;
    private double primeRate;

    public Bank(String name) {
        bankName = name;
        primeRate = 3.5;
    }

    public String getBankName() {
        return bankName;
    }

    public BankQuote getQuote(String ssn, double loanAmount, int loanDuration, int creditHistory, int creditScore) {
        Double rate = primeRate + (double)(loanDuration / 12) / 10 + Math.random() * 10 / 10;
        // Wait for a while
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // do nothing here
        }
        BankQuote result = new BankQuote(bankName, ssn, rate);
        return result;
    }

}

CreditAgency

public class CreditAgency implements CreditAgencyWS {

    public int getCreditHistoryLength(String ssn) {
        int creditScore = (int)(Math.random() * 600 + 300);
        return creditScore;
    }

    public int getCreditScore(String ssn) {
        int creditHistoryLength = (int)(Math.random() * 19 + 1);
        return creditHistoryLength;
    }

}

The below codes show how the start the loan broker.

Error formatting macro: snippet: java.lang.IndexOutOfBoundsException: Index: 20, Size: 20

We can send the request by creating a client proxy with the LoanBroker SEI in the client code. BTW, you can compare the two different routing rule's performance by running the client.

public final class Client {
    
    private static String url = "http://localhost:9008/loanBroker";

    private Client() {
    }

    public static LoanBrokerWS getProxy(String address) {
        // Now we use the simple front API to create the client proxy
        ClientProxyFactoryBean proxyFactory = new ClientProxyFactoryBean();
        ClientFactoryBean clientBean = proxyFactory.getClientFactoryBean();
        clientBean.setAddress(address);
        clientBean.setServiceClass(LoanBrokerWS.class);
        clientBean.setBus(BusFactory.getDefaultBus());
        return (LoanBrokerWS) proxyFactory.create();
    }

    public static void main(String[] args) {
        LoanBrokerWS loanBroker = getProxy(url);

        StopWatch watch = new StopWatch();
        String result = loanBroker.getLoanQuote("SSN", 5000.00, 24);

        System.out.println("Took " + watch.stop() + " milliseconds to call the loan broker service");
        System.out.println(result);
    }

}
© 2004-2011 The Apache Software Foundation.
Apache Camel, Camel, Apache, the Apache feather logo, and the Apache Camel project logo are trademarks of The Apache Software Foundation. All other marks mentioned may be trademarks or registered trademarks of their respective owners.
Graphic Design By Hiram