Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: ognl/SimpleNode.java


1   //--------------------------------------------------------------------------
2   //  Copyright (c) 1998-2004, Drew Davidson and Luke Blanshard
3   //  All rights reserved.
4   //
5   //  Redistribution and use in source and binary forms, with or without
6   //  modification, are permitted provided that the following conditions are
7   //  met:
8   //
9   //  Redistributions of source code must retain the above copyright notice,
10  //  this list of conditions and the following disclaimer.
11  //  Redistributions in binary form must reproduce the above copyright
12  //  notice, this list of conditions and the following disclaimer in the
13  //  documentation and/or other materials provided with the distribution.
14  //  Neither the name of the Drew Davidson nor the names of its contributors
15  //  may be used to endorse or promote products derived from this software
16  //  without specific prior written permission.
17  //
18  //  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  //  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  //  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  //  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  //  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  //  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  //  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25  //  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  //  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  //  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28  //  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
29  //  DAMAGE.
30  //--------------------------------------------------------------------------
31  package ognl;
32  
33  import java.io.*;
34  
35  /**
36   * @author Luke Blanshard (blanshlu@netscape.net)
37   * @author Drew Davidson (drew@ognl.org)
38   */
39  public abstract class SimpleNode implements Node, Serializable
40  {
41      protected Node          parent;
42      protected Node[]        children;
43      protected int           id;
44      protected OgnlParser    parser;
45  
46      private boolean         constantValueCalculated;
47      private boolean         hasConstantValue;
48      private Object          constantValue;
49  
50      public SimpleNode(int i) {
51          id = i;
52      }
53  
54      public SimpleNode(OgnlParser p, int i) {
55          this(i);
56          parser = p;
57      }
58  
59      public void jjtOpen() {
60      }
61  
62      public void jjtClose() {
63      }
64  
65      public void jjtSetParent(Node n) { parent = n; }
66      public Node jjtGetParent() { return parent; }
67  
68      public void jjtAddChild(Node n, int i) {
69          if (children == null) {
70              children = new Node[i + 1];
71          } else if (i >= children.length) {
72              Node c[] = new Node[i + 1];
73              System.arraycopy(children, 0, c, 0, children.length);
74              children = c;
75          }
76          children[i] = n;
77      }
78  
79      public Node jjtGetChild(int i) {
80          return children[i];
81      }
82  
83      public int jjtGetNumChildren() {
84          return (children == null) ? 0 : children.length;
85      }
86  
87        /* You can override these two methods in subclasses of SimpleNode to
88           customize the way the node appears when the tree is dumped.  If
89           your output uses more than one line you should override
90           toString(String), otherwise overriding toString() is probably all
91           you need to do. */
92  
93      public String toString() { return OgnlParserTreeConstants.jjtNodeName[id]; }
94  
95  // OGNL additions
96  
97      public String toString(String prefix) { return prefix + OgnlParserTreeConstants.jjtNodeName[id] + " " + toString(); }
98  
99        /* Override this method if you want to customize how the node dumps
100          out its children. */
101 
102     public void dump(PrintWriter writer, String prefix) {
103         writer.println(toString(prefix));
104         if (children != null) {
105             for (int i = 0; i < children.length; ++i) {
106                 SimpleNode n = (SimpleNode)children[i];
107                 if (n != null) {
108                     n.dump(writer, prefix + "  ");
109                 }
110             }
111         }
112     }
113 
114     public int getIndexInParent()
115     {
116         int     result = -1;
117 
118         if (parent != null) {
119             int     icount = parent.jjtGetNumChildren();
120 
121             for (int i = 0; i < icount; i++) {
122                 if (parent.jjtGetChild(i) == this) {
123                     result = i;
124                     break;
125                 }
126             }
127         }
128         return result;
129     }
130 
131     public Node getNextSibling()
132     {
133         Node    result = null;
134         int     i = getIndexInParent();
135 
136         if (i >= 0) {
137             int     icount = parent.jjtGetNumChildren();
138 
139             if (i < icount) {
140                 result = parent.jjtGetChild(i + 1);
141             }
142         }
143         return result;
144     }
145 
146     private static String getDepthString(int depth)
147     {
148         StringBuffer    result = new StringBuffer("");
149 
150         while (depth > 0) {
151             depth--;
152             result.append("  ");
153         }
154         return new String(result);
155     }
156 
157     protected Object evaluateGetValueBody( OgnlContext context, Object source ) throws OgnlException
158     {
159         Object      result;
160 
161         context.setCurrentObject(source);
162         context.setCurrentNode(this);
163         if (!constantValueCalculated) {
164             constantValueCalculated = true;
165             hasConstantValue = isConstant(context);
166             if (hasConstantValue) {
167                 constantValue = getValueBody(context, source);
168             }
169         }
170         return hasConstantValue ? constantValue : getValueBody(context, source);
171     }
172 
173     protected void evaluateSetValueBody( OgnlContext context, Object target, Object value ) throws OgnlException
174     {
175         context.setCurrentObject(target);
176         context.setCurrentNode(this);
177         setValueBody(context, target, value);
178     }
179 
180     public final Object getValue( OgnlContext context, Object source ) throws OgnlException
181     {
182         if (context.getTraceEvaluations()) {
183             EvaluationPool  pool = OgnlRuntime.getEvaluationPool();
184             Object          result = null;
185             Throwable       evalException = null;
186             Evaluation      evaluation = pool.create(this, source);
187 
188             context.pushEvaluation(evaluation);
189             try {
190                 result = evaluateGetValueBody(context, source);
191             } catch (OgnlException ex) {
192                 evalException = ex;
193                 throw ex;
194             } catch (RuntimeException ex) {
195                 evalException = ex;
196                 throw ex;
197             } finally {
198                 Evaluation      eval = context.popEvaluation();
199 
200                 eval.setResult(result);
201                 if (evalException != null) {
202                     eval.setException(evalException);
203                 }
204                 if ((evalException == null) && (context.getRootEvaluation() == null) && !context.getKeepLastEvaluation()) {
205                     pool.recycleAll(eval);
206                 }
207             }
208             return result;
209         } else {
210             return evaluateGetValueBody(context, source);
211         }
212     }
213 
214       /** Subclasses implement this method to do the actual work of extracting the
215           appropriate value from the source object. */
216     protected abstract Object getValueBody( OgnlContext context, Object source ) throws OgnlException;
217 
218     public final void setValue( OgnlContext context, Object target, Object value ) throws OgnlException
219     {
220         if (context.getTraceEvaluations()) {
221             EvaluationPool      pool = OgnlRuntime.getEvaluationPool();
222             Throwable           evalException = null;
223             Evaluation          evaluation = pool.create(this, target, true);
224 
225             context.pushEvaluation(evaluation);
226             try {
227                 evaluateSetValueBody(context, target, value);
228             } catch (OgnlException ex) {
229                 evalException = ex;
230                 ex.setEvaluation(evaluation);
231                 throw ex;
232             } catch (RuntimeException ex) {
233                 evalException = ex;
234                 throw ex;
235             } finally {
236                 Evaluation      eval = context.popEvaluation();
237 
238                 if (evalException != null) {
239                     eval.setException(evalException);
240                 }
241                 if ((evalException == null) && (context.getRootEvaluation() == null) && !context.getKeepLastEvaluation()) {
242                     pool.recycleAll(eval);
243                 }
244             }
245         } else {
246             evaluateSetValueBody(context, target, value);
247         }
248     }
249 
250     /** Subclasses implement this method to do the actual work of setting the
251         appropriate value in the target object.  The default implementation
252         throws an <code>InappropriateExpressionException</code>, meaning that it
253         cannot be a set expression.
254      */
255     protected void setValueBody( OgnlContext context, Object target, Object value ) throws OgnlException
256     {
257         throw new InappropriateExpressionException( this );
258     }
259 
260     /**
261         Returns true iff this node is constant without respect to the children.
262      */
263     public boolean isNodeConstant( OgnlContext context ) throws OgnlException
264     {
265         return false;
266     }
267 
268     public boolean isConstant( OgnlContext context ) throws OgnlException
269     {
270         return isNodeConstant(context);
271     }
272 
273     public boolean isNodeSimpleProperty( OgnlContext context ) throws OgnlException
274     {
275         return false;
276     }
277 
278     public boolean isSimpleProperty( OgnlContext context ) throws OgnlException
279     {
280         return isNodeSimpleProperty(context);
281     }
282 
283     public boolean isSimpleNavigationChain( OgnlContext context ) throws OgnlException
284     {
285         return isSimpleProperty(context);
286     }
287 
288       /** This method may be called from subclasses' jjtClose methods.  It flattens the
289           tree under this node by eliminating any children that are of the same class as
290           this node and copying their children to this node. */
291     protected void flattenTree()
292     {
293         boolean shouldFlatten = false;
294         int newSize = 0;
295 
296         for ( int i=0; i < children.length; ++i )
297             if ( children[i].getClass() == getClass() ) {
298                 shouldFlatten = true;
299                 newSize += children[i].jjtGetNumChildren();
300             }
301             else
302                 ++newSize;
303 
304         if ( shouldFlatten )
305           {
306             Node[] newChildren = new Node[newSize];
307             int j = 0;
308 
309             for ( int i=0; i < children.length; ++i ) {
310                 Node c = children[i];
311                 if ( c.getClass() == getClass() ) {
312                     for ( int k=0; k < c.jjtGetNumChildren(); ++k )
313                         newChildren[j++] = c.jjtGetChild(k);
314                 }
315                 else
316                     newChildren[j++] = c;
317             }
318 
319             if ( j != newSize )
320                 throw new Error( "Assertion error: " + j + " != " + newSize );
321 
322             this.children = newChildren;
323           }
324     }
325 }