com.headstrong.fusion.messaging.service.CBRProcessor.java Source code

Java tutorial

Introduction

Here is the source code for com.headstrong.fusion.messaging.service.CBRProcessor.java

Source

/*
 * The information in this document is subject to change without notice and 
 * does not represent a commitment by Headstrong Corporation. The software 
 * and/or databases described in this document are furnished under a license 
 * agreement and may be used or copied only in accordance with the terms of 
 * the agreement. 
 * 
 * Copyright  2008 Headstrong Corporation
 * All rights reserved.
 * 
 * $Id: CBRProcessor.java
 * $Revision: 
 * $Author: ssoni
 * $DateTime: Nov 27, 2008 
 */

package com.headstrong.fusion.messaging.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;

import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.commons.jexl.Expression;
import org.apache.commons.jexl.ExpressionFactory;
import org.apache.commons.jexl.JexlContext;
import org.apache.commons.jexl.JexlHelper;

import com.headstrong.fusion.commons.FusionConstants;
import com.headstrong.fusion.config.CBREndPointConfig;
import com.headstrong.fusion.config.When;

/**
 * Content Based Grouping of message is done by the processor.
 * 
 */
public class CBRProcessor implements Processor {

    private CBREndPointConfig config;
    private Map<When, Expression> expressions;

    private static final String HEADER = "header";
    private static final String BODY = "message";

    public CBRProcessor(CBREndPointConfig config) throws Exception {
        this.config = config;
        this.initializeExpressions();
    }

