View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.myfaces.orchestra.flow.utils;
21  
22  import java.util.Stack;
23  
24  import javax.el.ELContext;
25  import javax.el.ExpressionFactory;
26  import javax.el.MethodExpression;
27  import javax.el.ValueExpression;
28  import javax.faces.context.FacesContext;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.myfaces.orchestra.lib.OrchestraException;
33  
34  import com.sun.facelets.FaceletContext;
35  
36  /**
37   * Creates ValueExpression objects based on the "current" ELContext.
38   * <p>
39   * This class allows an ELContext to be "tunnelled" as a thread-local variable to places where code
40   * wants to create a ValueExpression even though the ELContext is not available as a parameter.
41   */
42  public class _ExpressionFactory
43  {
44      private static final ThreadLocal<Stack<ELContext>> _contextsThreadLocal = new ThreadLocal<Stack<ELContext>>();
45  
46      public static void pushContext(ELContext ctx)
47      {
48          if (ctx == null)
49          {
50              throw new IllegalArgumentException("ctx must not be null");
51          }
52          Stack<ELContext> s = _contextsThreadLocal.get();
53          if (s == null)
54          {
55              s = new Stack<ELContext>();
56              _contextsThreadLocal.set(s);
57          }
58          s.push(ctx);
59      }
60  
61      public static void popContext(ELContext ctx)
62      {
63          Stack<ELContext> s = _contextsThreadLocal.get();
64          if (s == null)
65          {
66              throw new IllegalStateException("context stack is null");
67          }
68          if (s.isEmpty())
69          {
70              throw new IllegalStateException("context stack is empty");
71          }
72          Object o = s.pop();
73          if (o != ctx)
74          {
75              throw new IllegalStateException("context stack unbalanced");
76          }
77          if (s.isEmpty())
78          {
79              _contextsThreadLocal.remove();
80          }
81      }
82  
83      private static FaceletContext peekContext()
84      {
85          Stack<ELContext> s = _contextsThreadLocal.get();
86          if (s == null)
87          {
88              return null;
89          }
90          return (FaceletContext) s.peek();
91      }
92  
93      public static ValueExpression createValueExpression(FacesContext facesContext, String expr)
94      {
95          ELContext elContext = peekContext();
96          if (elContext == null)
97          {
98              // ok, we are not running within the context of some particular UIComponent, ie we are
99              // not processing xml embedded within an of:flowCall tag in a JSP page. We are probably
100             // processing a flow.xml file loaded from the disk. In this case, just use the "global"
101             // el context held by the FacesContext object.
102             elContext = facesContext.getELContext();
103         }
104 
105         try
106         {
107             ExpressionFactory ef = facesContext.getApplication().getExpressionFactory();
108             ValueExpression ve = ef.createValueExpression(elContext, expr, Object.class);
109             return ve;
110         }
111         catch(Exception e)
112         {
113             Log log = LogFactory.getLog(_ExpressionFactory.class);
114             String msg = "Unable to parse value expression in flow:" + expr;
115             log.warn(msg, e);
116             throw new OrchestraException(msg, e);
117         }
118     }
119 
120     public static MethodExpression createMethodExpression(FacesContext facesContext, String expr)
121     {
122         ELContext elContext = peekContext();
123         if (elContext == null)
124         {
125             // ok, we are not running within the context of some particular UIComponent, ie we are
126             // not processing xml embedded within an of:flowCall tag in a JSP page. We are probably
127             // processing a flow.xml file loaded from the disk. In this case, just use the "global"
128             // el context held by the FacesContext object.
129             elContext = facesContext.getELContext();
130         }
131 
132         try
133         {
134             ExpressionFactory ef = facesContext.getApplication().getExpressionFactory();
135             MethodExpression me = ef.createMethodExpression(elContext, expr, Object.class, null);
136             return me;
137         }
138         catch(Exception e)
139         {
140             Log log = LogFactory.getLog(_ExpressionFactory.class);
141             String msg = "Unable to parse method expression in flow:" + expr;
142             log.warn(msg, e);
143             throw new OrchestraException(msg, e);
144         }
145     }
146 }