Package org.jboss.internal.soa.esb.services.routing.cbr

Source Code of org.jboss.internal.soa.esb.services.routing.cbr.DslHelper

/*
* 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.internal.soa.esb.services.routing.cbr;

import java.io.ByteArrayInputStream;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.log4j.Logger;
import org.jboss.internal.soa.esb.assertion.AssertArgument;
import org.jboss.internal.soa.esb.services.rules.util.RulesContext;
import org.jboss.soa.esb.helpers.ConfigTree;
import org.jboss.soa.esb.listeners.message.MessageDeliverException;
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.message.MessagePayloadProxy;
import org.jboss.soa.esb.message.body.content.BytesBody;
import org.jboss.soa.esb.util.XPathNamespaceContext;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

/**
* Domain Specific Language helper. Right now this supports the use of XPath, but this class can
* be beefed up upo to use other technologies as well.
* <p/>
*
* @author kstam@redhat.com
* @author <a href="mailto:dbevenius@redhat.com">Daniel Bevenius</a>
*
*/
public class DslHelper
{
  private static Logger log = Logger.getLogger(DslHelper.class);
 
  /**
   * The name of the boolean map context.
   */
  private static final String BOOLEAN_MAP = "DslHelper.BooleanMap" ;
 
  /**
   * The name of the number map.
   */
  private static final String NUMBER_MAP = "DslHelper.NumberMap" ;
 
  /**
   * The name of the string map.
   */
  private static final String STRING_MAP = "DslHelper.StringMap" ;
 
  /**
   * The name of the node map.
   */
  private static final String NODE_MAP = "DslHelper.NodeMap" ;
 
  /**
   * The name of the node list map.
   */
  private static final String NODE_LIST_MAP = "DslHelper.NodeListMap" ;
 
  /** XPath instance */
  private static XPathFactory xpf = XPathFactory.newInstance();
    private static MessagePayloadProxy payloadProxy;

    static {
        payloadProxy = new MessagePayloadProxy(new ConfigTree("config"), new String[] {BytesBody.BYTES_LOCATION}, new String[] {BytesBody.BYTES_LOCATION});
    }
   
    /**
   * Uses XPath to evalutate if the XPath expression is true or false.
   * This is the equivalent of calling selectAsBoolean( message, xpathExp, null).
   *
   * @param message -
   *         the ESB Message which body content will be used
   * @param xpathExp -
   *         XPath expression
   * @return Boolean
   *         true if the XPath expression evalutes to true
   * @throws XPathExpressionException
   *         represents an error in an XPath expression
   */
    public static Boolean selectAsBoolean(final Message message, final String xpathExp ) throws XPathExpressionException
    {
      return selectAsBoolean( message, xpathExp, null );
    }
   
    /**
   * Uses XPath to evalutate if the XPath expression is true or false.
   *
   * @param message -
   *         the ESB Message which body content will be used
   * @param xpathExp -
   *         XPath expression
   * @return Boolean
   *         true if the XPath expression evalutes to true
   * @param namespaces -
   *         Map of namespaces to be used in the xpath expression. Key=prefix,value = uri
   * @throws XPathExpressionException
   *         represents an error in an XPath expression
   */
    @SuppressWarnings("unchecked")
  public static Boolean selectAsBoolean(final Message message, final String xpathExp, final Map<String,String> namespaces ) throws XPathExpressionException
  {
    Map<String, Boolean> booleanMap = (Map<String, Boolean>)RulesContext.getContext(BOOLEAN_MAP) ;
    if (booleanMap != null)
    {
      final Boolean result = booleanMap.get(xpathExp) ;
      if (result != null)
      {
        return result ;
      }
    }
    else
    {
      booleanMap = new HashMap<String, Boolean>() ;
      RulesContext.setContext(BOOLEAN_MAP, booleanMap) ;
    }
   
    XPath xpath = getXPath( namespaces );
    Boolean value = (Boolean) xpath.evaluate( xpathExp, getInputSource(message), XPathConstants.BOOLEAN);
    booleanMap.put(xpathExp, value) ;
    return value;
  }

    /**
   * Uses XPath to select the Number matched by the XPath expression.
   * <p/>
   * This is the equivalent of calling selectAsNumber( message, xpathExp, null).
   *
   * @param message -
   *         the ESB Message which body content will be used
   * @param xpathExp -
   *         XPath expression
     * @return Number -
     *         the Number if XPath found a match, or null if no match was found.
     * @throws XPathExpressionException
   *         represents an error in an XPath expression
     */
    public static Number selectAsNumber(final Message message, final String xpathExp ) throws XPathExpressionException
    {
      return selectAsNumber( message, xpathExp, null );
    }
   
