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    import org.apache.commons.ognl.enhance.ExpressionCompiler;
023    import org.apache.commons.ognl.enhance.OrderedReturn;
024    import org.apache.commons.ognl.enhance.UnsupportedCompilationException;
025    
026    import java.lang.reflect.Array;
027    
028    /**
029     * $Id: ASTChain.java 1197011 2011-11-03 09:19:44Z mcucchiara $
030     * @author Luke Blanshard (blanshlu@netscape.net)
031     * @author Drew Davidson (drew@ognl.org)
032     */
033    public class ASTChain
034        extends SimpleNode
035        implements NodeType, OrderedReturn
036    {
037    
038        private Class getterClass;
039    
040        private Class setterClass;
041    
042        private String lastExpression;
043    
044        private String coreExpression;
045    
046        public ASTChain( int id )
047        {
048            super( id );
049        }
050    
051        public ASTChain( OgnlParser p, int id )
052        {
053            super( p, id );
054        }
055    
056        public String getLastExpression()
057        {
058            return lastExpression;
059        }
060    
061        public String getCoreExpression()
062        {
063            return coreExpression;
064        }
065    
066        public void jjtClose()
067        {
068            flattenTree();
069        }
070    
071        protected Object getValueBody( OgnlContext context, Object source )
072            throws OgnlException
073        {
074            Object result = source;
075    
076            for ( int i = 0, ilast = children.length - 1; i <= ilast; ++i )
077            {
078                boolean handled = false;
079    
080                if ( i < ilast )
081                {
082                    if ( children[i] instanceof ASTProperty )
083                    {
084                        ASTProperty propertyNode = (ASTProperty) children[i];
085                        int indexType = propertyNode.getIndexedPropertyType( context, result );
086    
087                        if ( ( indexType != OgnlRuntime.INDEXED_PROPERTY_NONE )
088                            && ( children[i + 1] instanceof ASTProperty ) )
089                        {
090                            ASTProperty indexNode = (ASTProperty) children[i + 1];
091    
092                            if ( indexNode.isIndexedAccess() )
093                            {
094                                Object index = indexNode.getProperty( context, result );
095    
096                                if ( index instanceof DynamicSubscript )
097                                {
098                                    if ( indexType == OgnlRuntime.INDEXED_PROPERTY_INT )
099                                    {
100                                        Object array = propertyNode.getValue( context, result );
101                                        int len = Array.getLength( array );
102    
103                                        switch ( ( (DynamicSubscript) index ).getFlag() )
104                                        {
105                                            case DynamicSubscript.ALL:
106                                                result = Array.newInstance( array.getClass().getComponentType(), len );
107                                                System.arraycopy( array, 0, result, 0, len );
108                                                handled = true;
109                                                i++;
110                                                break;
111                                            case DynamicSubscript.FIRST:
112                                                index = ( len > 0 ) ? 0 : -1;
113                                                break;
114                                            case DynamicSubscript.MID:
115                                                index = ( len > 0 ) ? ( len / 2 ) : -1;
116                                                break;
117                                            case DynamicSubscript.LAST:
118                                                index = ( len > 0 ) ? ( len - 1 ) : -1;
119                                                break;
120                                            default:
121                                                break;
122                                        }
123                                    }
124                                    else
125                                    {
126                                        if ( indexType == OgnlRuntime.INDEXED_PROPERTY_OBJECT )
127                                        {
128                                            throw new OgnlException( "DynamicSubscript '" + indexNode
129                                                + "' not allowed for object indexed property '" + propertyNode + "'" );
130                                        }
131                                    }
132                                }
133                                if ( !handled )
134                                {
135                                    result =
136                                        OgnlRuntime.getIndexedProperty( 
137                                            context,
138                                            result,
139                                            propertyNode.getProperty( context, result ).toString(),
140                                            index );
141                                    handled = true;
142                                    i++;
143                                }
144                            }
145                        }
146                    }
147                }
148                if ( !handled )
149                {
150                    result = children[i].getValue( context, result );
151                }
152            }
153            return result;
154        }
155    
156        protected void setValueBody( OgnlContext context, Object target, Object value )
157            throws OgnlException
158        {
159            boolean handled = false;
160    
161            for ( int i = 0, ilast = children.length - 2; i <= ilast; ++i )
162            {
163                if ( i <= ilast )
164                {
165                    if ( children[i] instanceof ASTProperty )
166                    {
167                        ASTProperty propertyNode = (ASTProperty) children[i];
168                        int indexType = propertyNode.getIndexedPropertyType( context, target );
169    
170                        if ( ( indexType != OgnlRuntime.INDEXED_PROPERTY_NONE )
171                            && ( children[i + 1] instanceof ASTProperty ) )
172                        {
173                            ASTProperty indexNode = (ASTProperty) children[i + 1];
174    
175                            if ( indexNode.isIndexedAccess() )
176                            {
177                                Object index = indexNode.getProperty( context, target );
178    
179                                if ( index instanceof DynamicSubscript )
180                                {
181                                    if ( indexType == OgnlRuntime.INDEXED_PROPERTY_INT )
182                                    {
183                                        Object array = propertyNode.getValue( context, target );
184                                        int len = Array.getLength( array );
185    
186                                        switch ( ( (DynamicSubscript) index ).getFlag() )
187                                        {
188                                            case DynamicSubscript.ALL:
189                                                System.arraycopy( target, 0, value, 0, len );
190                                                handled = true;
191                                                i++;
192                                                break;
193                                            case DynamicSubscript.FIRST:
194                                                index = ( len > 0 ) ? 0 : -1;
195                                                break;
196                                            case DynamicSubscript.MID:
197                                                index = ( len > 0 ) ? ( len / 2 ) : -1;
198                                                break;
199                                            case DynamicSubscript.LAST:
200                                                index = ( len > 0 ) ? ( len - 1 ) : -1;
201                                                break;
202                                            default:
203                                                break;
204                                        }
205                                    }
206                                    else
207                                    {
208                                        if ( indexType == OgnlRuntime.INDEXED_PROPERTY_OBJECT )
209                                        {
210                                            throw new OgnlException( "DynamicSubscript '" + indexNode
211                                                + "' not allowed for object indexed property '" + propertyNode + "'" );
212                                        }
213                                    }
214                                }
215                                if ( !handled && i == ilast )
216                                {
217                                    OgnlRuntime.setIndexedProperty( context, target,
218                                                                    propertyNode.getProperty( context, target ).toString(),
219                                                                    index, value );
220                                    handled = true;
221                                    i++;
222                                }
223                                else if ( !handled )
224                                {
225                                    target =
226                                        OgnlRuntime.getIndexedProperty( 
227                                            context,
228                                            target,
229                                            propertyNode.getProperty( context, target ).toString(),
230                                            index );
231                                    i++;
232                                    continue;
233                                }
234                            }
235                        }
236                    }
237                }
238                if ( !handled )
239                {
240                    target = children[i].getValue( context, target );
241                }
242            }
243            if ( !handled )
244            {
245                children[children.length - 1].setValue( context, target, value );
246            }
247        }
248    
249        public boolean isSimpleNavigationChain( OgnlContext context )
250            throws OgnlException
251        {
252            boolean result = false;
253    
254            if ( ( children != null ) && ( children.length > 0 ) )
255            {
256                result = true;
257                for ( int i = 0; result && ( i < children.length ); i++ )
258                {
259                    result =
260                        children[i] instanceof SimpleNode && ( (SimpleNode) children[i] ).isSimpleProperty( context );
261                }
262            }
263            return result;
264        }
265    
266        public Class getGetterClass()
267        {
268            return getterClass;
269        }
270    
271        public Class getSetterClass()
272        {
273            return setterClass;
274        }
275    
276        public String toGetSourceString( OgnlContext context, Object target )
277        {
278            String prevChain = (String) context.get( "_currentChain" );
279    
280            if ( target != null )
281            {
282                context.setCurrentObject( target );
283                context.setCurrentType( target.getClass() );
284            }
285    
286            String result = "";
287            NodeType lastType = null;
288            boolean ordered = false;
289            boolean constructor = false;
290            try
291            {
292                if ( ( children != null ) && ( children.length > 0 ) )
293                {
294                    for ( Node child : children )
295                    {
296                        /*
297                         * System.out.println("astchain child: " + _children[i].getClass().getName() +
298                         * " with current object target " + context.getCurrentObject() + " current type: " +
299                         * context.getCurrentType());
300                         */
301    
302                        String value = child.toGetSourceString( context, context.getCurrentObject() );
303    
304                        // System.out.println("astchain child returned >>  " + value + "  <<");
305    
306                        if ( ASTCtor.class.isInstance( child ) )
307                        {
308                            constructor = true;
309                        }
310    
311                        if ( NodeType.class.isInstance( child ) && ( (NodeType) child ).getGetterClass() != null )
312                        {
313                            lastType = (NodeType) child;
314                        }
315    
316                        // System.out.println("Astchain i: " + i + " currentobj : " + context.getCurrentObject() +
317                        // " and root: " + context.getRoot());
318                        if ( !ASTVarRef.class.isInstance( child ) && !constructor && !(
319                            OrderedReturn.class.isInstance( child )
320                                && ( (OrderedReturn) child ).getLastExpression() != null ) && ( parent == null
321                            || !ASTSequence.class.isInstance( parent ) ) )
322                        {
323                            value = OgnlRuntime.getCompiler( context ).castExpression( context, child, value );
324                        }
325    
326                        /*
327                         * System.out.println("astchain value now : " + value + " with index " + i + " current type " +
328                         * context.getCurrentType() + " current accessor " + context.getCurrentAccessor() + " prev type " +
329                         * context.getPreviousType() + " prev accessor " + context.getPreviousAccessor());
330                         */
331    
332                        if ( OrderedReturn.class.isInstance( child )
333                            && ( (OrderedReturn) child ).getLastExpression() != null )
334                        {
335                            ordered = true;
336                            OrderedReturn or = (OrderedReturn) child;
337    
338                            if ( or.getCoreExpression() == null || or.getCoreExpression().trim().length() <= 0 )
339                            {
340                                result = "";
341                            }
342                            else
343                            {
344                                result += or.getCoreExpression();
345                            }
346    
347                            lastExpression = or.getLastExpression();
348    
349                            if ( context.get( ExpressionCompiler.PRE_CAST ) != null )
350                            {
351                                lastExpression = context.remove( ExpressionCompiler.PRE_CAST ) + lastExpression;
352                            }
353                        }
354                        else if ( ASTOr.class.isInstance( child ) || ASTAnd.class.isInstance( child )
355                            || ASTCtor.class.isInstance( child ) || ( ASTStaticField.class.isInstance( child )
356                            && parent == null ) )
357                        {
358                            context.put( "_noRoot", "true" );
359                            result = value;
360                        }
361                        else
362                        {
363                            result += value;
364                        }
365    
366                        context.put( "_currentChain", result );
367                    }
368                }
369            }
370            catch ( Throwable t )
371            {
372                throw OgnlOps.castToRuntime( t );
373            }
374    
375            if ( lastType != null )
376            {
377                getterClass = lastType.getGetterClass();
378                setterClass = lastType.getSetterClass();
379            }
380    
381            if ( ordered )
382            {
383                coreExpression = result;
384            }
385    
386            context.put( "_currentChain", prevChain );
387    
388            return result;
389        }
390    
391        public String toSetSourceString( OgnlContext context, Object target )
392        {
393            String prevChain = (String) context.get( "_currentChain" );
394            String prevChild = (String) context.get( "_lastChild" );
395    
396            if ( prevChain != null )
397            {
398                throw new UnsupportedCompilationException( "Can't compile nested chain expressions." );
399            }
400            
401            if ( target != null )
402            {
403                context.setCurrentObject( target );
404                context.setCurrentType( target.getClass() );
405            }
406    
407            String result = "";
408            NodeType lastType = null;
409            boolean constructor = false;
410            try
411            {
412                if ( ( children != null ) && ( children.length > 0 ) )
413                {
414                    if ( ASTConst.class.isInstance( children[0] ) )
415                    {
416                        throw new UnsupportedCompilationException( "Can't modify constant values." );
417                    }
418    
419                    for ( int i = 0; i < children.length; i++ )
420                    {
421                        // System.out.println("astchain setsource child[" + i + "] : " + _children[i].getClass().getName());
422    
423                        if ( i == ( children.length - 1 ) )
424                        {
425                            context.put( "_lastChild", "true" );
426                        }
427    
428                        String value = children[i].toSetSourceString( context, context.getCurrentObject() );
429                        // if (value == null || value.trim().length() <= 0)
430                        // return "";
431    
432                        // System.out.println("astchain setter child returned >>  " + value + "  <<");
433    
434                        if ( ASTCtor.class.isInstance( children[i] ) )
435                        {
436                            constructor = true;
437                        }
438                        
439                        if ( NodeType.class.isInstance( children[i] )
440                            && ( (NodeType) children[i] ).getGetterClass() != null )
441                        {
442                            lastType = (NodeType) children[i];
443                        }
444    
445                        if ( !ASTVarRef.class.isInstance( children[i] )
446                            && !constructor
447                            && !( OrderedReturn.class.isInstance( children[i] )
448                            && ( (OrderedReturn) children[i] ).getLastExpression() != null )
449                            && ( parent == null || !ASTSequence.class.isInstance( parent ) ) )
450                        {
451                            value = OgnlRuntime.getCompiler( context ).castExpression( context, children[i], value );
452                        }
453    
454                        // System.out.println("astchain setter after cast value is: " + value);
455    
456                        /*
457                         * if (!constructor && !OrderedReturn.class.isInstance(_children[i]) && (_parent == null ||
458                         * !ASTSequence.class.isInstance(_parent))) { value =
459                         * OgnlRuntime.getCompiler().castExpression(context, _children[i], value); }
460                         */
461    
462                        if ( ASTOr.class.isInstance( children[i] ) || ASTAnd.class.isInstance( children[i] )
463                            || ASTCtor.class.isInstance( children[i] ) || ASTStaticField.class.isInstance( children[i] ) )
464                        {
465                            context.put( "_noRoot", "true" );
466                            result = value;
467                        }
468                        else
469                        {
470                            result += value;
471                        }
472                        
473                        context.put( "_currentChain", result );
474                    }
475                }
476            }
477            catch ( Throwable t )
478            {
479                throw OgnlOps.castToRuntime( t );
480            }
481    
482            context.put( "_lastChild", prevChild );
483            context.put( "_currentChain", prevChain );
484    
485            if ( lastType != null )
486            {
487                setterClass = lastType.getSetterClass();
488            }
489            
490            return result;
491        }
492        
493        public <R, P> R accept( NodeVisitor<? extends R, ? super P> visitor, P data )
494            throws OgnlException
495        {
496            return visitor.visit( this, data );
497        }
498    }