Package org.jboss.soa.esb.actions

Source Code of org.jboss.soa.esb.actions.ContentBasedWiretap

/*
* JBoss, Home of Professional Open Source
* Copyright 2006, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.soa.esb.actions;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.jboss.soa.esb.ConfigurationException;
import org.jboss.soa.esb.Service;
import org.jboss.soa.esb.actions.cbr.SxcXPathRouter;
import org.jboss.soa.esb.actions.cbr.XPathRouter;
import org.jboss.soa.esb.actions.cbr.RegexRouter;
import org.jboss.soa.esb.helpers.ConfigTree;
import org.jboss.soa.esb.listeners.ListenerTagNames;
import org.jboss.soa.esb.client.ServiceInvoker;
import org.jboss.soa.esb.client.MessageMulticaster;
import org.jboss.soa.esb.listeners.message.MessageDeliverException;
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.message.mapping.ObjectMapper;
import org.jboss.soa.esb.message.mapping.ObjectMappingException;
import org.jboss.soa.esb.services.registry.Registry;
import org.jboss.soa.esb.services.registry.RegistryException;
import org.jboss.soa.esb.services.registry.RegistryFactory;
import org.jboss.soa.esb.services.routing.MessageRouterException;
import org.jboss.soa.esb.services.routing.cbr.ContentBasedRouterFactory;

/**
* ContentBasedWirtap implements the WireTap pattern.
* The WireTap is an Enterprise Integration Pattern (EIP) where a copy of the message is
* sent to a control channel.
* <br>
* The CBWT is identical in functionality to the ContentBasedRouter,
* however it does not terminate the pipeline which makes it suitable to be used as a WireTap.
* <p/>
*
* Configuration Example:
*<pre>{@code
*
*<action class="org.jboss.soa.esb.actions.ContentBasedRouter" name="MyAction">
*    <property name="ruleSet" value="OrderDiscountOnMultipleOrders.drl" />
*    <property name="ruleReload" value="false" />
*    <property name="ruleFireMethod" value="FIRE_ALL_RULES" />
*    <property name="ruleAuditType" value="THREADED_FILE" />
*    <property name="ruleAuditFile" value="/tmp/event" />
*    <property name="ruleAuditInterval" value="1000" />
*    <property name="ruleClockType" value="REALTIME" />
*    <property name="ruleEventProcessingType" value="STREAM" />
*    <property name="stateful" value="true" />
*    <property name="object-paths">
*        <object-path esb="body.TheOrderHeader" />
*        <object-path esb="body.TheCustomer" />
*        <object-path esb="body.TheOrderStatus" entry-point="OrderStatusEntry" />
*        <object-path esb="body.TheOrderInfo" entry-point="OrderInfoEntry" />
*    </property>
*    <property name="channels">
*        <!-- chan1 and chan2 are equivalent (but timeout only applies if async == false) -->
*        <send-to channel-name="chan1" service-category="cat1" service-name="svc1" />
*        <send-to channel-name="chan2" channel-class="org.jboss.soa.esb.services.rules.ServiceChannel" service-category="cat1" service-name="svc1" async="true" timeout="30000" set-payload-location="org.jboss.soa.esb.message.defaultEntry" />
*        <!-- a custom channel -->
*        <send-to channel-name="chan3" channel-class="com.example.MyChannel" />
*    </property>
*    <property name="destinations">
*        <route-to destination-name="blue"  service-category="BlueTeam"  service-name="GoBlue" />
*        <route-to destination-name="red"   service-category="RedTeam"   service-name="GoRed" />
*        <route-to destination-name="green" service-category="GreenTeam" service-name="GoGreen" />
*    </property>
*</action>
*}</pre>
*
* Property description:
* <ul>
* <li> <i>class</i>    action class, one of : org.jboss.soa.esb.actions.ContentBasedRouter, org.jboss.soa.esb.actions.ContentBasedWireTap,<br>
*               or org.jboss.soa.esb.actions.MessageFilter
* <li> <i>ruleSet</i>    Name of the filename containing the Drools ruleSet.
* <li> <i>ruleLanguage</i>  Optional reference to a file containing the definition of a Domain Specific Language to be used for evaluating
*               the rule set.
* <li> <i>ruleReload</i>  Optional property which can be to true to enable 'hot' redeployment of rule sets.
* <li> <i>ruleFireMethod</i> Optional property that defines, for StatefulKnowledgeSessions, if fireAllRules() or fireUntilHalt() should be called.  Possible values are FIRE_ALL_RULES (the default) or FIRE_UNTIL_HALT.
* <li> <i>ruleAuditType</i> Optional property that defines the type of KnowledgeRuntimeLogger used (CONSOLE, FILE, THREADED_FILE).  If not defined and neither is ruleAuditFile, no auditing is done.  If not defined but ruleAuditFile is, the assumption is THREADED_FILE.
* <li> <i>ruleAuditFile</i> Optional property that defines the file path for a ruleAuditType of FILE or THREADED_FILE ("event" is the default, and ".log" is always appended).
* <li> <i>ruleAuditInterval</i> Optional property that defines the interval (in milliseconds) for a ruleAuditType of THREADED_FILE (1000 is the default).
* <li> <i>ruleclockType</i> Optional property that defines the type of clock used (REALTIME, PSEUDO).  Default is up to drools.
* <li> <i>ruleEventProcessingType</i> Optional property that defines the type of event processing used (STREAM, CLOUD).  Default is up to drools.
* <li> <i>stateful</i>    Optional property which tells the RuleService to use a stateful session where facts will be
*               remembered between invokations.
* <li> <i>object-paths</i> Optional property to pass Message objects into Rule Services WorkingMemory.  If an entry-point is specified, that will be placed in the StatefulSession's WorkingMemoryEntryPoint with the same name.
* <li> <i>channels</i> A set of send-­to properties each containing the logical name
*               of the destination along with the Service category and name
*              as referenced in the registry (if the default channel-class is used),
*              OR your own custom-class, which MUST implement org.drools.runtime.Channel,
*              , but MAY provide a setConfig(ConfigTree):void method.
*              <br/> The logical name is the name which should be used in the rule set.
<li> <i>destinations</i> A set of route-­to properties each containing the logical name
*               of the destination along with the Service category and name
*              as referenced in the registry.<br/> The logical name is the name
*              which should be used in the rule set.
* </ul>
* </br>
*
*
* @author <a href="mailto:schifest@heuristica.com.ar">schifest@heuristica.com.ar</a>
* @author kstam@jboss.com
* @author kevin.conner@jboss.com
* @author <a href="mailto:dbevenius@redhat.com">Daniel Bevenius</a>
*/
public class ContentBasedWiretap extends AbstractActionPipelineProcessor {

