Coverage Report - org.mule.expression.ExpressionUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
ExpressionUtils
0%
0/93
0%
0/68
0
 
 1  
 /*
 2  
  * $Id: ExpressionUtils.java 20473 2010-12-06 18:30:34Z 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  
 
 11  
 package org.mule.expression;
 12  
 
 13  
 import static org.mule.expression.ExpressionConstants.ALL_ARGUMENT;
 14  
 import static org.mule.expression.ExpressionConstants.DELIM;
 15  
 import static org.mule.expression.ExpressionConstants.OPTIONAL_ARGUMENT;
 16  
 
 17  
 import org.mule.api.MuleMessage;
 18  
 import org.mule.api.expression.RequiredValueException;
 19  
 import org.mule.api.transport.PropertyScope;
 20  
 import org.mule.config.i18n.CoreMessages;
 21  
 import org.mule.routing.filters.WildcardFilter;
 22  
 
 23  
 import java.util.ArrayList;
 24  
 import java.util.Collections;
 25  
 import java.util.HashMap;
 26  
 import java.util.List;
 27  
 import java.util.Map;
 28  
 
 29  
 /**
 30  
  * Used by the different header expression evaluators to read message properties, honuouring scope and return type
 31  
  */
 32  
 public final class ExpressionUtils
 33  
 {
 34  
     private ExpressionUtils()
 35  0
     {
 36  
         // don't instantiate
 37  0
     }
 38  
 
 39  
     /**
 40  
      * Gets a property or map/list of properties specific by an expression supporting multiple return types as well as all and optional modifiers
 41  
      * 
 42  
      * Handles scope-aware expressions like "#[header:INBOUND:foo]
 43  
      * @param expression the header name to evaluate.  this can be prefixed with a message scope such as INBOUND, OUTBOUND
 44  
      * or INVOCATION scope. If no scope is defined the default scope is OUTBOUND
 45  
      * 
 46  
      * @param msg the message to evaluate on
 47  
      */
 48  
     public static Object getPropertyWithScope(String expression, MuleMessage msg)
 49  
     {
 50  0
         return getPropertyWithScope(expression, msg, Object.class);
 51  
     }
 52  
     
 53  
     /**
 54  
      * Gets a property or map/list of properties specific by an expression supporting multiple return types as well as all and optional modifiers
 55  
      *
 56  
      * Handles scope-aware expressions like "#[header:INBOUND:foo]
 57  
      * @param expression the header name to evaluate.  this can be prefixed with a message scope such as INBOUND, OUTBOUND
 58  
      * or INVOCATION scope. If no scope is defined the default scope is OUTBOUND
 59  
      * 
 60  
      * @param msg the message to evaluate on
 61  
      * @param type the expected return type for this evaluation
 62  
      * @return  an object of type 'type' corresponding to the message header requested or null if the header was not on
 63  
      * the message in the specified scope
 64  
      */
 65  
     public static <T> T getPropertyWithScope(String expression, MuleMessage msg, Class<T> type)
 66  
     {
 67  0
         return getPropertyInternal(expression, PropertyScope.OUTBOUND, true, msg, type);
 68  
     }
 69  
     
 70  
     /**
 71  
      * Gets a property or map/list of properties specific by an expression supporting multiple return types as well as all and optional modifiers
 72  
      * 
 73  
      * @param msg the message to evaluate on
 74  
      * @param type the expected return type for this evaluation
 75  
      * @return  an object of type 'type' corresponding to the message header requested or null if the header was not on
 76  
      * the message in the specified scope
 77  
      */
 78  
     public static Object getProperty(String expression, PropertyScope scope, MuleMessage msg)
 79  
     {
 80  0
         return getProperty(expression, scope, msg, Object.class);
 81  
     }
 82  
     
 83  
     /**
 84  
      * Gets a property or map/list of properties specific by an expression supporting multiple return types as well as all and optional modifiers
 85  
      * 
 86  
      * @param msg the message to evaluate on
 87  
      * @param type the expected return type for this evaluation
 88  
      * @return  an object of type 'type' corresponding to the message header requested or null if the header was not on
 89  
      * the message in the specified scope
 90  
      */
 91  
     public static <T> T getProperty(String expression, PropertyScope scope,  MuleMessage msg, Class<T> type)
 92  
     {
 93  0
         return getPropertyInternal(expression, scope, false, msg, type);
 94  
     }
 95  
 
 96  
     /**
 97  
      * Obtains a property or map/list of properties from a message using an expression that specifies which property or properties to evaluate.
 98  
      * This method can be used  default scope 
 99  
      * @param expression the expression used to evaluator the message
 100  
      * @param scope the scope to be used when obtaining a property.  This is the default if parseScopes is true.
 101  
      * @param parseScope should scope we parsed from expression string.  When true the scope acts as a default.
 102  
      * @param msg the message to be evaluated
 103  
      * @param type return type expected
 104  
      * @return property or list/map of evaluated property values 
 105  
      */
 106  
     @SuppressWarnings("unchecked")
 107  
     protected static <T> T getPropertyInternal(String expression, PropertyScope scope, boolean parseScope, MuleMessage msg, Class<T> type)
 108  
     {
 109  0
         if (parseScope)
 110  
         {
 111  0
             PropertyScope tempScope = getScope(expression);
 112  0
             if (tempScope != null)
 113  
             {
 114  
                 // cut-off leading scope and separator
 115  0
                 expression = expression.substring(tempScope.getScopeName().length() + 1);
 116  0
                 scope = tempScope;
 117  
             }
 118  
         }
 119  
         
 120  0
         if (expression.contains(ALL_ARGUMENT))
 121  
         {
 122  0
             WildcardFilter filter = new WildcardFilter(expression);
 123  0
             if (Map.class.isAssignableFrom(type))
 124  
             {
 125  0
                 Map<String, Object> props = new HashMap<String, Object>();
 126  0
                 for (String name : msg.getPropertyNames(scope))
 127  
                 {
 128  0
                     if (filter.accept(name))
 129  
                     {
 130  0
                         props.put(name, msg.getProperty(name, scope));
 131  
                     }
 132  
                 }
 133  0
                 return (T) returnMap(props, scope);
 134  
             }
 135  0
             else if (List.class.isAssignableFrom(type))
 136  
             {
 137  0
                 List<Object> values = new ArrayList<Object>();
 138  0
                 for (String name : msg.getPropertyNames(scope))
 139  
                 {
 140  0
                     if (filter.accept(name))
 141  
                     {
 142  0
                         values.add(msg.getProperty(name, scope));
 143  
                     }
 144  
                 }
 145  0
                 return (T) returnList(values, scope);
 146  
             }
 147  
             else
 148  
             {
 149  
                 //TODO i18n
 150  0
                 throw new IllegalArgumentException("Type specified is not a collection type but '" + ALL_ARGUMENT + "' was specified for all properties. Type is: " + type);
 151  
             }
 152  
         }
 153  0
         else if (Map.class.isAssignableFrom(type))
 154  
         {
 155  0
             String[] names = expression.split(DELIM);
 156  0
             Map<String, Object> props = new HashMap<String, Object>();
 157  0
             for (String name : names)
 158  
             {
 159  0
                 boolean required = true;
 160  0
                 name = name.trim();
 161  0
                 PropertyScope entryScope = scope;
 162  0
                 if (parseScope)
 163  
                 {
 164  0
                     entryScope = getScope(name);
 165  0
                     if (entryScope != null)
 166  
                     {
 167  
                         // cut-off leading scope and separator
 168  0
                         name = name.substring(entryScope.getScopeName().length() + 1);
 169  
                     }
 170  
                     else
 171  
                     {
 172  0
                         entryScope = scope;
 173  
                     }
 174  
                 }
 175  0
                 if (name.endsWith(OPTIONAL_ARGUMENT))
 176  
                 {
 177  0
                     name = name.substring(0, name.length() - OPTIONAL_ARGUMENT.length());
 178  0
                     required = false;
 179  
                 }
 180  0
                 Object value = msg.getProperty(name, entryScope);
 181  0
                 if (value == null && required)
 182  
                 {
 183  0
                     throw new RequiredValueException(CoreMessages.expressionEvaluatorReturnedNull("headers", entryScope.getScopeName() + ":" + name));
 184  
                 }
 185  0
                 else if (value != null)
 186  
                 {
 187  0
                     props.put(name, value);
 188  
                 }
 189  
             }
 190  0
             return (T) returnMap(props, scope);
 191  
         }
 192  0
         else if (List.class.isAssignableFrom(type))
 193  
         {
 194  0
             String[] names = expression.split(DELIM);
 195  0
             List<Object> values = new ArrayList<Object>();
 196  0
             for (String name : names)
 197  
             {
 198  0
                 boolean required = true;
 199  0
                 name = name.trim();
 200  0
                 PropertyScope itemScope = scope;
 201  0
                 if (parseScope)
 202  
                 {
 203  0
                     itemScope = getScope(name);
 204  0
                     if (itemScope != null)
 205  
                     {
 206  
                         // cut-off leading scope and separator
 207  0
                         name = name.substring(itemScope.getScopeName().length() + 1);
 208  
                     }
 209  
                     else
 210  
                     {
 211  0
                         itemScope = scope;
 212  
                     }
 213  
                 }
 214  0
                 if (name.endsWith(OPTIONAL_ARGUMENT))
 215  
                 {
 216  0
                     name = name.substring(0, name.length() - OPTIONAL_ARGUMENT.length());
 217  0
                     required = false;
 218  
                 }
 219  0
                 name = name.trim();
 220  0
                 Object value = msg.getProperty(name, itemScope);
 221  0
                 if (value == null && required)
 222  
                 {
 223  0
                     throw new RequiredValueException(CoreMessages.expressionEvaluatorReturnedNull("headers-list", itemScope.getScopeName() + ":" + name));
 224  
                 }
 225  0
                 else if (value != null)
 226  
                 {
 227  0
                     values.add(value);
 228  
                 }
 229  
             }
 230  0
             return (T) returnList(values, scope);
 231  
         }
 232  
         else
 233  
         {
 234  0
             boolean required = true;
 235  0
             if (expression.endsWith(OPTIONAL_ARGUMENT))
 236  
             {
 237  0
                 expression = expression.substring(0, expression.length() - OPTIONAL_ARGUMENT.length());
 238  0
                 required = false;
 239  
             }
 240  0
             Object result = msg.getProperty(expression.trim(), scope);
 241  0
             if (result == null && required)
 242  
             {
 243  0
                 throw new RequiredValueException(CoreMessages.expressionEvaluatorReturnedNull("header", scope.getScopeName() + ":" + expression));
 244  
 
 245  
             }
 246  0
             return (T) result;
 247  
         }
 248  
     }
 249  
 
 250  
     private static Map<String, Object> returnMap(Map<String, Object> props, PropertyScope scope)
 251  
     {
 252  0
         Map<String, Object> p = (props.size() == 0 ? Collections.<String, Object>emptyMap() : props);
 253  0
         if (scope.equals(PropertyScope.INBOUND))
 254  
         {
 255  0
             p = Collections.unmodifiableMap(p);
 256  
         }
 257  0
         return p;
 258  
     }
 259  
 
 260  
     private static List<Object> returnList(List<Object> values, PropertyScope scope)
 261  
     {
 262  0
         List<Object> l = (values.size() == 0 ? Collections.emptyList() : values);
 263  0
         if (scope.equals(PropertyScope.INBOUND))
 264  
         {
 265  0
             l = Collections.unmodifiableList(l);
 266  
         }
 267  0
         return l;
 268  
     }
 269  
 
 270  
     protected static PropertyScope getScope(String expression)
 271  
     {
 272  
         // see if scope has been specified explicitly
 273  0
         final String[] tokens = expression.split(":", 2); // note we split only once, not on every separator
 274  
         PropertyScope scope;
 275  0
         if (tokens.length == 2)
 276  
         {
 277  0
             final String candidate = tokens[0];
 278  0
             scope = PropertyScope.get(candidate.toLowerCase());
 279  0
             if (scope == null)
 280  
             {
 281  0
                 throw new IllegalArgumentException(String.format("'%s' is not a valid property scope.", candidate));
 282  
             }
 283  
 
 284  0
             return scope;
 285  
         }
 286  0
         return null;
 287  
     }
 288  
 }