    /**
   * Uses XPath to select the Number matched by the XPath expression.
   *
   * @param message -
   *         the ESB Message which body content will be used
   * @param xpathExp -
   *         XPath expression
   * @param namespaces -
   *         Map of namespaces to be used in the xpath expression. Key=prefix,value = uri
     * @return Number -
     *         the Number if XPath found a match, or null if no match was found.
     * @throws XPathExpressionException
   *         represents an error in an XPath expression
     */
    @SuppressWarnings("unchecked")
  public static Number selectAsNumber(final Message message, final String xpathExp, final Map<String,String> namespaces ) throws XPathExpressionException
  {
    Map<String, Number> numberMap = (Map<String, Number>)RulesContext.getContext(NUMBER_MAP) ;
    if (numberMap != null)
    {
      final Number result = numberMap.get(xpathExp) ;
      if (result != null)
      {
        return result ;
      }
    }
    else
    {
      numberMap = new HashMap<String, Number>() ;
      RulesContext.setContext(NUMBER_MAP, numberMap) ;
    }
   
    final XPath xpath = getXPath( namespaces );
    final Number number = (Number) xpath.evaluate( xpathExp, getInputSource(message), XPathConstants.NUMBER);
    numberMap.put(xpathExp, number) ;
    return number;
  }
   
    /**
   * Uses XPath to select the String matched by the XPath expression.
   * <p/>
   * This is the equivalen of calling selectAsString( message, xpathExp, null).
   *
   * @param message -
   *         the ESB Message which body content will be used
   * @param xpathExp -
   *         XPath expression
     * @return String -
     *         the String if XPath found a match, or null if no match was found.
     * @throws XPathExpressionException
   *         represents an error in an XPath expression
     */
    public static String selectAsString(final Message message, final String xpathExp ) throws XPathExpressionException
    {
      return selectAsString( message, xpathExp, null );
    }
   
    /**
   * Uses XPath to select the String matched by the XPath expression.
   *
   * @param message -
   *         the ESB Message which body content will be used
   * @param xpathExp -
   *         XPath expression
   * @param namespaces -
   *         Map of namespaces to be used in the xpath expression. Key=prefix,value = uri
     * @return String -
     *         the String if XPath found a match, or null if no match was found.
     * @throws XPathExpressionException
   *         represents an error in an XPath expression
     */
    @SuppressWarnings("unchecked")
  public static String selectAsString(final Message message, final String xpathExp, final Map<String,String> namespaces ) throws XPathExpressionException
    {
    Map<String, String> stringMap = (Map<String, String>)RulesContext.getContext(STRING_MAP) ;
    if (stringMap != null)
    {
      final String result = stringMap.get(xpathExp) ;
      if (result != null)
      {
        return result ;
      }
    }
    else
    {
      stringMap = new HashMap<String, String>() ;
      RulesContext.setContext(STRING_MAP, stringMap) ;
    }
    final XPath xpath = getXPath( namespaces );
    final String string = (String) xpath.evaluate( xpathExp, getInputSource(message), XPathConstants.STRING);
    stringMap.put(xpathExp, string) ;
    return string;
  }
   
   
    /**
   * Uses XPath to select the Node matched by the XPath expression.
   * <p/>
   * This is the equivalent of calling selectAsNode( message, xpathExp null).
   *
   * @param message -
   *         the ESB Message which body content will be used
   * @param xpathExp -
   *         XPath expression
     * @return Node -
     *         the Node if XPath found a match, or null if no match was found.
     * @throws XPathExpressionException
   *         represents an error in an XPath expression
     */
    public static Node selectAsNode(final Message message, final String xpathExp ) throws XPathExpressionException
    {
      return selectAsNode( message, xpathExp, null );
    }
   
