blob: 8ca6e3c16f205124c813d891e3f6f49e48d8d53f [file] [log] [blame]
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 );
}
}