    public static final String ROUTE_TO_TAG = "route-to";

    public static final String OBJECT_PATH_TAG = "object-path";

    public static final String OBJECT_PATH = "esb";
   
    public static final String ENTRY_POINT = "entry-point";

    public static final String DEFAULT_CBR_CLASS = "org.jboss.internal.soa.esb.services.routing.cbr.JBossRulesRouter";

    ServiceInvoker dlQueueInvoker;

    public ContentBasedWiretap(ConfigTree config)
            throws ConfigurationException, RegistryException,
            MessageRouterException {
        _config = config;
        checkMyParms();
        _registry = RegistryFactory.getRegistry();
        _cbr = ContentBasedRouterFactory.getRouter(_cbrClass);
        _cbr.setConfigTree(config);
        _mapper = new ObjectMapper(config);
        try {
            dlQueueInvoker = new ServiceInvoker(ServiceInvoker.INTERNAL_SERVICE_CATEGORY, ServiceInvoker.DEAD_LETTER_SERVICE_NAME);
        } catch (MessageDeliverException e) {
            throw new MessageRouterException(e);
        }
       
        messageMulticaster.setAggregatorOnProperties(Aggregator.aggregatorOnProperties(config));
    }

    public void initialise() { }

    /**
     * Router the message to one or more destinations, using the
     * ContentBasedRouter to figure out to which destinations it is going to
     * be routed too.
     *
     * @param message
     * @return Message
     * @throws ActionProcessingException
     */
    public Message process(Message message) throws ActionProcessingException
    {
        try {
            List<Service> outgoingDestinations = executeRules(message);
            if (outgoingDestinations.size()==0) {
                String error = "No rule destination(s) "+ _destinations.keySet() + " were matched, "
                           + ". Please fix your configuration and/or routing rules.";
                _logger.error(error);
                try {
                    _logger.debug("Sending message to the DeadLetterService");
                    dlQueueInvoker.deliverAsync(message);
                    throw new ActionProcessingException(error);
                } catch (MessageDeliverException e) {
                    throw new MessageRouterException("Failed to deliver message to Dead Letter Channel.", e);
                }
            } else {
                routeMessage(message, outgoingDestinations);
            }
        } catch (MessageRouterException e) {
            throw new ActionProcessingException(e);
        }
        return message;
    }
   
    protected List<Service> executeRules(Message message)
        throws MessageRouterException
    {
        List<Service> outgoingDestinations = new ArrayList<Service>();
        try {
            List<Object> objectList = _mapper.createObjectList(message,
                    _messagePathList);
            List<String> destinations = _cbr.route(_ruleSet, _ruleLanguage,
                    _ruleReload, message, objectList);
            for (String destination : destinations) {
                if (_destinations.containsKey(destination)) {
                    outgoingDestinations.add(_destinations.get(destination));
                } else {
                    throw new MessageRouterException("Destination " + destination + " does not exist your configuration");
                }
            }
        } catch (ObjectMappingException ome) {
            throw new MessageRouterException(ome);
        }
        return outgoingDestinations;
    }

    protected final void routeMessage(Message message, List<Service> outgoingDestinations)
        throws MessageRouterException
   
