Package net.xoetrope.xui.evaluator

Source Code of net.xoetrope.xui.evaluator.XDefaultAttributeEvaluator

package net.xoetrope.xui.evaluator;

import java.lang.reflect.Method;


import net.xoetrope.debug.DebugLogger;
import net.xoetrope.xui.PageSupport;
import net.xoetrope.xui.XPage;
import net.xoetrope.xui.XProject;
import net.xoetrope.xui.build.BuildProperties;
import net.xoetrope.xui.helper.XuiUtilities;
import java.util.Hashtable;
import net.xoetrope.xui.XMethodReference;
import net.xoetrope.xui.exception.XExceptionHandler;

/**
* An attribute evaluator
* <p>An evaluated attribute's implementing method is by default in the owner
* page such that a reference like</p>
* <code>${myMethod()}</code>
* <p>would evaluate to a method in the current page with a signature like:</p>
* <code>public void myMethod();</code>
* <p>The attributes can also be defined in classes other than the current page
* or classes derived from XPage. The syntax for such expressions is as follows:</p>
* <ul>
* <li>1. <code>${mypackage.MyClass[referenceName].myMethod(args...)}</code> for a named object instance</li>
* <li>2. <code>${mypackage.MyClass[].myMethod(args...)}</code> to create a new instance of the class on each evaluation</li>
* <li>3. <code>${mypackage.MyClass.myMethod(args...)}</code> to invoke a static method</li>
* <li>4. <code>${myMethod[referenceName](args...)}</code> for a method contained with the invoking page</li>
* <li>5. <code>${this[componentName].componentMethod(args...)}</code> for a method contained within named component</li>
* <li>6. <code>${this.method(args...)}</code> for a method contained within the enclosing page, identical to 4 above</li>
* <li>7. <code>${project.method(args...)}</code> for a method contained within the project</li>
* <li>8. <code>${comp.method(args...)}</code> for a method contained within the component</li>
// * <li>9. <code>${this}</code> for a reference to the page</li>
// * <li>10. <code>${comp}</code> for a reference to the component</li>
* </ul>
* <p>where mypackage is the name of the Java package containing the class MyClass.
* The value of referenceName is a user defined value that identifies the instance
* of the class. The application instantiates an instance of the class when
* the expression is first encountered and thereafter maintains the instance with
* each subsequent call retrieving the same instance of the class.</p>
* <p>The method call can contain zero or more arguments</p>
* <p> Copyright (c) Xoetrope Ltd., 2002-2004</p>
* <p> $Revision: 2.8 $</p>
* <p> License: see License.txt</p>
*/
public class XDefaultAttributeEvaluator implements XAttributeEvaluator
{
  /**
   * The collection of class instances that are known to implement the methods
   * of evaluated attributes
   */
  protected Hashtable classInstances;
 
  protected Object provider;

  protected XProject currentProject;
 
  protected XExceptionHandler exceptionHandler;
 
  protected Object result;

  /**
   * Create a new evaluator
   * @param currentProject the current project
   * @param project the current or owning project
   */
  public XDefaultAttributeEvaluator( XProject project )
  {
    currentProject = project;
  }
 
  /**
   * Set the current project and complete any initialization that depends on the
   * project reference/instance.
   * @param project the current or owning project
   */
  public void setCurrentProject( XProject project )
  {
    currentProject = project;
    classInstances = (Hashtable)currentProject.getObject( "UserClassReferences" );
    if ( classInstances == null ) {
      classInstances = new Hashtable( 5 );
      currentProject.setObject( "UserClassReferences", classInstances );
    }
  }
 
  /**
   * Set an exception handler for processing exceptions
   * @param eh the exception handler
   */
  public void setExceptionHandler( XExceptionHandler eh )
  {
    exceptionHandler = eh;
  }
 
  /**
   * Explicitly set the result of an evaluation. This method may be used
   * by an exception handler to override the result and set a sensible
   * value in case of an exception
   * @param the new result value
   */
  public void setResult( Object value )
  {
    result = value;
  }
 
  /**
   * Explicitly get the result of an evaluation. This method may be used
   * by an exception handler to determine the result and set a sensible
   * value in case of an exception
   * @return the current/intermediate result value
   */
  public Object getResult()
  {
    return result;
  }

