View Javadoc

1   package org.apache.commons.ognl;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   * http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.commons.ognl.enhance.ExpressionCompiler;
23  import org.apache.commons.ognl.enhance.OrderedReturn;
24  import org.apache.commons.ognl.enhance.UnsupportedCompilationException;
25  
26  import java.lang.reflect.Array;
27  
28  /**
29   * $Id: ASTChain.java 1197011 2011-11-03 09:19:44Z mcucchiara $
30   * @author Luke Blanshard (blanshlu@netscape.net)
31   * @author Drew Davidson (drew@ognl.org)
32   */
33  public class ASTChain
34      extends SimpleNode
35      implements NodeType, OrderedReturn
36  {
37  
38      private Class getterClass;
39  
40      private Class setterClass;
41  
42      private String lastExpression;
43  
44      private String coreExpression;
45  
46      public ASTChain( int id )
47      {
48          super( id );
49      }
50  
51      public ASTChain( OgnlParser p, int id )
52      {
53          super( p, id );
54      }
55  
56      public String getLastExpression()
57      {
58          return lastExpression;
59      }
60  
61      public String getCoreExpression()
62      {
63          return coreExpression;
64      }
65  
66      public void jjtClose()
67      {
68          flattenTree();
69      }
70  
71      protected Object getValueBody( OgnlContext context, Object source )
72          throws OgnlException
73      {
74          Object result = source;
75  
76          for ( int i = 0, ilast = children.length - 1; i <= ilast; ++i )
77          {
78              boolean handled = false;
79  
80              if ( i < ilast )
81              {
82                  if ( children[i] instanceof ASTProperty )
83                  {
84                      ASTProperty propertyNode = (ASTProperty) children[i];
85                      int indexType = propertyNode.getIndexedPropertyType( context, result );
86  
87                      if ( ( indexType != OgnlRuntime.INDEXED_PROPERTY_NONE )
88                          && ( children[i + 1] instanceof ASTProperty ) )
89                      {
90                          ASTProperty indexNode = (ASTProperty) children[i + 1];
91  
92                          if ( indexNode.isIndexedAccess() )
93                          {
94                              Object index = indexNode.getProperty( context, result );
95  
96                              if ( index instanceof DynamicSubscript )
97                              {
98                                  if ( indexType == OgnlRuntime.INDEXED_PROPERTY_INT )
99                                  {
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 }