        try {
            messageMulticaster.sendToSubset(message, outgoingDestinations);
        } catch (RegistryException e) {
            throw new MessageRouterException(e);
        } catch (MessageDeliverException e) {
            throw new MessageRouterException(e);
        }
    }

    /**
     * Reading the piece of configTree specific to the CBR, and setting the
     * configuration.
     *
     * @throws ConfigurationException
     */
    protected void checkMyParms() throws ConfigurationException {
        _ruleSet = _config.getAttribute(ListenerTagNames.RULE_SET_TAG);
        _ruleLanguage = _config.getAttribute(ListenerTagNames.RULE_LANGUAGE_TAG);
        String ruleReload = _config.getAttribute(ListenerTagNames.RULE_RELOAD_TAG);
        if (ruleReload != null && "true".equals(ruleReload)) {
            _ruleReload = true;
        }

        String cbrAlias = _config.getAttribute(ListenerTagNames.CBR_ALIAS);

        _cbrClass = _config.getAttribute(ListenerTagNames.CBR_CLASS);
        if(cbrAlias != null && _cbrClass != null) {
            throw new ConfigurationException("Invalid " + getClass().getSimpleName() + " configuration.  Cannot configure both '" + ListenerTagNames.CBR_ALIAS + "' and '" + ListenerTagNames.CBR_CLASS + "' properties on the same action configuration.");
        }

        if(_cbrClass == null) {
            if(cbrAlias == null) {
                _cbrClass = DEFAULT_CBR_CLASS;
            } else if(cbrAlias.equalsIgnoreCase("JBRules") || cbrAlias.equalsIgnoreCase("Drools")) {
                _cbrClass = DEFAULT_CBR_CLASS;
            } else if(cbrAlias.equalsIgnoreCase("XPath")) {
                _cbrClass = XPathRouter.class.getName();
            } else if(cbrAlias.equalsIgnoreCase("SXC")) {
                _cbrClass = SxcXPathRouter.class.getName();
            } else if(cbrAlias.equalsIgnoreCase("Regex") || cbrAlias.equalsIgnoreCase("Regexp")) {
                _cbrClass = RegexRouter.class.getName();
            } else {
                throw new ConfigurationException("Invalid " + getClass().getSimpleName() + " configuration.  Unsupported '" + ListenerTagNames.CBR_ALIAS + "' property value '" + cbrAlias + "'.");
            }
        }

        _destinations = new HashMap<String, Service>();
        ConfigTree[] destList = _config.getChildren(ROUTE_TO_TAG);
        if (destList != null) {
            for (ConfigTree curr : destList) {
                try {
                    String key = buildDestinationKey(curr);
                    String category = curr.getAttribute(
                            ListenerTagNames.SERVICE_CATEGORY_NAME_TAG, "");
                    String name = curr
                            .getRequiredAttribute(ListenerTagNames.SERVICE_NAME_TAG);
                    Service service = new Service(category, name);
                    _destinations.put(key, service);
                    messageMulticaster.addRecipient(service);
                }
                catch (Exception e) {
                    throw new ConfigurationException(
                            "Problems with destination list", e);
                }
            }
        }
        _messagePathList = new ArrayList<String>();
        entryPointMap = new HashMap<String, List<String>>();
        ConfigTree[] objectList = _config.getChildren(OBJECT_PATH_TAG);
        if (objectList != null) {
            for (ConfigTree curr : objectList) {
                try {
                    final String objectPath = curr.getRequiredAttribute(OBJECT_PATH);
                    final String entryPoint = curr.getAttribute(ENTRY_POINT);
                    if (entryPoint != null)
                    {
                        List<String> list = entryPointMap.get(entryPoint);
                        if (list == null)
                        {
                            list = new ArrayList<String>();
                            // Add the list to the entrypoint map indexed by the entry-point name.
                            entryPointMap.put(entryPoint, list);
                        }
                        // Add the object path to the entry-point list.
                        list.add(objectPath);
                    }
                    else
                    {
                        _messagePathList.add(objectPath);
                    }
                }
                catch (Exception e) {
                    throw new ConfigurationException( "Problems with object path list", e);
                }
            }
        }
       

    }

    public static String buildDestinationKey(ConfigTree destinationConfig) throws ConfigurationException {
        String key = destinationConfig.getAttribute(ListenerTagNames.DESTINATION_NAME_TAG);

        if(key != null) {
            return key;
        }

        // Otherwise, build a key from the service category and name...
        String category = destinationConfig.getAttribute(ListenerTagNames.SERVICE_CATEGORY_NAME_TAG, "");
        String name = destinationConfig.getRequiredAttribute(ListenerTagNames.SERVICE_NAME_TAG);

        return category + "-" + name;
    }

    protected ConfigTree _config;

    protected Map<String, Service> _destinations;

    protected MessageMulticaster messageMulticaster = new MessageMulticaster();

    protected String _cbrClass;

    protected String _ruleSet;

    protected String _ruleLanguage;

    protected boolean _ruleReload;

    protected List<String> _messagePathList;
   
    protected Map<String, List<String>> entryPointMap;

    protected ObjectMapper _mapper;

    protected Registry _registry;

    protected org.jboss.soa.esb.services.routing.cbr.ContentBasedRouter _cbr;

    protected static final Logger _logger = Logger.getLogger(ContentBasedWiretap.class);

}
TOP

Related Classes of org.jboss.soa.esb.actions.ContentBasedWiretap

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.