    /**
     * CBR Expression Samples.
     * <p>
     * HEADER ONLY (#header{type}.equals("type1"))
     * <p>
     * COMPLETE (#header{type}.equals("type1") &&
     * #body{parent.child}.equals("data"))
     * <p>
     * #header refers to the header data and #body refers to the field in the
     * message body. All the field references would be replaced with actual
     * method calls on the header and message bean.
     * 
     * @throws Exception
     */
    private void initializeExpressions() throws Exception {
        Map<When, Expression> expressions = new HashMap<When, Expression>();
        for (When when : this.getConfig().getWhen()) {
            String expression = when.getExpression();
            for (Entry<String, String> field : getTokens(expression, "#header").entrySet()) {
                expression = expression.replaceAll(Pattern.quote(field.getKey()),
                        HEADER + ".get(\"" + field.getValue() + "\")");
            }

            for (Entry<String, String> field : getTokens(expression, "#body").entrySet()) {
                expression = expression.replaceAll(Pattern.quote(field.getKey()),
                        BODY + ".getValue(\"" + field.getValue() + "\")");
            }
            // create JEXL- expression
            Expression jexlExpr = ExpressionFactory.createExpression(expression);
            expressions.put(when, jexlExpr);
        }
        this.setExpressions(expressions);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.camel.Processor#process(org.apache.camel.Exchange)
     */
    @SuppressWarnings("unchecked")
    public void process(Exchange exchange) throws Exception {

        Object inputMessage = exchange.getIn().getBody();
        Object header = exchange.getIn().getHeaders();

        // Size of the list of sub-lists being created after content based
        // sub-grouping.
        int size = config.getWhen().size() + (config.getOtherwise() == null ? 0 : 1);

        if (inputMessage instanceof List) {
            List<List<Object>> outputList = new ArrayList<List<Object>>(size);
            this.initializeList(outputList, size);
            for (Object message : (List<Object>) inputMessage) {
                boolean matchFound = false;
                for (When when : config.getWhen()) {
                    Expression expression = this.getExpressions().get(when);
                    if (expression != null && this.evaluateExpression(expression, header, message)) {
                        // since the list is already initialized null check
                        // is not required.
                        List<Object> subList = outputList.get(config.getWhen().indexOf(when));
                        subList.add(message);
                        matchFound = true;
                        break;
                    }
                }
                if (!matchFound && config.getOtherwise() != null) {
                    // put it in the last index element.
                    List<Object> subList = outputList.get(size - 1);
                    subList.add(message);
                }
            }
            this.clearEmptySubLists(outputList);
            exchange.getIn().setBody(outputList);
        } else {
            List<Object> outputList = new ArrayList<Object>(size);
            this.initializeListWithNull(outputList, size);
            boolean matchFound = false;
            for (When when : config.getWhen()) {
                Expression expression = this.getExpressions().get(when);
                if (expression != null) {
                    JexlContext jc = JexlHelper.createContext();
                    // Now evaluate the expression, getting the result
                    jc.getVars().put(HEADER, header);
                    jc.getVars().put(BODY, inputMessage);
                    if (this.evaluateExpression(expression, header, inputMessage)) {
                        outputList.set(config.getWhen().indexOf(when), inputMessage);
                        matchFound = true;
                        break;
                    }
                }
            }
            if (!matchFound && config.getOtherwise() != null) {
                outputList.set(size - 1, inputMessage);
            }
            exchange.getIn().setBody(outputList);
        }
    }

    @SuppressWarnings("unchecked")
    private boolean evaluateExpression(Expression expression, Object header, Object body) throws Exception {
        Boolean expressionResult = false;
        JexlContext jc = JexlHelper.createContext();
        // Now evaluate the expression, getting the result
        jc.getVars().put(HEADER, header);
        jc.getVars().put(BODY, body);
        // FIXME To avoid runtime exceptions.
        Object result = expression.evaluate(jc);
        if (result != null) {
            expressionResult = (Boolean) result;
        }
        return expressionResult;
    }

    /**
     * Initializes the list with empty sublists.
     * 
     * @param list
     * @param size
     */
    @SuppressWarnings("unchecked")
    private void initializeListWithNull(List list, int size) {
        for (int i = 0; i < size; i++) {
            list.add(FusionConstants.EMPTY_STRING);
        }
    }

    /**
     * Initializes the list with empty sublists.
     * 
     * @param list
     * @param size
     */
    @SuppressWarnings("unchecked")
    private void initializeList(List list, int size) {
        for (int i = 0; i < size; i++) {
            list.add(new ArrayList<Object>());
        }
    }

    /**
     * Sets the index values to null if the sublist at that index is empty.
     * Required for the content based router.
     * 
     * @param list
     */
    private void clearEmptySubLists(List<List<Object>> list) {
        for (int i = 0; i < list.size(); i++) {
            List<Object> subList = list.get(i);
            if (subList != null && subList.isEmpty()) {
                list.set(i, FusionConstants.EMPTY_LIST);
            }
        }
    }

    /**
     * @return the config
     */
    public CBREndPointConfig getConfig() {
        return config;
    }

    /**
     * @param config
     *            the config to set
     */
    public void setConfig(CBREndPointConfig config) {
        this.config = config;
    }

    /**
     * @return the expressions
     */
    public Map<When, Expression> getExpressions() {
        return expressions;
    }

    /**
     * @param expressions
     *            the expressions to set
     */
    public void setExpressions(Map<When, Expression> expressions) {
        this.expressions = expressions;
    }

    /**
     * 
     * @precondition
     * @postcondition
     * @param str
     * @param identifier
     * @return
     */
    private Map<String, String> getTokens(String str, String identifier) {
        int identifierIndex = 0;
        int fieldIndex = 0;
        Map<String, String> tokens = new HashMap<String, String>();
        while (true) {
            identifierIndex = str.indexOf(identifier, fieldIndex);
            if (identifierIndex != -1) {
                fieldIndex = identifierIndex + identifier.length() + 1;
                String token = str.substring(identifierIndex, str.indexOf("}", fieldIndex) + 1);
                String field = str.substring(fieldIndex, str.indexOf("}", fieldIndex));
                tokens.put(token, field);
            } else {
                break;
            }
        }
        return tokens;
    }

}