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