Esempio n. 1
0
  /**
   * @param context
   * @param variable
   * @return The evaluated value of the variable.
   * @throws MethodInvocationException
   */
  public Object getVariableValue(Context context, String variable)
      throws MethodInvocationException {
    Object obj = null;
    try {
      obj = context.get(variable);
    } catch (RuntimeException e) {
      log.error(
          "Exception calling reference $" + variable + " at " + Log.formatFileString(uberInfo));
      throw e;
    }

    if (strictRef && obj == null) {
      if (!context.containsKey(variable)) {
        log.error(
            "Variable $" + variable + " has not been set at " + Log.formatFileString(uberInfo));
        throw new MethodInvocationException(
            "Variable $" + variable + " has not been set",
            null,
            identifier,
            uberInfo.getTemplateName(),
            uberInfo.getLine(),
            uberInfo.getColumn());
      }
    }
    return obj;
  }
Esempio n. 2
0
  /**
   * Sets the value of a complex reference (something like $foo.bar) Currently used by
   * ASTSetReference()
   *
   * @see ASTSetDirective
   * @param context context object containing this reference
   * @param value Object to set as value
   * @return true if successful, false otherwise
   * @throws MethodInvocationException
   */
  public boolean setValue(InternalContextAdapter context, Object value)
      throws MethodInvocationException {
    if (jjtGetNumChildren() == 0) {
      context.put(rootString, value);
      return true;
    }

    /*
     *  The rootOfIntrospection is the object we will
     *  retrieve from the Context. This is the base
     *  object we will apply reflection to.
     */

    Object result = getVariableValue(context, rootString);

    if (result == null) {
      String msg = "reference set is not a valid reference at " + Log.formatFileString(uberInfo);
      log.error(msg);
      return false;
    }

    /*
     * How many child nodes do we have?
     */

    for (int i = 0; i < numChildren - 1; i++) {
      result = jjtGetChild(i).execute(result, context);

      if (result == null) {
        if (strictRef) {
          String name = jjtGetChild(i + 1).getFirstToken().image;
          throw new MethodInvocationException(
              "Attempted to access '" + name + "' on a null value",
              null,
              name,
              uberInfo.getTemplateName(),
              jjtGetChild(i + 1).getLine(),
              jjtGetChild(i + 1).getColumn());
        }

        String msg = "reference set is not a valid reference at " + Log.formatFileString(uberInfo);
        log.error(msg);

        return false;
      }
    }

    if (astIndex != null) {
      // If astIndex is not null then we are actually setting an index reference,
      // something of the form $foo[1] =, or in general any reference that ends with
      // the brackets.  This means that we need to call a more general method
      // of the form set(Integer, <something>), or put(Object, <something), where
      // the first parameter is the index value and the second is the LHS of the set.

      Object argument = astIndex.jjtGetChild(0).value(context);
      // If negative, turn -1 into (size - 1)
      argument = ASTIndex.adjMinusIndexArg(argument, result, context, astIndex);
      Object[] params = {argument, value};
      Class[] paramClasses = {
        params[0] == null ? null : params[0].getClass(),
        params[1] == null ? null : params[1].getClass()
      };

      String methodName = "set";
      VelMethod method =
          ClassUtils.getMethod(methodName, params, paramClasses, result, context, astIndex, false);

      if (method == null) {
        // If we can't find a 'set' method, lets try 'put',  This warrents a little
        // investigation performance wise... if the user is using the hash
        // form $foo["blaa"], then it may be expensive to first try and fail on 'set'
        // then go to 'put'?  The problem is that getMethod will try the cache, then
        // perform introspection on 'result' for 'set'
        methodName = "put";
        method =
            ClassUtils.getMethod(
                methodName, params, paramClasses, result, context, astIndex, false);
      }

      if (method == null) {
        // couldn't find set or put method, so bail
        if (strictRef) {
          throw new VelocityException(
              "Found neither a 'set' or 'put' method with param types '("
                  + printClass(paramClasses[0])
                  + ","
                  + printClass(paramClasses[1])
                  + ")' on class '"
                  + result.getClass().getName()
                  + "' at "
                  + Log.formatFileString(astIndex));
        }
        return false;
      }

      try {
        method.invoke(result, params);
      } catch (RuntimeException e) {
        // Kludge since invoke throws Exception, pass up Runtimes
        throw e;
      } catch (Exception e) {
        throw new MethodInvocationException(
            "Exception calling method '"
                + methodName
                + "("
                + printClass(paramClasses[0])
                + ","
                + printClass(paramClasses[1])
                + ")' in  "
                + result.getClass(),
            e.getCause(),
            identifier,
            astIndex.getTemplateName(),
            astIndex.getLine(),
            astIndex.getColumn());
      }

      return true;
    }

    /*
     *  We support two ways of setting the value in a #set($ref.foo = $value ) :
     *  1) ref.setFoo( value )
     *  2) ref,put("foo", value ) to parallel the get() map introspection
     */

    try {
      VelPropertySet vs = rsvc.getUberspect().getPropertySet(result, identifier, value, uberInfo);

      if (vs == null) {
        if (strictRef) {
          throw new MethodInvocationException(
              "Object '"
                  + result.getClass().getName()
                  + "' does not contain property '"
                  + identifier
                  + "'",
              null,
              identifier,
              uberInfo.getTemplateName(),
              uberInfo.getLine(),
              uberInfo.getColumn());
        } else {
          return false;
        }
      }

      vs.invoke(result, value);
    } catch (InvocationTargetException ite) {
      /*
       *  this is possible
       */

      throw new MethodInvocationException(
          "ASTReference : Invocation of method '"
              + identifier
              + "' in  "
              + result.getClass()
              + " threw exception "
              + ite.getTargetException().toString(),
          ite.getTargetException(),
          identifier,
          getTemplateName(),
          this.getLine(),
          this.getColumn());
    }
    /** pass through application level runtime exceptions */
    catch (RuntimeException e) {
      throw e;
    } catch (Exception e) {
      /*
       *  maybe a security exception?
       */
      String msg =
          "ASTReference setValue() : exception : "
              + e
              + " template at "
              + Log.formatFileString(uberInfo);
      log.error(msg, e);
      throw new VelocityException(msg, e);
    }

    return true;
  }
