Coverage Report - org.mule.module.xml.expression.JaxpXPathExpressionEvaluator
 
Classes in this File Line Coverage Branch Coverage Complexity
JaxpXPathExpressionEvaluator
0%
0/55
0%
0/18
0
JaxpXPathExpressionEvaluator$1
0%
0/7
0%
0/2
0
 
 1  
 /*
 2  
  * $Id: JaxpXPathExpressionEvaluator.java 20321 2010-11-24 15:21:24Z dfeist $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 package org.mule.module.xml.expression;
 11  
 
 12  
 import org.mule.api.MuleContext;
 13  
 import org.mule.api.MuleMessage;
 14  
 import org.mule.api.MuleRuntimeException;
 15  
 import org.mule.api.context.MuleContextAware;
 16  
 import org.mule.api.context.notification.MuleContextNotificationListener;
 17  
 import org.mule.api.expression.ExpressionEvaluator;
 18  
 import org.mule.api.lifecycle.Disposable;
 19  
 import org.mule.api.lifecycle.Initialisable;
 20  
 import org.mule.api.lifecycle.InitialisationException;
 21  
 import org.mule.api.registry.RegistrationException;
 22  
 import org.mule.context.notification.MuleContextNotification;
 23  
 import org.mule.module.xml.i18n.XmlMessages;
 24  
 import org.mule.module.xml.stax.MapNamespaceContext;
 25  
 import org.mule.module.xml.util.NamespaceManager;
 26  
 
 27  
 import java.util.Map;
 28  
 import java.util.WeakHashMap;
 29  
 
 30  
 import javax.xml.namespace.QName;
 31  
 import javax.xml.xpath.XPath;
 32  
 import javax.xml.xpath.XPathConstants;
 33  
 import javax.xml.xpath.XPathExpression;
 34  
 import javax.xml.xpath.XPathExpressionException;
 35  
 import javax.xml.xpath.XPathFactory;
 36  
 
 37  
 import org.mule.transformer.types.DataTypeFactory;
 38  
 import org.w3c.dom.Node;
 39  
 
 40  
 /**
 41  
  * Uses JAXP XPath processing to evaluate xpath expressions against Xml fragments and documents
 42  
  * <p/>
 43  
  * Note that the Jaxp Expression evaluator differs from the Mule XPATH evaluator slightly since you cna set the JaxP
 44  
  * return type as a prefix to the expression i.e.
 45  
  * <code>
 46  
  * xpath2:[node]/foo/bar
 47  
  * </code>
 48  
  * <p/>
 49  
  * Where the type can either be boolean, string, number, node or nodeset.  iBeans will automatically convert numbers based on the
 50  
  * return type as well as convert node to Document if required.
 51  
  */
 52  0
 public class JaxpXPathExpressionEvaluator implements ExpressionEvaluator, Initialisable, Disposable, MuleContextAware
 53  
 {
 54  
 
 55  0
     private Map cache = new WeakHashMap(8);
 56  
 
 57  
     private MuleContext muleContext;
 58  
     private NamespaceManager namespaceManager;
 59  0
     private QName returnType = XPathConstants.STRING;
 60  
 
 61  
     public JaxpXPathExpressionEvaluator()
 62  0
     {
 63  
 
 64  0
     }
 65  
 
 66  
     public String getName()
 67  
     {
 68  0
         return "xpath2";
 69  
     }
 70  
 
 71  
     public void setMuleContext(MuleContext context)
 72  
     {
 73  0
         this.muleContext = context;
 74  0
     }
 75  
 
 76  
     public void initialise() throws InitialisationException
 77  
     {
 78  
         try
 79  
         {
 80  
             /*
 81  
                 Workaround for standalone mode, when registry bootstrap order may be non-deterministic and lead
 82  
                 to failures on startup.
 83  
 
 84  
                 initialise() can't do any lookups as it will have spring create and init beans for things like
 85  
                 global endpoints, interfering with current lifecycle and leading to failure.
 86  
                 TODO AP/RM this will be solved by the @Inject annotation or phase, as discussed
 87  
 
 88  
                 RM*: Update: I'm hesistant to include support for @Inject since MUle isn't a DI container and
 89  
                 having this annotation (and associated @Named) sends a confusing message
 90  
              */
 91  0
             this.muleContext.registerListener(new MuleContextNotificationListener<MuleContextNotification>(){
 92  
 
 93  
                 public void onNotification(MuleContextNotification notification)
 94  
                 {
 95  
                     // CONTEXT_INITIALIZED fires too soon, before registry is inited, thus using this one
 96  0
                     if (MuleContextNotification.CONTEXT_STARTING == notification.getAction())
 97  
                     {
 98  
                         try
 99  
                         {
 100  0
                             namespaceManager = muleContext.getRegistry().lookupObject(NamespaceManager.class);
 101  
                         }
 102  0
                         catch (RegistrationException e)
 103  
                         {
 104  0
                             throw new RuntimeException(e);
 105  0
                         }
 106  
                     }
 107  0
                 }
 108  
             });
 109  
         }
 110  0
         catch (Throwable t)
 111  
         {
 112  0
             throw new InitialisationException(t, this);
 113  0
         }
 114  0
     }
 115  
 
 116  
     /**
 117  
      * {@inheritDoc}
 118  
      */
 119  
     public Object evaluate(String expression, MuleMessage message)
 120  
     {
 121  0
         QName retType = returnType;
 122  0
         if (expression.startsWith("["))
 123  
         {
 124  0
             int x = expression.indexOf("]");
 125  0
             if (x == -1)
 126  
             {
 127  0
                 throw new IllegalArgumentException("Expression is malformed: " + expression);
 128  
             }
 129  0
             String type = expression.substring(1, x);
 130  0
             expression = expression.substring(x + 1);
 131  0
             if (type.equalsIgnoreCase("boolean"))
 132  
             {
 133  0
                 retType = XPathConstants.BOOLEAN;
 134  
             }
 135  0
             else if (type.equalsIgnoreCase("string"))
 136  
             {
 137  0
                 retType = XPathConstants.STRING;
 138  
             }
 139  0
             else if (type.equalsIgnoreCase("node"))
 140  
             {
 141  0
                 retType = XPathConstants.NODE;
 142  
             }
 143  0
             else if (type.equalsIgnoreCase("nodeset"))
 144  
             {
 145  0
                 retType = XPathConstants.NODESET;
 146  
             }
 147  0
             else if (type.equalsIgnoreCase("number"))
 148  
             {
 149  0
                 retType = XPathConstants.NUMBER;
 150  
             }
 151  
             else
 152  
             {
 153  0
                 throw new IllegalArgumentException("Result type not recognised: " + type + ". Use either boolean, string, number, node or nodeset.");
 154  
             }
 155  
         }
 156  
         try
 157  
         {
 158  0
             Node payload = (Node) message.getPayload(DataTypeFactory.create(Node.class));
 159  
 
 160  0
             XPathExpression xpath = getXPath(expression);
 161  
 
 162  0
             return xpath.evaluate(payload, retType);
 163  
         }
 164  0
         catch (Exception e)
 165  
         {
 166  0
             throw new MuleRuntimeException(XmlMessages.failedToProcessXPath(expression), e);
 167  
         }
 168  
     }
 169  
 
 170  
     /**
 171  
      * {@inheritDoc}
 172  
      */
 173  
     public final void setName(String name)
 174  
     {
 175  0
         throw new UnsupportedOperationException("setName");
 176  
     }
 177  
 
 178  
     protected XPathExpression getXPath(String expression) throws XPathExpressionException
 179  
     {
 180  0
         XPathExpression xpath = (XPathExpression) cache.get(expression + getClass().getName());
 181  0
         if (xpath == null)
 182  
         {
 183  0
             xpath = createXPath(expression);
 184  0
             cache.put(expression + getClass().getName(), xpath);
 185  
         }
 186  0
         return xpath;
 187  
     }
 188  
 
 189  
     protected XPathExpression createXPath(String expression) throws XPathExpressionException
 190  
     {
 191  0
         XPath xp = XPathFactory.newInstance().newXPath();
 192  0
         if (getNamespaceManager() != null)
 193  
         {
 194  0
             xp.setNamespaceContext(new MapNamespaceContext(getNamespaceManager().getNamespaces()));
 195  
         }
 196  0
         return xp.compile(expression);
 197  
     }
 198  
 
 199  
     /**
 200  
      * A lifecycle method where implementor should free up any resources. If an
 201  
      * exception is thrown it should just be logged and processing should continue.
 202  
      * This method should not throw Runtime exceptions.
 203  
      */
 204  
     public void dispose()
 205  
     {
 206  0
         cache.clear();
 207  0
     }
 208  
 
 209  
     public NamespaceManager getNamespaceManager()
 210  
     {
 211  0
         return namespaceManager;
 212  
     }
 213  
 
 214  
     public void setNamespaceManager(NamespaceManager namespaceManager)
 215  
     {
 216  0
         this.namespaceManager = namespaceManager;
 217  0
     }
 218  
 
 219  
     public MuleContext getMuleContext()
 220  
     {
 221  0
         return muleContext;
 222  
     }
 223  
 
 224  
     public QName getReturnType()
 225  
     {
 226  0
         return returnType;
 227  
     }
 228  
 
 229  
     public void setReturnType(QName returnType)
 230  
     {
 231  0
         this.returnType = returnType;
 232  0
     }
 233  
 }
 234