You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@velocity.apache.org by "Henning Schmiedehausen (JIRA)" <ji...@apache.org> on 2006/11/04 21:08:18 UTC
[jira] Assigned: (VELOCITY-414) Extend the MethodInvocation
exception to be able to give the velocity macro writer a usefull error page
[ http://issues.apache.org/jira/browse/VELOCITY-414?page=all ]
Henning Schmiedehausen reassigned VELOCITY-414:
-----------------------------------------------
Assignee: Henning Schmiedehausen
> Extend the MethodInvocation exception to be able to give the velocity macro writer a usefull error page
> -------------------------------------------------------------------------------------------------------
>
> Key: VELOCITY-414
> URL: http://issues.apache.org/jira/browse/VELOCITY-414
> Project: Velocity
> Issue Type: Improvement
> Components: Source
> Affects Versions: 1.5, 1.4
> Reporter: Matthijs Lambooy
> Assigned To: Henning Schmiedehausen
> Fix For: 1.5
>
>
> We use velocity macros that invoke methods in a java written web engine.
> When an invoked method fails because of an exception, it is not
> possible to use the
> MethodInvocation exception to give the velocity macro writer a usefull
> error page since the MethodInvocation Exception has not cause set.
> So to be short the reason why the method invocation failed can not be
> routed back to the veloticy macro writer on a running system.
> I extended the MethodInvocationException.java and the method execute in
> ASTMethod.java
> proposed changes in MethodInvocationException.java :
> ===============================================
> package org.apache.velocity.exception;
> import org.apache.velocity.exception.VelocityException;
> import org.apache.velocity.runtime.parser.Token;
> /*
> * Copyright 2001,2004 The Apache Software Foundation.
> *
> * Licensed 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.
> */
> /**
> * Application-level exception thrown when a reference method is
> * invoked and an exception is thrown.
> * <br>
> * When this exception is thrown, a best effort will be made to have
> * useful information in the exception's message. For complete
> * information, consult the runtime log.
> *
> * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
> * @version $Id: MethodInvocationException.java,v 1.2.14.1 2004/03/03 23:22:54 geirm Exp $
> */
> public class MethodInvocationException extends VelocityException
> {
> private String methodName = "";
> private String referenceName = "";
> private Throwable wrapped = null;
> private int line; // Added by CX
> private int column; // Added by CX
> /**
> * CTOR - wraps the passed in exception for
> * examination later
> *
> * @param message
> * @param e Throwable that we are wrapping
> * @param methodName name of method that threw the exception
> */
> public MethodInvocationException( String message, Throwable e, String methodName )
> {
> super(message);
> this.wrapped = e;
> this.methodName = methodName;
> }
> /**
> * Returns the name of the method that threw the
> * exception
> *
> * @return String name of method
> */
> public String getMethodName()
> {
> return methodName;
> }
> /**
> * returns the wrapped Throwable that caused this
> * MethodInvocationException to be thrown
> *
> * @return Throwable thrown by method invocation
> */
> public Throwable getWrappedThrowable()
> {
> return wrapped;
> }
> /**
> * Sets the reference name that threw this exception
> *
> * @param reference name of reference
> */
> public void setReferenceName( String ref )
> {
> referenceName = ref;
> }
> /**
> * Retrieves the name of the reference that caused the
> * exception
> *
> * @return name of reference
> */
> public String getReferenceName()
> {
> return referenceName;
> }
> /**
> * Retrieves the line number where the error occured
> *
> * @return line number
> */
> public int getLine()
> {
> return line;
> }
>
> /**
> * Sets the line number where the error occured
> *
> * @param line
> */
> public void setLine(int line)
> {
> this.line = line;
> }
> /**
> * Retrieves the line number where the error occured
> *
> * @return column number
> */
> public int getColumn()
> {
> return column;
> }
> /**
> * Sets the column number where the error occured
> *
> * @param column
> */
> public void setColumn(int column)
> {
> this.column = column;
> }
>
> }
> ===============================================
> Proposed changes in ASTMethod.java
> ===============================================
> package org.apache.velocity.runtime.parser.node;
> /*
> * Copyright 2000-2001,2004 The Apache Software Foundation.
> *
> * Licensed 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.velocity.context.InternalContextAdapter;
> import org.apache.velocity.runtime.parser.*;
> import org.apache.velocity.util.introspection.IntrospectionCacheData;
> import org.apache.velocity.util.introspection.VelMethod;
> import org.apache.velocity.util.introspection.Info;
> import org.apache.velocity.exception.MethodInvocationException;
> import java.lang.reflect.InvocationTargetException;
> import org.apache.velocity.app.event.EventCartridge;
> /**
> * ASTMethod.java
> *
> * Method support for references : $foo.method()
> *
> * NOTE :
> *
> * introspection is now done at render time.
> *
> * Please look at the Parser.jjt file which is
> * what controls the generation of this class.
> *
> * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
> * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
> * @version $Id: ASTMethod.java,v 1.24.4.1 2004/03/03 23:22:59 geirm Exp $
> */
> public class ASTMethod extends SimpleNode
> {
> private String methodName = "";
> private int paramCount = 0;
> public ASTMethod(int id)
> {
> super(id);
> }
> public ASTMethod(Parser p, int id)
> {
> super(p, id);
> }
> /** Accept the visitor. **/
> public Object jjtAccept(ParserVisitor visitor, Object data)
> {
> return visitor.visit(this, data);
> }
> /**
> * simple init - init our subtree and get what we can from
> * the AST
> */
> public Object init( InternalContextAdapter context, Object data)
> throws Exception
> {
> super.init( context, data );
> /*
> * this is about all we can do
> */
> methodName = getFirstToken().image;
> paramCount = jjtGetNumChildren() - 1;
> return data;
> }
> /**
> * invokes the method. Returns null if a problem, the
> * actual return if the method returns something, or
> * an empty string "" if the method returns void
> */
> public Object execute(Object o, InternalContextAdapter context)
> throws MethodInvocationException
> {
> /*
> * new strategy (strategery!) for introspection. Since we want
> * to be thread- as well as context-safe, we *must* do it now,
> * at execution time. There can be no in-node caching,
> * but if we are careful, we can do it in the context.
> */
> VelMethod method = null;
> Object [] params = new Object[paramCount];
> try
> {
> /*
> * check the cache
> */
> IntrospectionCacheData icd = context.icacheGet( this );
> Class c = o.getClass();
> /*
> * like ASTIdentifier, if we have cache information, and the
> * Class of Object o is the same as that in the cache, we are
> * safe.
> */
> if ( icd != null && icd.contextData == c )
> {
> /*
> * sadly, we do need recalc the values of the args, as this can
> * change from visit to visit
> */
> for (int j = 0; j < paramCount; j++)
> params[j] = jjtGetChild(j + 1).value(context);
> /*
> * and get the method from the cache
> */
> method = (VelMethod) icd.thingy;
> }
> else
> {
> /*
> * otherwise, do the introspection, and then
> * cache it
> */
> for (int j = 0; j < paramCount; j++)
> params[j] = jjtGetChild(j + 1).value(context);
> method = rsvc.getUberspect().getMethod(o, methodName, params, new Info("",1,1));
> if (method != null)
> {
> icd = new IntrospectionCacheData();
> icd.contextData = c;
> icd.thingy = method;
> context.icachePut( this, icd );
> }
> }
>
> /*
> * if we still haven't gotten the method, either we are calling
> * a method that doesn't exist (which is fine...) or I screwed
> * it up.
> */
> if (method == null)
> return null;
> }
> catch( MethodInvocationException mie )
> {
> /*
> * this can come from the doIntrospection(), as the arg values
> * are evaluated to find the right method signature. We just
> * want to propogate it here, not do anything fancy
> */
> throw mie;
> }
> catch( Exception e )
> {
> /*
> * can come from the doIntropection() also, from Introspector
> */
> rsvc.error("ASTMethod.execute() : exception from introspection : " + e);
> return null;
> }
> try
> {
> /*
> * get the returned object. It may be null, and that is
> * valid for something declared with a void return type.
> * Since the caller is expecting something to be returned,
> * as long as things are peachy, we can return an empty
> * String so ASTReference() correctly figures out that
> * all is well.
> */
> Object obj = method.invoke(o, params);
>
> if (obj == null)
> {
> if( method.getReturnType() == Void.TYPE)
> return new String("");
> }
>
> return obj;
> }
> catch( InvocationTargetException ite )
> {
> /*
> * In the event that the invocation of the method
> * itself throws an exception, we want to catch that
> * wrap it, and throw. We don't log here as we want to figure
> * out which reference threw the exception, so do that
> * above
> */
> EventCartridge ec = context.getEventCartridge();
> /*
> * if we have an event cartridge, see if it wants to veto
> * also, let non-Exception Throwables go...
> */
> if ( ec != null && ite.getTargetException() instanceof java.lang.Exception)
> {
> try
> {
> return ec.methodException( o.getClass(), methodName, (Exception)ite.getTargetException() );
> }
> catch( Exception e )
> {
> MethodInvocationException miex = new MethodInvocationException(
> "Invocation of method '"
> + methodName + "' in " + o.getClass()
> + " threw exception "
> + e.getClass() + " : " + e.getMessage(),
> e, methodName );
> miex.initCause(ite.getTargetException());
> miex.setLine(first.beginLine);
> miex.setColumn(first.beginColumn);
> throw miex;
> }
> }
> else
> {
> /*
> * no event cartridge to override. Just throw
> */
> MethodInvocationException miex = new MethodInvocationException(
> "Invocation of method '"
> + methodName + "' in " + o.getClass()
> + " threw exception "
> + ite.getTargetException().getClass() + " : "
> + ite.getTargetException().getMessage(),
> ite.getTargetException(), methodName );
> miex.initCause(ite.getTargetException());
> miex.setLine(first.beginLine);
> miex.setColumn(first.beginColumn);
> throw miex;
> }
> }
> catch( Exception e )
> {
> rsvc.error("ASTMethod.execute() : exception invoking method '"
> + methodName + "' in " + o.getClass() + " : " + e );
>
> return null;
> }
> }
> }
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
---------------------------------------------------------------------
To unsubscribe, e-mail: velocity-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: velocity-dev-help@jakarta.apache.org