001    package org.apache.commons.ognl;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *   http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    /**
023     * An <code>Evaluation</code> is and object that holds a node being evaluated and the source from which that node will
024     * take extract its value. It refers to child evaluations that occur as a result of the nodes' evaluation.
025     */
026    public class Evaluation
027    {
028        private SimpleNode node;
029    
030        private Object source;
031    
032        private boolean setOperation;
033    
034        private Object result;
035    
036        private Throwable exception;
037    
038        private Evaluation parent;
039    
040        private Evaluation next;
041    
042        private Evaluation previous;
043    
044        private Evaluation firstChild;
045    
046        private Evaluation lastChild;
047    
048        /**
049         * Constructs a new "get" <code>Evaluation</code> from the node and source given.
050         */
051        public Evaluation( SimpleNode node, Object source )
052        {
053            super();
054            this.node = node;
055            this.source = source;
056        }
057    
058        /**
059         * Constructs a new <code>Evaluation</code> from the node and source given. If <code>setOperation</code> is true
060         * this <code>Evaluation</code> represents a "set" as opposed to a "get".
061         */
062        public Evaluation( SimpleNode node, Object source, boolean setOperation )
063        {
064            this( node, source );
065            this.setOperation = setOperation;
066        }
067    
068        /**
069         * Returns the <code>SimpleNode</code> for this <code>Evaluation</code>
070         */
071        public SimpleNode getNode()
072        {
073            return node;
074        }
075    
076        /**
077         * Sets the node of the evaluation. Normally applications do not need to set this. Notable exceptions to this rule
078         * are custom evaluators that choose between navigable objects (as in a multi-root evaluator where the navigable
079         * node is chosen at runtime).
080         */
081        public void setNode( SimpleNode value )
082        {
083            node = value;
084        }
085    
086        /**
087         * Returns the source object on which this Evaluation operated.
088         */
089        public Object getSource()
090        {
091            return source;
092        }
093    
094        /**
095         * Sets the source of the evaluation. Normally applications do not need to set this. Notable exceptions to this rule
096         * are custom evaluators that choose between navigable objects (as in a multi-root evaluator where the navigable
097         * node is chosen at runtime).
098         */
099        public void setSource( Object value )
100        {
101            source = value;
102        }
103    
104        /**
105         * Returns true if this Evaluation represents a set operation.
106         */
107        public boolean isSetOperation()
108        {
109            return setOperation;
110        }
111    
112        /**
113         * Marks the Evaluation as a set operation if the value is true, else marks it as a get operation.
114         */
115        public void setSetOperation( boolean value )
116        {
117            setOperation = value;
118        }
119    
120        /**
121         * Returns the result of the Evaluation, or null if it was a set operation.
122         */
123        public Object getResult()
124        {
125            return result;
126        }
127    
128        /**
129         * Sets the result of the Evaluation. This method is normally only used interally and should not be set without
130         * knowledge of what you are doing.
131         */
132        public void setResult( Object value )
133        {
134            result = value;
135        }
136    
137        /**
138         * Returns the exception that occurred as a result of evaluating the Evaluation, or null if no exception occurred.
139         */
140        public Throwable getException()
141        {
142            return exception;
143        }
144    
145        /**
146         * Sets the exception that occurred as a result of evaluating the Evaluation. This method is normally only used
147         * interally and should not be set without knowledge of what you are doing.
148         */
149        public void setException( Throwable value )
150        {
151            exception = value;
152        }
153    
154        /**
155         * Returns the parent evaluation of this evaluation. If this returns null then it is is the root evaluation of a
156         * tree.
157         */
158        public Evaluation getParent()
159        {
160            return parent;
161        }
162    
163        /**
164         * Returns the next sibling of this evaluation. Returns null if this is the last in a chain of evaluations.
165         */
166        public Evaluation getNext()
167        {
168            return next;
169        }
170    
171        /**
172         * Returns the previous sibling of this evaluation. Returns null if this is the first in a chain of evaluations.
173         */
174        public Evaluation getPrevious()
175        {
176            return previous;
177        }
178    
179        /**
180         * Returns the first child of this evaluation. Returns null if there are no children.
181         */
182        public Evaluation getFirstChild()
183        {
184            return firstChild;
185        }
186    
187        /**
188         * Returns the last child of this evaluation. Returns null if there are no children.
189         */
190        public Evaluation getLastChild()
191        {
192            return lastChild;
193        }
194    
195        /**
196         * Gets the first descendent. In any Evaluation tree this will the Evaluation that was first executed.
197         */
198        public Evaluation getFirstDescendant()
199        {
200            if ( firstChild != null )
201            {
202                return firstChild.getFirstDescendant();
203            }
204            return this;
205        }
206    
207        /**
208         * Gets the last descendent. In any Evaluation tree this will the Evaluation that was most recently executing.
209         */
210        public Evaluation getLastDescendant()
211        {
212            if ( lastChild != null )
213            {
214                return lastChild.getLastDescendant();
215            }
216            return this;
217        }
218    
219        /**
220         * Adds a child to the list of children of this evaluation. The parent of the child is set to the receiver and the
221         * children references are modified in the receiver to reflect the new child. The lastChild of the receiver is set
222         * to the child, and the firstChild is set also if child is the first (or only) child.
223         */
224        public void addChild( Evaluation child )
225        {
226            if ( firstChild == null )
227            {
228                firstChild = child;
229                lastChild = child;
230            }
231            else
232            {
233                if ( firstChild == lastChild )
234                {
235                    firstChild.next = child;
236                    lastChild = child;
237                    lastChild.previous = firstChild;
238                }
239                else
240                {
241                    child.previous = lastChild;
242                    lastChild.next = child;
243                    lastChild = child;
244                }
245            }
246            child.parent = this;
247        }
248    
249        /**
250         * Reinitializes this Evaluation to the parameters specified.
251         */
252        public void init( SimpleNode node, Object source, boolean setOperation )
253        {
254            this.node = node;
255            this.source = source;
256            this.setOperation = setOperation;
257            result = null;
258            exception = null;
259            parent = null;
260            next = null;
261            previous = null;
262            firstChild = null;
263            lastChild = null;
264        }
265    
266        /**
267         * Resets this Evaluation to the initial state.
268         */
269        public void reset()
270        {
271            init( null, null, false );
272        }
273    
274        /**
275         * Produces a String value for the Evaluation. If compact is true then a more compact form of the description only
276         * including the node type and unique identifier is shown, else a full description including source and result are
277         * shown. If showChildren is true the child evaluations are printed using the depth string given as a prefix.
278         */
279        public String toString( boolean compact, boolean showChildren, String depth )
280        {
281            String stringResult;
282    
283            if ( compact )
284            {
285                stringResult = depth + "<" + node.getClass().getName() + " " + System.identityHashCode( this ) + ">";
286            }
287            else
288            {
289                String ss = ( source != null ) ? source.getClass().getName() : "null", rs =
290                    ( result != null ) ? result.getClass().getName() : "null";
291    
292                stringResult =
293                    depth + "<" + node.getClass().getName() + ": [" + ( setOperation ? "set" : "get" ) + "] source = " + ss
294                        + ", result = " + result + " [" + rs + "]>";
295            }
296            if ( showChildren )
297            {
298                Evaluation child = firstChild;
299    
300                stringResult += "\n";
301                while ( child != null )
302                {
303                    stringResult += child.toString( compact, depth + "  " );
304                    child = child.next;
305                }
306            }
307            return stringResult;
308        }
309    
310        /**
311         * Produces a String value for the Evaluation. If compact is true then a more compact form of the description only
312         * including the node type and unique identifier is shown, else a full description including source and result are
313         * shown. Child evaluations are printed using the depth string given as a prefix.
314         */
315        public String toString( boolean compact, String depth )
316        {
317            return toString( compact, true, depth );
318        }
319    
320        /**
321         * Returns a String description of the Evaluation.
322         */
323        @Override
324        public String toString()
325        {
326            return toString( false, "" );
327        }
328    }