2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to you under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.shale.test.el;
19  
20  import java.util.ArrayList;
21  import java.util.List;
22  import javax.el.ELContext;
23  import javax.el.ELResolver;
24  import javax.el.ValueExpression;
25  import javax.faces.context.FacesContext;
26  
27  /***
28   * <p>Mock implementation of <code>ValueExpression</code>.</p>
29   *
30   * <p>This implementation supports a limited subset of overall expression functionality:</p>
31   * <ul>
32   * <li>A literal string that contains no expression delimiters.</li>
33   * <li>An expression that starts with "#{" or "${", and ends with "}".</li>
34   * </ul>
35   */
36  public class MockValueExpression extends ValueExpression {
37      
38  
39      // ------------------------------------------------------------ Constructors
40  
41  
42      /***
43       * Serial version UID.
44       */
45      private static final long serialVersionUID = -8649071428507512623L;
46  
47  
48      /***
49       * <p>Construct a new expression for the specified expression string.</p>
50       *
51       * @param expression Expression string to be evaluated
52       * @param expectedType Expected type of the result
53       */
54      public MockValueExpression(String expression, Class expectedType) {
55  
56          if (expression == null) {
57              throw new NullPointerException("Expression string cannot be null");
58          }
59          this.expression = expression;
60          this.expectedType = expectedType;
61          parse();
62  
63      }
64  
65  
66      // ------------------------------------------------------ Instance Variables
67  
68  
69      /***
70       * <p>The parsed elements of this expression.</p>
71       */
72      private String[] elements = null;
73  
74  
75      /***
76       * <p>The expected result type for <code>getValue()</code> calls.</p>
77       */
78      private Class expectedType = null;
79  
80  
81      /***
82       * <p>The original expression string used to create this expression.</p>
83       */
84      private String expression = null;
85  
86  
87      // ------------------------------------------------------ Expression Methods
88  
89  
90      /***
91       * <p>Return <code>true</code> if this expression is equal to the
92       * specified expression.</p>
93       *
94       * @param obj Object to be compared
95       */
96      public boolean equals(Object obj) {
97  
98          if ((obj != null) & (obj instanceof ValueExpression)) {
99              return expression.equals(((ValueExpression) obj).getExpressionString());
100         } else {
101             return false;
102         }
103 
104     }
105 
106 
107     /***
108      * <p>Return the original String used to create this expression,
109      * unmodified.</p>
110      */
111     public String getExpressionString() {
112 
113         return this.expression;
114 
115     }
116 
117 
118     /***
119      * <p>Return the hash code for this expression.</p>
120      */
121     public int hashCode() {
122 
123         return this.expression.hashCode();
124 
125     }
126 
127 
128     /***
129      * <p>Return <code>true</code> if the expression string for this expression
130      * contains only literal text.</p>
131      */
132     public boolean isLiteralText() {
133 
134         return (expression.indexOf("${") < 0) && (expression.indexOf("#{") < 0);
135 
136     }
137 
138 
139     // ------------------------------------------------- ValueExpression Methods
140 
141 
142     /***
143      * <p>Return the type that the result of this expression will
144      * be coerced to.</p>
145      */
146     public Class getExpectedType() {
147 
148         return this.expectedType;
149 
150     }
151 
152 
153     /***
154      * <p>Evaluate this expression relative to the specified context,
155      * and return the most general type that is acceptable for the
156      * value passed in a <code>setValue()</code> call.</p>
157      *
158      * @param context ELContext for this evaluation
159      */
160     public Class getType(ELContext context) {
161 
162         if (context == null) {
163             throw new NullPointerException();
164         }
165         Object value = getValue(context);
166         if (value == null) {
167             return null;
168         } else {
169             return value.getClass();
170         }
171 
172     }
173 
174 
175     /***
176      * <p>Evaluate this expression relative to the specified context,
177      * and return the result.</p>
178      *
179      * @param context ELContext for this evaluation
180      */
181     public Object getValue(ELContext context) {
182 
183         if (context == null) {
184             throw new NullPointerException();
185         }
186         if (isLiteralText()) {
187             return expression;
188         }
189 
190         FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
191         ELResolver resolver = fcontext.getApplication().getELResolver();
192         Object base = null;
193         for (int i = 0; i < elements.length; i++) {
194             base = resolver.getValue(context, base, elements[i]);
195         }
196         return fcontext.getApplication().getExpressionFactory().coerceToType(base, getExpectedType());
197 
198     }
199 
200 
201     /***
202      * <p>Evaluate this expression relative to the specified context,
203      * and return <code>true</code> if a call to <code>setValue()</code>
204      * will always fail.</p>
205      *
206      * @param context ELContext for this evaluation
207      */
208     public boolean isReadOnly(ELContext context) {
209 
210         if (context == null) {
211             throw new NullPointerException();
212         }
213         if (isLiteralText()) {
214             return true;
215         }
216 
217         FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
218         ELResolver resolver = fcontext.getApplication().getELResolver();
219         Object base = null;
220         for (int i = 0; i < elements.length - 1; i++) {
221             base = resolver.getValue(context, base, elements[i]);
222         }
223         return resolver.isReadOnly(context, base, elements[elements.length - 1]);
224 
225     }
226 
227 
228 
229     /***
230      * <p>Evaluate this expression relative to the specified context,
231      * and set the result to the specified value.</p>
232      *
233      * @param context ELContext for this evaluation
234      * @param value Value to which the result should be set
235      */
236     public void setValue(ELContext context, Object value) {
237 
238         if (context == null) {
239             throw new NullPointerException();
240         }
241 
242         FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
243         ELResolver resolver = fcontext.getApplication().getELResolver();
244         Object base = null;
245         for (int i = 0; i < elements.length - 1; i++) {
246             base = resolver.getValue(context, base, elements[i]);
247         }
248         resolver.setValue(context, base, elements[elements.length - 1], value);
249 
250     }
251 
252 
253     // --------------------------------------------------------- Private Methods
254 
255 
256     /***
257      * <p>Parse the expression string into its constituent elemetns.</p>
258      */
259     private void parse() {
260 
261         if (isLiteralText()) {
262             elements = new String[0];
263             return;
264         }
265 
266         if (expression.startsWith("${") || expression.startsWith("#{")) {
267             if (expression.endsWith("}")) {               
268                 List names = new ArrayList();
269                 StringBuffer expr = new StringBuffer(expression.substring(2, expression.length() - 1).replaceAll(" ", ""));
270                 boolean isBlockOn = false;
271                 for (int i = expr.length() - 1; i > -1; i--) {
272                     if (expr.charAt(i) == ' ') {
273                         expr.deleteCharAt(i);
274                     } else if (expr.charAt(i) == ']') {
275                         expr.deleteCharAt(i);
276                     } else if (expr.charAt(i) == '[') {
277                         expr.deleteCharAt(i);
278                     } else if (expr.charAt(i) == '\'') {
279                         if (!isBlockOn) {
280                             expr.deleteCharAt(i);
281                         } else {
282                             names.add(0, expr.substring(i + 1));
283                             expr.delete(i, expr.length());
284                         }
285                         isBlockOn = !isBlockOn;
286                     } else if (expr.charAt(i) == '.' && !isBlockOn) {
287                         names.add(0, expr.substring(i + 1));
288                         expr.delete(i, expr.length());
289                     }
290                 }
291                 if (expr.length() > 0) {
292                     names.add(0, expr.toString());
293                 }
294 
295                 elements = (String[]) names.toArray(new String[names.size()]);
296             } else {
297                 throw new IllegalArgumentException(expression);
298             }
299         } else {
300             throw new IllegalArgumentException(expression);
301         }
302 
303     }
304 
305 
306 }