    /**
   * Uses XPath to select the Node matched by the XPath expression.
   * <p/>
   *
   * @param message -
   *         the ESB Message which body content will be used
   * @param xpathExp -
   *         XPath expression
   * @param namespaces -
   *         Map of namespaces to be used in the xpath expression. Key=prefix,value = uri
     * @return Node -
     *         the Node if XPath found a match, or null if no match was found.
     * @throws XPathExpressionException
   *         represents an error in an XPath expression
     */
    @SuppressWarnings("unchecked")
  public static Node selectAsNode(final Message message, final String xpathExp, final Map<String,String> namespaces ) throws XPathExpressionException
  {
    Map<String, Node> nodeMap = (Map<String, Node>)RulesContext.getContext(NODE_MAP) ;
    if (nodeMap != null)
    {
      final Node result = nodeMap.get(xpathExp) ;
      if (result != null)
      {
        return result ;
      }
    }
    else
    {
      nodeMap = new HashMap<String, Node>() ;
      RulesContext.setContext(NODE_MAP, nodeMap) ;
    }
    final XPath xpath = getXPath( namespaces );
    final Node node = (Node) xpath.evaluate( xpathExp, getInputSource(message), XPathConstants.NODE);
    nodeMap.put(xpathExp, node) ;
    return node;
  }
   
    /**
   * Uses XPath to select the NodeList matched by the XPath expression.
   * <p/>
   * This is the equivalent of calling selectAsNodeList( message, xpathExp null).
   *
   * @param message -
   *         the ESB Message which body content will be used
   * @param xpathExp -
   *         XPath expression
     * @return NodeList -
     *         the NodeList if XPath found a match, or null if no match was found.
     * @throws XPathExpressionException
   *         represents an error in an XPath expression
     */
    public static NodeList selectAsNodeList( final Message message, final String xpathExp ) throws XPathExpressionException
    {
      return selectAsNodeList( message, xpathExp, null );
    }
   
    /**
   * Uses XPath to select the NodeList matched by the XPath expression.
   * <p/>
   *
   * @param message -
   *         the ESB Message which body content will be used
   * @param xpathExp -
   *         XPath expression
   * @param namespaces -
   *         Map of namespaces to be used in the xpath expression. Key=prefix,value = uri
     * @return NodeList -
     *         the NodeList if XPath found a match, or null if no match was found.
     * @throws XPathExpressionException
   *         represents an error in an XPath expression
     */
    @SuppressWarnings("unchecked")
  public static NodeList selectAsNodeList( final Message message, final String xpathExp, Map<String,String> namespaces ) throws XPathExpressionException
  {
    Map<String, NodeList> nodeListMap = (Map<String, NodeList>)RulesContext.getContext(NODE_LIST_MAP) ;
    if (nodeListMap != null)
    {
      final NodeList result = nodeListMap.get(xpathExp) ;
      if (result != null)
      {
        return result ;
      }
    }
    else
    {
      nodeListMap = new HashMap<String, NodeList>() ;
      RulesContext.setContext(NODE_LIST_MAP, nodeListMap) ;
    }
    final XPath xpath = getXPath( namespaces );
    final NodeList nodeList = (NodeList) xpath.evaluate(xpathExp, getInputSource(message), XPathConstants.NODESET);
    log.info("XPath [" + xpathExp + "], nr of matches : " + nodeList.getLength());
    nodeListMap.put(xpathExp, nodeList) ;
    return nodeList;
  }
   
    /**
   * Uses XPath to look for the occurence of a certain node, specified in the XPath expression.
   * This can be used to find out if the Message object contains the node specified by the XPath
   * expression.
   * <p/>
   * This is the equivalent of calling xmlContentMatches( message, xpathExp, null).
   *
   * @param message -
   *         the ESB Message which body content will be used.
   * @param xpathExp -
   *         XPath expression to find a node.
   * @return true
   *         if the node is found and false in all other cases.
   * @throws XPathExpressionException
   *         represents an error in an XPath expression
   */
  public static boolean xmlContentMatches(final Message message, final String xpathExp) throws XPathExpressionException
  {
    return xmlContentMatches( message, xpathExp, null );
  }
 
    /**
   * Uses XPath to look for the occurence of a certain node, specified in the XPath expression.
   * This can be used to find out if the Message object contains the node specified by the XPath
   * expression.
   *
   * @param message -
   *         the ESB Message which body content will be used.
   * @param xpathExp -
   *         XPath expression to find a node.
   * @param namespaces -
   *         Map of namespaces to be used in the xpath expression. Key=prefix,value = uri
   * @return true
   *         if the node is found and false in all other cases.
   * @throws XPathExpressionException
   *         represents an error in an XPath expression
   */
  public static boolean xmlContentMatches(final Message message, final String xpathExp, final Map<String,String> namespaces ) throws XPathExpressionException
  {
        return selectAsNode( message, xpathExp, namespaces ) != null ;
  }
 
