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