Coverage Report - org.mule.module.xml.transformer.JXPathExtractor
 
Classes in this File Line Coverage Branch Coverage Complexity
JXPathExtractor
0%
0/67
0%
0/34
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.transformer;
 8  
 
 9  
 import org.mule.api.MuleContext;
 10  
 import org.mule.api.expression.ExpressionRuntimeException;
 11  
 import org.mule.api.lifecycle.InitialisationException;
 12  
 import org.mule.api.registry.RegistrationException;
 13  
 import org.mule.api.transformer.TransformerException;
 14  
 import org.mule.config.i18n.CoreMessages;
 15  
 import org.mule.module.xml.util.NamespaceManager;
 16  
 import org.mule.transformer.AbstractTransformer;
 17  
 import org.mule.util.StringUtils;
 18  
 
 19  
 import java.util.ArrayList;
 20  
 import java.util.HashMap;
 21  
 import java.util.List;
 22  
 import java.util.Map;
 23  
 
 24  
 import org.apache.commons.jxpath.JXPathContext;
 25  
 import org.dom4j.Document;
 26  
 import org.dom4j.DocumentHelper;
 27  
 import org.dom4j.Node;
 28  
 import org.dom4j.XPath;
 29  
 
 30  
 /**
 31  
  * The JXPathExtractor is a simple transformer that evaluates an xpath expression
 32  
  * against the given bean and that returns the result. <p/> By default, a single
 33  
  * result will be returned. If multiple values are expected, set the
 34  
  * {@link #singleResult} property to <code>false</code>. In this case a
 35  
  * {@link List} of values will be returned. Note the property is currently ignored
 36  
  * for non-String/XML payloads.
 37  
  */
 38  0
 public class JXPathExtractor extends AbstractTransformer
 39  
 {
 40  
     public static final String OUTPUT_TYPE_NODE = "NODE";
 41  
 
 42  
     public static final String OUTPUT_TYPE_XML = "XML";
 43  
 
 44  
     public static final String OUTPUT_TYPE_VALUE = "VALUE";
 45  
 
 46  
     private volatile String expression;
 47  
     
 48  
     private volatile String outputType;
 49  
     
 50  
     private volatile Map namespaces;
 51  
 
 52  0
     private volatile boolean singleResult = true;
 53  
 
 54  
     private NamespaceManager namespaceManager;
 55  
 
 56  
     public void setMuleContext(MuleContext context)
 57  
     {
 58  0
         this.muleContext = context;
 59  
         try
 60  
         {
 61  0
             namespaceManager = muleContext.getRegistry().lookupObject(NamespaceManager.class);
 62  
         }
 63  0
         catch (RegistrationException e)
 64  
         {
 65  0
             throw new ExpressionRuntimeException(CoreMessages.failedToLoad("NamespaceManager"), e);
 66  0
         }
 67  0
     }
 68  
 
 69  
     /**
 70  
      * Template method where deriving classes can do any initialisation after the
 71  
      * properties have been set on this transformer
 72  
      *
 73  
      * @throws org.mule.api.lifecycle.InitialisationException
 74  
      *
 75  
      */
 76  
     @Override
 77  
     public void initialise() throws InitialisationException
 78  
     {
 79  0
         super.initialise();
 80  0
         if (namespaceManager != null)
 81  
         {
 82  0
             if (namespaces == null)
 83  
             {
 84  0
                 namespaces = new HashMap(namespaceManager.getNamespaces());
 85  
             }
 86  
             else
 87  
             {
 88  0
                 namespaces.putAll(namespaceManager.getNamespaces());
 89  
             }
 90  
         }
 91  0
     }
 92  
 
 93  
     /**
 94  
      * Evaluate the expression in the context of the given object and returns the
 95  
      * result. If the given object is a string, it assumes it is an valid xml and
 96  
      * parses it before evaluating the xpath expression.
 97  
      */
 98  
     public Object doTransform(Object src, String encoding) throws TransformerException
 99  
     {
 100  
         try
 101  
         {
 102  0
             Object result = null;
 103  0
             if (src instanceof String)
 104  
             {
 105  0
                 Document doc = DocumentHelper.parseText((String) src);
 106  
 
 107  0
                 XPath xpath = doc.createXPath(expression);
 108  0
                 if (namespaces != null)
 109  
                 {
 110  0
                     xpath.setNamespaceURIs(namespaces);
 111  
                 }
 112  
                 
 113  
                 // This is the way we always did it before, so keep doing it that way
 114  
                 // as xpath.evaluate() will return non-string results (like Doubles)
 115  
                 // for some scenarios.
 116  0
                 if (outputType == null && singleResult)
 117  
                 {
 118  0
                     return xpath.valueOf(doc);
 119  
                 }
 120  
                 
 121  
                 // TODO handle non-list cases, see
 122  
                 //http://www.dom4j.org/apidocs/org/dom4j/XPath.html#evaluate(java.lang.Object)
 123  0
                 Object obj = xpath.evaluate(doc);
 124  0
                 if (obj instanceof List)
 125  
                 {
 126  0
                     for (int i = 0; i < ((List) obj).size(); i++)
 127  
                     {
 128  0
                         final Node node = (Node) ((List) obj).get(i);
 129  0
                         result = add(result, node);
 130  
                         
 131  0
                         if (singleResult)
 132  
                         {
 133  0
                             break;
 134  
                         }
 135  
                     }
 136  
                 }
 137  
                 else
 138  
                 {
 139  0
                     result = add(result, obj);
 140  
                 }
 141  
 
 142  0
             }
 143  
             else
 144  
             {
 145  0
                 JXPathContext context = JXPathContext.newContext(src);
 146  0
                 result = context.getValue(expression);
 147  
             }
 148  0
             return result;
 149  
         }
 150  0
         catch (Exception e)
 151  
         {
 152  0
             throw new TransformerException(this, e);
 153  
         }
 154  
 
 155  
     }
 156  
     
 157  
     private Object add(Object result, Object value)
 158  
     {
 159  0
         Object formattedResult = getResult(value);
 160  0
         if (singleResult)
 161  
         {
 162  0
             return formattedResult;
 163  
         }
 164  
         else
 165  
         {
 166  0
             if (result == null)
 167  
             {
 168  0
                 result = new ArrayList();
 169  
             }
 170  
             
 171  0
             ((List) result).add(formattedResult);
 172  
         }
 173  0
         return result;
 174  
     }
 175  
 
 176  
     private Object getResult(Object value)
 177  
     {
 178  0
         Object result = null;
 179  0
         if (StringUtils.contains(OUTPUT_TYPE_VALUE, outputType) || outputType == null)
 180  
         {
 181  0
             if (value instanceof Node)
 182  
             {
 183  0
                 result = ((Node) value).getText();
 184  
             }
 185  
             else
 186  
             {
 187  
                 // this maintains backward compat with previous 2.1.x versions. 
 188  0
                 result = value.toString();
 189  
             }
 190  
         }
 191  0
         else if (StringUtils.contains(OUTPUT_TYPE_XML, outputType))
 192  
         {
 193  0
             if (value instanceof Node)
 194  
             {
 195  0
                 result = ((Node) value).asXML();
 196  
             }
 197  
             else 
 198  
             {
 199  0
                 throw new IllegalStateException("XPath expression output must be a Node to output as XML. Expression type was: " + value.getClass());
 200  
             }
 201  
         }
 202  0
         else if (StringUtils.contains(OUTPUT_TYPE_NODE, outputType))
 203  
         {
 204  0
             result = value;
 205  
         }
 206  0
         return result;
 207  
     }
 208  
 
 209  
     /**
 210  
      * @return Returns the expression.
 211  
      */
 212  
     public String getExpression()
 213  
     {
 214  0
         return expression;
 215  
     }
 216  
 
 217  
     /**
 218  
      * @param expression The expression to set.
 219  
      */
 220  
     public void setExpression(String expression)
 221  
     {
 222  0
         this.expression = expression;
 223  0
     }
 224  
 
 225  
     /**
 226  
      * Should a single value be returned.
 227  
      * 
 228  
      * @return value
 229  
      */
 230  
     public boolean isSingleResult()
 231  
     {
 232  0
         return singleResult;
 233  
     }
 234  
 
 235  
     /**
 236  
      * If multiple results are expected from the {@link #expression} evaluation, set
 237  
      * this to false.
 238  
      * 
 239  
      * @param singleResult flag
 240  
      */
 241  
     public void setSingleResult(boolean singleResult)
 242  
     {
 243  0
         this.singleResult = singleResult;
 244  0
     }
 245  
 
 246  
     public String getOutputType()
 247  
     {
 248  0
         return outputType;
 249  
     }
 250  
 
 251  
     public void setOutputType(String outputEncoding)
 252  
     {
 253  0
         this.outputType = outputEncoding;
 254  0
     }
 255  
 
 256  
     public Map getNamespaces()
 257  
     {
 258  0
         return namespaces;
 259  
     }
 260  
 
 261  
     public void setNamespaces(Map namespaceURIs)
 262  
     {
 263  0
         this.namespaces = namespaceURIs;
 264  0
     }
 265  
     
 266  
 }