  /**
   * Uses XPath to look for any occurence of a certain tag, specific in the xpath expression.
   * This can be used to find out if the Message object contains the node specified by the XPath
   * Note, that this method cannot be used with a boolean expression, use {@link #selectAsBoolean(Message, String)}
   * for that.
   * <p/>
   * This is the equivalent of calling xmlContentExists( message, xpathExp, null).
   *
   * @param message -
   *         the ESB Message which body content will be used.
   * @param xpathExp -
   *         XPath expression to find a node.
   * @return true
   *         if one or more nodes are found and false in all other cases.
   * @throws XPathExpressionException
   *         represents an error in an XPath expression
   */
  public static boolean xmlContentExists(final Message message, final String xpathExp) throws XPathExpressionException
  {
    return xmlContentExists( message, xpathExp, null );
  }
 
    /**
   * Uses XPath to look for any occurence of a certain tag, specific in the xpath expression.
   * This can be used to find out if the Message object contains the node specified by the XPath
   * Note, that this method cannot be used with a boolean expression, use {@link #selectAsBoolean(Message, String)}
   * for that.
   *
   * @param message -
   *         the ESB Message which body content will be used.
   * @param xpathExp -
   *         XPath expression to find a node.
   * @param namespaces -
   *         Map of namespaces to be used in the xpath expression. Key=prefix,value = uri
   * @return true
   *         if one or more nodes are found and false in all other cases.
   * @throws XPathExpressionException
   *         represents an error in an XPath expression
   */
  public static boolean xmlContentExists(final Message message, final String xpathExp, final Map<String,String> namespaces ) throws XPathExpressionException
  {
    final NodeList nodeList = selectAsNodeList( message, xpathExp, namespaces );
    return nodeList == null ? false : nodeList.getLength() > 0 ;
  }
 
  /**
   * Uses XPath to look for the occurence of a certain tag, specific in the xpath expression.
   * </p>
   * Note that {@link #selectAsBoolean(Message, String)} can be used instead of this method
   * and the XPath equality operator can be used in the XPath expression:
   * <br>
   * <pre>{@code
   * String xpathExp = "/Order/OrderLines/OrderLine/Product/@productId = 364";
   * }</pre>
   * <br>
   * <p/>
   * This is the equivalent of calling xmlContentEquals( message, xpathExp, null).
   *
   * @param message -
   *       the ESB Message which body content will be used.
   * @param xpathExp -
   *       XPath expression to find a node.
   * @return true -
   *       if the node is found and false in all other cases.
   * @throws XPathExpressionException
   *       represents an error in an XPath expression
   */
  public static boolean xmlContentEquals(final Message message, final String xpathExp, final String value ) throws XPathExpressionException
  {
    return xmlContentEquals( message, xpathExp, value, null );
  }
 
  /**
   * Uses XPath to look for the occurence of a certain tag, specific in the xpath expression.
   * </p>
   * Note that {@link #selectAsBoolean(Message, String)} can be used instead of this method
   * and the XPath equality operator can be used in the XPath expression:
   * <br>
   * <pre>{@code
   * String xpathExp = "/Order/OrderLines/OrderLine/Product/@productId = 364";
   * }</pre>
   * <br>
   *
   * @param message -
   *       the ESB Message which body content will be used.
   * @param xpathExp -
   *       XPath expression to find a node.
   * @param namespaces -
   *       Map of namespaces to be used in the xpath expression. Key=prefix,value = uri
   * @return true -
   *       if the node is found and false in all other cases.
   * @throws XPathExpressionException
   *       represents an error in an XPath expression
   */
  public static boolean xmlContentEquals(final Message message, final String xpathExp, final String value, final Map<String,String> namespaces ) throws XPathExpressionException
  {
    final String xpathResult = selectAsString( message, xpathExp, namespaces );
    return xpathResult == null ? false : xpathResult.equals( value );
  }
 
    /**
   * Uses XPath to look for the occurence of a certain tag, specific in the xpath expression.
   * <p/>
   * This is the equivalent of calling xmlContentGreaterThan( message, xpathExp, value, null).
   *
   * @param message -
   *         the ESB Message which body content will be used.
   * @param xpathExp -
   *         XPath expression to find a node.
   * @return true
   *         if the node is found and false in all other cases.
   * @throws XPathExpressionException
   *         represents an error in an XPath expression
   */
  public static boolean xmlContentGreaterThan( final Message message, final String xpathExp, final String value) throws XPathExpressionException
  {
    return xmlContentGreaterThan( message, xpathExp, value, null );
  }
 