Esempio n. 3
0
  /**
   * gets an Object that 'is' the value of the reference
   *
   * @param o unused Object parameter
   * @param context context used to generate value
   * @return The execution result.
   * @throws MethodInvocationException
   */
  public Object execute(Object o, InternalContextAdapter context) throws MethodInvocationException {

    if (referenceType == RUNT) return null;

    /*
     *  get the root object from the context
     */

    Object result = getVariableValue(context, rootString);

    if (result == null && !strictRef) {
      return EventHandlerUtil.invalidGetMethod(
          rsvc, context, getDollarBang() + rootString, null, null, uberInfo);
    }

    /*
     * Iteratively work 'down' (it's flat...) the reference
     * to get the value, but check to make sure that
     * every result along the path is valid. For example:
     *
     * $hashtable.Customer.Name
     *
     * The $hashtable may be valid, but there is no key
     * 'Customer' in the hashtable so we want to stop
     * when we find a null value and return the null
     * so the error gets logged.
     */

    try {
      Object previousResult = result;
      int failedChild = -1;
      for (int i = 0; i < numChildren; i++) {
        if (strictRef && result == null) {
          /**
           * At this point we know that an attempt is about to be made to call a method or property
           * on a null value.
           */
          String name = jjtGetChild(i).getFirstToken().image;
          throw new VelocityException(
              "Attempted to access '"
                  + name
                  + "' on a null value at "
                  + Log.formatFileString(
                      uberInfo.getTemplateName(),
                      +jjtGetChild(i).getLine(),
                      jjtGetChild(i).getColumn()));
        }
        previousResult = result;
        result = jjtGetChild(i).execute(result, context);
        if (result == null && !strictRef) // If strict and null then well catch this
        // next time through the loop
        {
          failedChild = i;
          break;
        }
      }

      if (result == null) {
        if (failedChild == -1) {
          result =
              EventHandlerUtil.invalidGetMethod(
                  rsvc, context, getDollarBang() + rootString, previousResult, null, uberInfo);
        } else {
          StringBuffer name = new StringBuffer(getDollarBang()).append(rootString);
          for (int i = 0; i <= failedChild; i++) {
            Node node = jjtGetChild(i);
            if (node instanceof ASTMethod) {
              name.append(".").append(((ASTMethod) node).getMethodName()).append("()");
            } else {
              name.append(".").append(node.getFirstToken().image);
            }
          }

          if (jjtGetChild(failedChild) instanceof ASTMethod) {
            String methodName = ((ASTMethod) jjtGetChild(failedChild)).getMethodName();
            result =
                EventHandlerUtil.invalidMethod(
                    rsvc, context, name.toString(), previousResult, methodName, uberInfo);
          } else {
            String property = jjtGetChild(failedChild).getFirstToken().image;
            result =
                EventHandlerUtil.invalidGetMethod(
                    rsvc, context, name.toString(), previousResult, property, uberInfo);
          }
        }
      }

      return result;
    } catch (MethodInvocationException mie) {
      mie.setReferenceName(rootString);
      throw mie;
    }
  }