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