  /**
   * Uses XPath to look for the occurence of a certain tag, specific in the xpath expression.
   *
   * @param message -
   *         the ESB Message which body content will be used.
   * @param xpathExp -
   *         XPath expression to find a node.
   * @param namespaces -
   *         Map of namespaces to be used in the xpath expression. Key=prefix,value = uri
   * @return true
   *         if the node is found and false in all other cases.
   * @throws XPathExpressionException
   *         represents an error in an XPath expression
   */
  public static boolean xmlContentGreaterThan( final Message message, final String xpathExp, final String value, final Map<String,String> namespaces) throws XPathExpressionException
  {
    final String xpathResult = (String) selectAsString( message, xpathExp, namespaces );

    if ( xpathResult != null && !"".equals( xpathResult ) )
      return parseDouble( xpathResult ) > parseDouble( value );
    else
        return false;
  }
 
  /**
   * Uses XPath to look for the occurence of a certain tag, specific in the xpath expression.
   * <p/>
   * This is the equivalent of calling xmlContentLessThan( message, xpathExp, value, null).
   *
   * @param message -
   *         the ESB Message which body content will be used.
   * @param xpathExp -
   *         XPath expression to find a node.
   * @return true
   *         if the node is found and false in all other cases.
   * @throws XPathExpressionException
   *         represents an error in an XPath expression
   */
    public static boolean xmlContentLessThan( final Message message, final String xpathExp, final String value) throws XPathExpressionException
    {
        return xmlContentLessThan( message, xpathExp, value, null );
    }
 
    /**
     * Uses XPath to look for the occurence of a certain tag, specific in the xpath expression.
     *
     * @param message -
     *              the ESB Message which body content will be used.
     * @param xpathExp -
     *              XPath expression to find a node.
     * @return true
     *              if the node is found and false in all other cases.
     * @throws XPathExpressionException
     *              represents an error in an XPath expression
     */
    public static boolean xmlContentLessThan( final Message message, final String xpathExp, final String value, final Map<String,String> namespaces) throws XPathExpressionException
    {
        final String xpathResult = (String) selectAsString( message, xpathExp, namespaces );

        if ( xpathResult != null && !"".equals( xpathResult ) )
            return parseDouble( xpathResult ) < parseDouble( value );
        else
            return false;
    }
   
    /**
     * Will take the passed in string of namespaces in the form "prefix=uri,prefix=uri".
     *
     * @param namespaces string of namespaces in the form "prefix=uri,prefix=uri"
     * @return Map<String,String> where the key will be the namespace prefix and the value the uri
     */
    public static Map<String, String> parseNamespaces( final String namespaces )
  {
    AssertArgument.isNotNullAndNotEmpty( namespaces, "namespaces" );
   
    final String[] namespacesElements = namespaces.split( "," );
    final Map<String,String> namespacesMap = new HashMap<String,String>();
    for ( String ns : namespacesElements )
    {
      final String[] pairs = ns.split( "=" );
      namespacesMap.put( pairs[0].trim(), pairs[1].trim() );
    }
    return namespacesMap;
  }
 
  private static double parseDouble( final String string ) throws XPathExpressionException
  {
    try
    {
      return Double.parseDouble( string );
    }
    catch (NumberFormatException e)
    {
      throw new XPathExpressionException("Could not parse value [" + string + "] to double" );
    }
  }
 
  private static void setNamespaces( final XPath xpath, final Map<String,String> namespaces )
    {
        if ( namespaces == null )
            return;

        final XPathNamespaceContext namespaceContext = new XPathNamespaceContext();
        for ( Entry<String, String> entry : namespaces.entrySet() )
            namespaceContext.setMapping( entry.getKey(), entry.getValue() );

        xpath.setNamespaceContext( namespaceContext );
    }


    private static InputSource getInputSource(Message message) throws XPathExpressionException
    {
        Object payload;

        try
        {
            payload = payloadProxy.getPayload(message);
        }
        catch (MessageDeliverException e)
        {
            throw new XPathExpressionException(e);
        }

        if(payload instanceof byte[])
        {
            return new InputSource(new ByteArrayInputStream((byte[]) payload));
        }
        else if(payload instanceof String)
        {
            return new InputSource(new StringReader((String) payload));
        }
        else
        {
            throw new XPathExpressionException("Unsupport expression input object type: " + payload.getClass().getName());
        }
    }
   
    private static XPath getXPath( final Map<String,String> namespaces )
    {
    final XPath xpath = xpf.newXPath();
    setNamespaces( xpath, namespaces );
    return xpath;
    }
}
TOP

Related Classes of org.jboss.internal.soa.esb.services.routing.cbr.DslHelper

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.