  /**
   * Get the value of an attribute.
   * @param instance the page or instance that provides the methods/field for the evaluator
   * @param attributeValue the raw value of the attribute
   * @return the evaluated value of the attribute
   */
  public Object evaluateAttribute( Object instance, String attributeValue )
  {
    if ( attributeValue == null )
      return null;
   
    provider = instance;
    String resultStr = attributeValue;
    result = resultStr;
    try {
      int startPos = resultStr.indexOf( "${" );
      int len = resultStr.length();
      while ( startPos >= 0 ) {
        XMethodReference methodRef = getMethodReference( provider, resultStr );
        if ( methodRef == null ) {
          DebugLogger.logWarning( "Unable to evaluate attribute with the method call(?): " + result );
          return result;
        }
        int endPos = XuiUtilities.indexOfMatchingEnding( resultStr, '{', '}', startPos + 2 );
        Object methodValue = methodRef.method.invoke( methodRef.instance, methodRef.args );
        if (( startPos > 0 ) || ( endPos < ( len -1 ))) {
          String newStr = "";
          if ( startPos > 0 )
            newStr = resultStr.substring( 0, startPos );
          newStr += methodValue.toString();
          if ( ( endPos < ( len -1 )))
            newStr += resultStr.substring( endPos + 1 );
          result = resultStr = newStr;
          startPos = resultStr.indexOf( "${" );
        }
        else
          return methodValue;         
      }
    }
    catch ( Exception ex ) {
      if ( exceptionHandler != null ) {
        if ( exceptionHandler.handleException( provider, ex, this ))
          return result;
      }
      if ( BuildProperties.DEBUG ) {
        DebugLogger.logWarning( "Unable to evaluate attribute with the method call(?): " + attributeValue );
        Throwable t = ex.getCause();
        if ( t != null )
          t.printStackTrace();
        else
          ex.printStackTrace();
      }
    }
    return result;
  }
 
  /**
   * Get the method reference for the methods named in the attribute
   * @param attributeValue the method name
   * @return the method reference or null if the referenced/named method cannot be found
   */
  public XMethodReference getMethodReference( String attributeValue )
  {
    return getMethodReference( null, attributeValue );
  }
 
  /**
   * Get the value of an attribute by evaluating a method reference
   * @param instnace the page or object from that provides the methods or fields referenced in the evaluation
   * @param attributeValue the attribute to be evaluated
   */
  public XMethodReference getMethodReference( Object instance, String attributeValue )
  {
    try {
      int expPos = attributeValue.indexOf( "${" );
      if ( expPos >= 0 ) {
        Class[] params;
        int endAttribName = attributeValue.indexOf( '(' );
        int endAttribArgs = XuiUtilities.indexOfMatchingEnding( attributeValue, '(', ')', endAttribName + 1 );
       
        String methodName = attributeValue.substring( expPos + 2, endAttribName );       
        Object args[];

        // Check for an argumentless call
        if ( ( endAttribName + 1 ) == endAttribArgs ) {
          args = new Object[ 0 ];
          params = new Class[ 0 ];
        }
        else {
          String argValues = attributeValue.substring( endAttribName + 1, endAttribArgs );
          // Count the number of commas
          int numArgs = 1 + XuiUtilities.count( argValues, ',', '(', ')' );
          args = new Object[ numArgs ];
          params = new Class[ numArgs ];
          XuiUtilities.getArguments( argValues, params, args, ',', '(', ')' );
        }

        // Find the class that implements the method
        Class clazz = null;
        Object classInstance = null;
        int pos = methodName.lastIndexOf( '.' );
        if ( pos > 0 ) {
          String className = methodName.substring( 0, pos );
          methodName = methodName.substring( pos + 1 );

          // Check for the class instance type
          className = className.substring( 0, pos );         
          if (( pos = className.indexOf( "this[" )) == 0 ) {
            String componentName = className.substring( pos + 5, className.length() -1 ).trim();
            classInstance = ((PageSupport)instance).findComponent( componentName );
          }
          else if ( ( pos = className.indexOf( "[" ) ) >= 0 ) {
            String referenceName = className.substring( pos + 1, className.length() -1 ).trim();
            className = className.substring( 0, pos );
            if ( referenceName.length() > 0 ) {
              classInstance = classInstances.get( referenceName );
              if ( classInstance == null ) {
                clazz = XPage.class.forName( className.trim());
                classInstance = clazz.newInstance();
                classInstances.put( referenceName, classInstance );
              }
              else
                clazz = classInstance.getClass();
           
          }
          else if ( className.equals( "this" )) // This is provided purely for self consistency
            classInstance = instance;
          else if ( className.equals( "project" ))
            classInstance = currentProject;
          else {
            clazz = Class.forName( className.trim());
            classInstance = clazz.newInstance();         
          }
         
          if ( clazz == null )
            clazz = classInstance.getClass();
        }
        else if ( instance != null ) {
          clazz = instance.getClass();
          classInstance = instance;
        }

        // Find and invoke the method
        Method theMethod = clazz.getMethod( methodName, params );
        return new XMethodReference ( clazz, classInstance, theMethod, args );
      }
    }
    catch ( Exception ex ) {
      if ( BuildProperties.DEBUG )
        DebugLogger.logWarning( "Unable to evaluate attribute with the method call(?): " + attributeValue );
    }
    return null;
  }
 
  /**
   * Get the current provider object. In most cases this should correspond to the active
   * page at the time the evaluator was last used, but no guarantees can be provided
   * that multiple threads are not updating the value. The value should be retrieved
   * and cached as soon as the evaluated method is entered as other method calls
   * could have the side effect of reseting the value.
   * @return the current object used for evaluation of method and field references
   */
  public Object getObject()
  {
    return provider;
 
}
TOP

Related Classes of net.xoetrope.xui.evaluator.XDefaultAttributeEvaluator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.