| package org.apache.commons.ognl; |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import org.apache.commons.ognl.enhance.ExpressionCompiler; |
| import org.apache.commons.ognl.enhance.OrderedReturn; |
| import org.apache.commons.ognl.enhance.UnsupportedCompilationException; |
| |
| import java.lang.reflect.Array; |
| |
| /** |
| * $Id$ |
| */ |
| public class ASTChain |
| extends SimpleNode |
| implements NodeType, OrderedReturn |
| { |
| |
| private Class getterClass; |
| |
| private Class setterClass; |
| |
| private String lastExpression; |
| |
| private String coreExpression; |
| |
| public ASTChain( int id ) |
| { |
| super( id ); |
| } |
| |
| public ASTChain( OgnlParser p, int id ) |
| { |
| super( p, id ); |
| } |
| |
| public String getLastExpression() |
| { |
| return lastExpression; |
| } |
| |
| public String getCoreExpression() |
| { |
| return coreExpression; |
| } |
| |
| public void jjtClose() |
| { |
| flattenTree(); |
| } |
| |
| protected Object getValueBody( OgnlContext context, Object source ) |
| throws OgnlException |
| { |
| Object result = source; |
| |
| for ( int i = 0, ilast = children.length - 1; i <= ilast; ++i ) |
| { |
| boolean handled = false; |
| |
| if ( (i < ilast) && (children[i] instanceof ASTProperty) ) |
| { |
| ASTProperty propertyNode = (ASTProperty) children[i]; |
| int indexType = propertyNode.getIndexedPropertyType( context, result ); |
| |
| if ( ( indexType != OgnlRuntime.INDEXED_PROPERTY_NONE ) |
| && ( children[i + 1] instanceof ASTProperty ) ) |
| { |
| ASTProperty indexNode = (ASTProperty) children[i + 1]; |
| |
| if ( indexNode.isIndexedAccess() ) |
| { |
| Object index = indexNode.getProperty( context, result ); |
| |
| if ( index instanceof DynamicSubscript ) |
| { |
| if ( indexType == OgnlRuntime.INDEXED_PROPERTY_INT ) |
| { |
| Object array = propertyNode.getValue( context, result ); |
| int len = Array.getLength( array ); |
| |
| switch ( ( (DynamicSubscript) index ).getFlag() ) |
| { |
| case DynamicSubscript.ALL: |
| result = Array.newInstance( array.getClass().getComponentType(), len ); |
| System.arraycopy( array, 0, result, 0, len ); |
| handled = true; |
| i++; |
| break; |
| case DynamicSubscript.FIRST: |
| index = ( len > 0 ) ? 0 : -1; |
| break; |
| case DynamicSubscript.MID: |
| index = ( len > 0 ) ? ( len / 2 ) : -1; |
| break; |
| case DynamicSubscript.LAST: |
| index = ( len > 0 ) ? ( len - 1 ) : -1; |
| break; |
| default: |
| break; |
| } |
| } |
| else |
| { |
| if ( indexType == OgnlRuntime.INDEXED_PROPERTY_OBJECT ) |
| { |
| throw new OgnlException( "DynamicSubscript '" + indexNode |
| + "' not allowed for object indexed property '" + propertyNode + "'" ); |
| } |
| } |
| } |
| if ( !handled ) |
| { |
| result = |
| OgnlRuntime.getIndexedProperty( |
| context, |
| result, |
| propertyNode.getProperty( context, result ).toString(), |
| index ); |
| handled = true; |
| i++; |
| } |
| } |
| } |
| } |
| if ( !handled ) |
| { |
| result = children[i].getValue( context, result ); |
| } |
| } |
| return result; |
| } |
| |
| protected void setValueBody( OgnlContext context, Object target, Object value ) |
| throws OgnlException |
| { |
| boolean handled = false; |
| |
| for ( int i = 0, ilast = children.length - 2; i <= ilast; ++i ) |
| { |
| if ( (i <= ilast) && (children[i] instanceof ASTProperty) ) |
| { |
| ASTProperty propertyNode = (ASTProperty) children[i]; |
| int indexType = propertyNode.getIndexedPropertyType( context, target ); |
| |
| if ( ( indexType != OgnlRuntime.INDEXED_PROPERTY_NONE ) |
| && ( children[i + 1] instanceof ASTProperty ) ) |
| { |
| ASTProperty indexNode = (ASTProperty) children[i + 1]; |
| |
| if ( indexNode.isIndexedAccess() ) |
| { |
| Object index = indexNode.getProperty( context, target ); |
| |
| if ( index instanceof DynamicSubscript ) |
| { |
| if ( indexType == OgnlRuntime.INDEXED_PROPERTY_INT ) |
| { |
| Object array = propertyNode.getValue( context, target ); |
| int len = Array.getLength( array ); |
| |
| switch ( ( (DynamicSubscript) index ).getFlag() ) |
| { |
| case DynamicSubscript.ALL: |
| System.arraycopy( target, 0, value, 0, len ); |
| handled = true; |
| i++; |
| break; |
| case DynamicSubscript.FIRST: |
| index = ( len > 0 ) ? 0 : -1; |
| break; |
| case DynamicSubscript.MID: |
| index = ( len > 0 ) ? ( len / 2 ) : -1; |
| break; |
| case DynamicSubscript.LAST: |
| index = ( len > 0 ) ? ( len - 1 ) : -1; |
| break; |
| default: |
| break; |
| } |
| } |
| else |
| { |
| if ( indexType == OgnlRuntime.INDEXED_PROPERTY_OBJECT ) |
| { |
| throw new OgnlException( "DynamicSubscript '" + indexNode |
| + "' not allowed for object indexed property '" + propertyNode + "'" ); |
| } |
| } |
| } |
| if ( !handled && i == ilast ) |
| { |
| OgnlRuntime.setIndexedProperty( context, target, |
| propertyNode.getProperty( context, target ).toString(), |
| index, value ); |
| handled = true; |
| i++; |
| } |
| else if ( !handled ) |
| { |
| target = |
| OgnlRuntime.getIndexedProperty( |
| context, |
| target, |
| propertyNode.getProperty( context, target ).toString(), |
| index ); |
| i++; |
| continue; |
| } |
| } |
| } |
| } |
| if ( !handled ) |
| { |
| target = children[i].getValue( context, target ); |
| } |
| } |
| if ( !handled ) |
| { |
| children[children.length - 1].setValue( context, target, value ); |
| } |
| } |
| |
| public boolean isSimpleNavigationChain( OgnlContext context ) |
| throws OgnlException |
| { |
| boolean result = false; |
| |
| if ( ( children != null ) && ( children.length > 0 ) ) |
| { |
| result = true; |
| for ( int i = 0; result && ( i < children.length ); i++ ) |
| { |
| result = |
| children[i] instanceof SimpleNode && ( (SimpleNode) children[i] ).isSimpleProperty( context ); |
| } |
| } |
| return result; |
| } |
| |
| public Class getGetterClass() |
| { |
| return getterClass; |
| } |
| |
| public Class getSetterClass() |
| { |
| return setterClass; |
| } |
| |
| public String toGetSourceString( OgnlContext context, Object target ) |
| { |
| String prevChain = (String) context.get( "_currentChain" ); |
| |
| if ( target != null ) |
| { |
| context.setCurrentObject( target ); |
| context.setCurrentType( target.getClass() ); |
| } |
| |
| String result = ""; |
| NodeType lastType = null; |
| boolean ordered = false; |
| boolean constructor = false; |
| try |
| { |
| if ( ( children != null ) && ( children.length > 0 ) ) |
| { |
| for ( Node child : children ) |
| { |
| /* |
| * System.out.println("astchain child: " + _children[i].getClass().getName() + |
| * " with current object target " + context.getCurrentObject() + " current type: " + |
| * context.getCurrentType()); |
| */ |
| |
| String value = child.toGetSourceString( context, context.getCurrentObject() ); |
| |
| // System.out.println("astchain child returned >> " + value + " <<"); |
| |
| if ( ASTCtor.class.isInstance( child ) ) |
| { |
| constructor = true; |
| } |
| |
| if ( NodeType.class.isInstance( child ) && ( (NodeType) child ).getGetterClass() != null ) |
| { |
| lastType = (NodeType) child; |
| } |
| |
| // System.out.println("Astchain i: " + i + " currentobj : " + context.getCurrentObject() + |
| // " and root: " + context.getRoot()); |
| if ( !ASTVarRef.class.isInstance( child ) && !constructor && !( |
| OrderedReturn.class.isInstance( child ) |
| && ( (OrderedReturn) child ).getLastExpression() != null ) && ( parent == null |
| || !ASTSequence.class.isInstance( parent ) ) ) |
| { |
| value = OgnlRuntime.getCompiler( context ).castExpression( context, child, value ); |
| } |
| |
| /* |
| * System.out.println("astchain value now : " + value + " with index " + i + " current type " + |
| * context.getCurrentType() + " current accessor " + context.getCurrentAccessor() + " prev type " + |
| * context.getPreviousType() + " prev accessor " + context.getPreviousAccessor()); |
| */ |
| |
| if ( OrderedReturn.class.isInstance( child ) |
| && ( (OrderedReturn) child ).getLastExpression() != null ) |
| { |
| ordered = true; |
| OrderedReturn or = (OrderedReturn) child; |
| |
| if ( or.getCoreExpression() == null || or.getCoreExpression().trim().isEmpty() ) |
| { |
| result = ""; |
| } |
| else |
| { |
| result += or.getCoreExpression(); |
| } |
| |
| lastExpression = or.getLastExpression(); |
| |
| if ( context.get( ExpressionCompiler.PRE_CAST ) != null ) |
| { |
| lastExpression = context.remove( ExpressionCompiler.PRE_CAST ) + lastExpression; |
| } |
| } |
| else if ( ASTOr.class.isInstance( child ) || ASTAnd.class.isInstance( child ) |
| || ASTCtor.class.isInstance( child ) || ( ASTStaticField.class.isInstance( child ) |
| && parent == null ) ) |
| { |
| context.put( "_noRoot", "true" ); |
| result = value; |
| } |
| else |
| { |
| result += value; |
| } |
| |
| context.put( "_currentChain", result ); |
| } |
| } |
| } |
| catch ( Throwable t ) |
| { |
| throw OgnlOps.castToRuntime( t ); |
| } |
| |
| if ( lastType != null ) |
| { |
| getterClass = lastType.getGetterClass(); |
| setterClass = lastType.getSetterClass(); |
| } |
| |
| if ( ordered ) |
| { |
| coreExpression = result; |
| } |
| |
| context.put( "_currentChain", prevChain ); |
| |
| return result; |
| } |
| |
| public String toSetSourceString( OgnlContext context, Object target ) |
| { |
| String prevChain = (String) context.get( "_currentChain" ); |
| String prevChild = (String) context.get( "_lastChild" ); |
| |
| if ( prevChain != null ) |
| { |
| throw new UnsupportedCompilationException( "Can't compile nested chain expressions." ); |
| } |
| |
| if ( target != null ) |
| { |
| context.setCurrentObject( target ); |
| context.setCurrentType( target.getClass() ); |
| } |
| |
| String result = ""; |
| NodeType lastType = null; |
| boolean constructor = false; |
| try |
| { |
| if ( ( children != null ) && ( children.length > 0 ) ) |
| { |
| if ( ASTConst.class.isInstance( children[0] ) ) |
| { |
| throw new UnsupportedCompilationException( "Can't modify constant values." ); |
| } |
| |
| for ( int i = 0; i < children.length; i++ ) |
| { |
| // System.out.println("astchain setsource child[" + i + "] : " + _children[i].getClass().getName()); |
| |
| if ( i == ( children.length - 1 ) ) |
| { |
| context.put( "_lastChild", "true" ); |
| } |
| |
| String value = children[i].toSetSourceString( context, context.getCurrentObject() ); |
| // if (value == null || value.trim().isEmpty()) |
| // return ""; |
| |
| // System.out.println("astchain setter child returned >> " + value + " <<"); |
| |
| if ( ASTCtor.class.isInstance( children[i] ) ) |
| { |
| constructor = true; |
| } |
| |
| if ( NodeType.class.isInstance( children[i] ) |
| && ( (NodeType) children[i] ).getGetterClass() != null ) |
| { |
| lastType = (NodeType) children[i]; |
| } |
| |
| if ( !ASTVarRef.class.isInstance( children[i] ) |
| && !constructor |
| && !( OrderedReturn.class.isInstance( children[i] ) |
| && ( (OrderedReturn) children[i] ).getLastExpression() != null ) |
| && ( parent == null || !ASTSequence.class.isInstance( parent ) ) ) |
| { |
| value = OgnlRuntime.getCompiler( context ).castExpression( context, children[i], value ); |
| } |
| |
| // System.out.println("astchain setter after cast value is: " + value); |
| |
| /* |
| * if (!constructor && !OrderedReturn.class.isInstance(_children[i]) && (_parent == null || |
| * !ASTSequence.class.isInstance(_parent))) { value = |
| * OgnlRuntime.getCompiler().castExpression(context, _children[i], value); } |
| */ |
| |
| if ( ASTOr.class.isInstance( children[i] ) || ASTAnd.class.isInstance( children[i] ) |
| || ASTCtor.class.isInstance( children[i] ) || ASTStaticField.class.isInstance( children[i] ) ) |
| { |
| context.put( "_noRoot", "true" ); |
| result = value; |
| } |
| else |
| { |
| result += value; |
| } |
| |
| context.put( "_currentChain", result ); |
| } |
| } |
| } |
| catch ( Throwable t ) |
| { |
| throw OgnlOps.castToRuntime( t ); |
| } |
| |
| context.put( "_lastChild", prevChild ); |
| context.put( "_currentChain", prevChain ); |
| |
| if ( lastType != null ) |
| { |
| setterClass = lastType.getSetterClass(); |
| } |
| |
| return result; |
| } |
| |
| public <R, P> R accept( NodeVisitor<? extends R, ? super P> visitor, P data ) |
| throws OgnlException |
| { |
| return visitor.visit( this, data ); |
| } |
| } |