Author: wglass
Date: Thu Oct 12 04:52:06 2006
New Revision: 463213

URL: http://svn.apache.org/viewvc?view=rev&rev=463213
Log:
New event handler: InvalidReferenceEventHandler.  Allows the developer to trap 
invalid references, property assignments, method calls.
Sample implementation can be used to record all invalid references for later 
retrieval.  With a configuration option, it can
also throw an exception upon the first invalid reference.  Related to 
VELOCITY-423. 

Added:
    
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/InvalidReferenceEventHandler.java
   (with props)
    
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/implement/InvalidReferenceInfo.java
   (with props)
    
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/implement/ReportInvalidReferences.java
   (with props)
    
jakarta/velocity/engine/trunk/src/test/org/apache/velocity/test/InvalidEventHandlerTestCase.java
   (with props)
Modified:
    
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/EventHandlerUtil.java
    
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/exception/ParseErrorException.java
    
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java
    
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java
    
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTMethod.java
    
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java
    
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java
    
jakarta/velocity/engine/trunk/src/test/org/apache/velocity/test/BuiltInEventHandlerTestCase.java

Modified: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/EventHandlerUtil.java
URL: 
http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/EventHandlerUtil.java?view=diff&rev=463213&r1=463212&r2=463213
==============================================================================
--- 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/EventHandlerUtil.java
 (original)
+++ 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/EventHandlerUtil.java
 Thu Oct 12 04:52:06 2006
@@ -21,6 +21,7 @@
 import org.apache.velocity.context.InternalContextAdapter;
 import org.apache.velocity.runtime.RuntimeServices;
 import org.apache.velocity.util.ExceptionUtils;
+import org.apache.velocity.util.introspection.Info;
 
 
 /**
@@ -228,7 +229,121 @@
             throw ExceptionUtils.createRuntimeException("Exception in event 
handler.",e);
         }
     }
+   
+
+    /**
+     * Called when an invalid get method is encountered.
+     * 
+     * @param rsvc The RuntimeServices Object.
+     * @param context the context when the reference was found invalid
+     * @param reference complete invalid reference
+     * @param object object from reference, or null if not available
+     * @param property name of property, or null if not relevant
+     * @param info contains info on template, line, col
+     * @return
+     */
+    public static Object invalidGetMethod(RuntimeServices rsvc,
+            InternalContextAdapter context, String reference, 
+            Object object, String property, Info info)
+    {
+        return  
+        invalidReferenceHandlerCall (
+                new InvalidReferenceEventHandler.InvalidGetMethodExecutor
+                (context, reference, object, property, info),
+                rsvc, 
+                context);       
+    }
+        
+        
+   /**
+     * Called when an invalid get method is encountered.
+     * 
+     * @param rsvc The RuntimeServices Object.
+     * @param context the context when the reference was found invalid
+     * @param reference complete invalid reference
+     * @param object object from reference, or null if not available
+     * @param property name of property, or null if not relevant
+     * @param info contains info on template, line, col
+     */
+    public static void invalidSetMethod(RuntimeServices rsvc,
+            InternalContextAdapter context, String leftreference, 
+            String rightreference, Info info)
+    {
+        /**
+         * ignore return value
+         */
+        invalidReferenceHandlerCall (
+                new InvalidReferenceEventHandler.InvalidSetMethodExecutor
+                (context, leftreference, rightreference, info),
+                rsvc, 
+                context);   
+    }
     
+    /**
+     * Called when an invalid method is encountered.
+     * 
+     * @param rsvc The RuntimeServices Object.
+     * @param context the context when the reference was found invalid
+     * @param reference complete invalid reference
+     * @param object object from reference, or null if not available
+     * @param method name of method, or null if not relevant
+     * @param info contains info on template, line, col
+     * @return
+     */
+    public static Object invalidMethod(RuntimeServices rsvc,
+            InternalContextAdapter context,  String reference,
+            Object object, String method, Info info)
+    {
+        return 
+        invalidReferenceHandlerCall (
+                new InvalidReferenceEventHandler.InvalidMethodExecutor
+                (context, reference, object, method, info),
+                rsvc, 
+                context);       
+    }
+    
+    
+    /**
+     * Generic call to InvalidReferenceEventHandler method. 
+     * @param methodExecutor
+     * @param rsvc
+     * @param context
+     * @return
+     */
+    public static Object invalidReferenceHandlerCall(
+            EventHandlerMethodExecutor methodExecutor, 
+            RuntimeServices rsvc,
+            InternalContextAdapter context)
+    {
+        // app level cartridges have already been initialized
+        EventCartridge ev1 = rsvc.getApplicationEventCartridge();
+        Iterator applicationEventHandlerIterator = 
+            (ev1 == null) ? null: ev1.getInvalidReferenceEventHandlers();      
        
+        
+        EventCartridge ev2 = context.getEventCartridge();
+        initializeEventCartridge(rsvc, ev2);
+        Iterator contextEventHandlerIterator = 
+            (ev2 == null) ? null: ev2.getInvalidReferenceEventHandlers();      
        
+        
+        try
+        {
+            callEventHandlers(
+                    applicationEventHandlerIterator, 
+                    contextEventHandlerIterator, methodExecutor);
+            
+            return methodExecutor.getReturnValue();
+        }
+        catch (RuntimeException e)
+        {
+            throw e;
+        }
+        catch (Exception e)
+        {
+            throw ExceptionUtils.createRuntimeException("Exception in event 
handler.",e);
+        }
+        
+    }
+
     /**
      * Initialize the event cartridge if appropriate.
      * @param rsvc

Added: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/InvalidReferenceEventHandler.java
URL: 
http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/InvalidReferenceEventHandler.java?view=auto&rev=463213
==============================================================================
--- 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/InvalidReferenceEventHandler.java
 (added)
+++ 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/InvalidReferenceEventHandler.java
 Thu Oct 12 04:52:06 2006
@@ -0,0 +1,234 @@
+package org.apache.velocity.app.event;
+
+/*
+ * Copyright 2001-2006 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.Context;
+import org.apache.velocity.util.introspection.Info;
+
+/**
+ * Event handler called when an invalid reference is encountered.  Allows 
+ * the application to report errors or substitute return values. <May be 
chained
+ * in sequence; the behavior will differ per method.
+ * 
+ * <p>This feature should be regarded as experimental.
+ *
+ * @author <a href="mailto:[EMAIL PROTECTED]">Will Glass-Husain</a>
+ * @version $Id$
+ */
+public interface InvalidReferenceEventHandler extends EventHandler
+{
+    
+    /**
+     * Called when object is null or there is no getter for the given 
+     * property.  Also called for invalid references without properties.  
+     * invalidGetMethod() will be called in sequence for
+     * each link in the chain until the first non-null value is
+     * returned.
+     * 
+     * @param context the context when the reference was found invalid
+     * @param reference string with complete invalid reference
+     * @param object the object referred to, or null if not found
+     * @param property the property name from the reference
+     * @param info contains template, line, column details
+     * @return substitute return value for missing reference
+     */
+    public Object invalidGetMethod(Context context, String reference, 
+            Object object, String property, Info info);
+
+    /**
+     * Called when object is null or there is no setter for the given 
+     * property.  invalidSetMethod() will be called in sequence for
+     * each link in the chain until a true value is returned.  It's
+     * recommended that false be returned as a default to allow
+     * for easy chaining.
+     * 
+     * @param context the context when the reference was found invalid
+     * @param leftreference string to which the value is being assigned
+     * @param rightreference the invalid reference on the right
+     * @param property the property name from the reference
+     * @param info contains template, line, column details
+     * @param if true then stop calling invalidSetMethod along the 
+     * chain.
+     */
+    public boolean invalidSetMethod(Context context, String leftreference, 
+            String rightreference, Info info);
+
+    /**
+     * Called when object is null or the given method does not exist.
+     * invalidMethod() will be called in sequence for each link in 
+     * the chain until the first non-null value is returned. 
+     * 
+     * @param context the context when the reference was found invalid
+     * @param reference string with complete invalid reference
+     * @param object the object referred to, or null if not found
+     * @param method the name of the (non-existent) method
+     * @param info contains template, line, column details
+     * @return substitute return value for missing reference
+     */
+    public Object invalidMethod(Context context, String reference,  
+            Object object, String method, Info info);
+    
+    
+    /**
+     * Defines the execution strategy for invalidGetMethod
+     */
+    static class InvalidGetMethodExecutor implements 
EventHandlerMethodExecutor 
+    {
+        private Context context;
+        private String reference;
+        private Object object;
+        private String property;
+        private Info info;
+        
+        private Object result;
+        
+        InvalidGetMethodExecutor(
+                Context context, 
+                String reference, 
+                Object object, 
+                String property, 
+                Info info)
+        {
+            this.context = context;
+            this.reference = reference;
+            this.object = object;
+            this.property = property;
+            this.info = info;
+        }
+
+        /**
+         * Call the method invalidGetMethod()
+         *  
+         * @param handler call the appropriate method on this handler
+         */
+        public void execute(EventHandler handler)
+        {
+            result = ((InvalidReferenceEventHandler) handler).invalidGetMethod(
+                    context, reference, object, property, info);
+        }
+
+        public Object getReturnValue()
+        {
+            return result;
+        }
+
+        public boolean isDone()
+        {
+            return (result != null);
+        }                
+    }
+
+    /**
+     * Defines the execution strategy for invalidGetMethod
+     */
+    static class InvalidSetMethodExecutor implements 
EventHandlerMethodExecutor 
+    {
+        private Context context;
+        private String leftreference;
+        private String rightreference;
+        private Info info;
+        
+        private boolean result;
+        
+        InvalidSetMethodExecutor(
+                Context context, 
+                String leftreference, 
+                String rightreference, 
+                Info info)
+        {
+            this.context = context;
+            this.leftreference = leftreference;
+            this.rightreference = rightreference;
+            this.info = info;
+        }
+
+        /**
+         * Call the method invalidSetMethod()
+         *  
+         * @param handler call the appropriate method on this handler
+         */
+        public void execute(EventHandler handler)
+        {
+            result = ((InvalidReferenceEventHandler) handler).invalidSetMethod(
+                    context, leftreference, rightreference, info);            
+        }        
+    
+        public Object getReturnValue()
+        {
+            return null;
+        }
+
+        public boolean isDone()
+        {
+            return result;
+        }        
+
+    }
+
+    /**
+     * Defines the execution strategy for invalidGetMethod
+     */
+    static class InvalidMethodExecutor implements EventHandlerMethodExecutor
+    {
+        private Context context;
+        private String reference;
+        private Object object;
+        private String method;
+        private Info info;
+
+        private Object result;
+        private boolean executed = false;
+        
+        InvalidMethodExecutor(
+                Context context, 
+                String reference, 
+                Object object,
+                String method,
+                Info info)
+        {
+            this.context = context;
+            this.reference = reference;
+            this.object = object;
+            this.method = method;
+            this.info = info;
+        }
+
+        /**
+         * Call the method invalidMethod()
+         *  
+         * @param handler call the appropriate method on this handler
+         */
+        public void execute(EventHandler handler)
+        {
+            executed = true;
+            result = ((InvalidReferenceEventHandler) handler).invalidMethod(
+                    context, reference, object, method, info);
+        }
+        
+        public Object getReturnValue()
+        {
+            return result;
+        }
+
+        public boolean isDone()
+        {
+            return executed && (result != null);
+        }        
+
+    }
+
+}

Propchange: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/InvalidReferenceEventHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/InvalidReferenceEventHandler.java
------------------------------------------------------------------------------
    svn:keywords = Id Author Date Revision

Added: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/implement/InvalidReferenceInfo.java
URL: 
http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/implement/InvalidReferenceInfo.java?view=auto&rev=463213
==============================================================================
--- 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/implement/InvalidReferenceInfo.java
 (added)
+++ 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/implement/InvalidReferenceInfo.java
 Thu Oct 12 04:52:06 2006
@@ -0,0 +1,60 @@
+package org.apache.velocity.app.event.implement;
+
+/*
+ * Copyright 2001-2006 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.util.introspection.Info;
+
+/**
+ * Convenience class to use when reporting out invalid syntax 
+ * with line, column, and template name.
+ * 
+ * @author <a href="mailto:[EMAIL PROTECTED]">Will Glass-Husain </a>
+ * @version $Id$
+ */
+public class InvalidReferenceInfo extends Info
+{
+    private String invalidReference;
+    
+    public InvalidReferenceInfo(String invalidReference, Info info)
+    {
+        super(info.getTemplateName(),info.getLine(),info.getColumn());
+        this.invalidReference = invalidReference; 
+    }
+
+    /**
+     * Get the specific invalid reference string.
+     * @return the invalid reference string
+     */
+    public String getInvalidReference()
+    {
+        return invalidReference;
+    }
+    
+    
+
+    /**
+     * Formats a textual representation of this object as <code>SOURCE
+     * [line X, column Y]</code>.
+     *
+     * @return String representing this object.
+     */
+    public String toString()
+    {
+        return getTemplateName() + " [line " + getLine() + ", column " +
+            getColumn() + "]: " + invalidReference;
+    }
+}

Propchange: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/implement/InvalidReferenceInfo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/implement/InvalidReferenceInfo.java
------------------------------------------------------------------------------
    svn:keywords = Id Author Date Revision

Added: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/implement/ReportInvalidReferences.java
URL: 
http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/implement/ReportInvalidReferences.java?view=auto&rev=463213
==============================================================================
--- 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/implement/ReportInvalidReferences.java
 (added)
+++ 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/implement/ReportInvalidReferences.java
 Thu Oct 12 04:52:06 2006
@@ -0,0 +1,177 @@
+package org.apache.velocity.app.event.implement;
+
+/*
+ * Copyright 2001-2006 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 java.util.ArrayList;
+import java.util.List;
+
+import org.apache.velocity.app.event.InvalidReferenceEventHandler;
+import org.apache.velocity.context.Context;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.runtime.RuntimeServices;
+import org.apache.velocity.util.RuntimeServicesAware;
+import org.apache.velocity.util.introspection.Info;
+
+/**
+ * Use this event handler to flag invalid references.  Since this 
+ * is intended to be used for a specific request, this should be
+ * used as a local event handler attached to a specific context
+ * instead of being globally defined in the Velocity properties file.
+ * 
+ * <p>
+ * Note that InvalidReferenceHandler can be used
+ * in two modes.  If the Velocity properties file contains the following:
+ * <pre>
+ * <CODE>eventhandler.invalidreference.exception = true
+ * </pre>
+ * then the event handler will throw a ParseErrorRuntimeException upon 
+ * hitting the first invalid reference.  This stops processing and is 
+ * passed through to the application code.  The ParseErrorRuntimeException
+ * contain information about the template name, line number, column number,
+ * and invalid reference.
+ * 
+ * <p>
+ * If this configuration setting is false or omitted then the page 
+ * will be processed as normal, but all invalid references will be collected
+ * in a List of InvalidReferenceInfo objects.
+ * 
+ * <p>This feature should be regarded as experimental.
+ * 
+ * @author <a href="mailto:[EMAIL PROTECTED]">Will Glass-Husain</a>
+ * @version $Id$
+ */
+public class ReportInvalidReferences implements 
+InvalidReferenceEventHandler, RuntimeServicesAware
+{
+
+    public static final String EVENTHANDLER_INVALIDREFERENCE_EXCEPTION = 
"eventhandler.invalidreference.exception";
+    
+    /** 
+     * List of InvalidReferenceInfo objects
+     */
+    List invalidReferences = new ArrayList();
+
+    /**
+     * If true, stop at the first invalid reference and throw an exception.
+     */
+    private boolean stopOnFirstInvalidReference = false;
+    
+       
+    /**
+     * Collect the error and/or throw an exception, depending on configuration.
+     *
+     * @param context the context when the reference was found invalid
+     * @param reference string with complete invalid reference
+     * @param object the object referred to, or null if not found
+     * @param property the property name from the reference
+     * @param info contains template, line, column details
+     * @return always returns null
+     * @throws ParseErrorException
+     */
+    public Object invalidGetMethod(Context context, String reference, Object 
object, 
+            String property, Info info)
+    {
+        reportInvalidReference(reference, info);
+        return null;
+    }
+
+    /**
+     * Collect the error and/or throw an exception, depending on configuration.
+     *
+     * @param context the context when the reference was found invalid
+     * @param reference complete invalid reference
+     * @param object the object referred to, or null if not found
+     * @param method the property name from the reference
+     * @param info contains template, line, column details
+     * @return always returns null
+     * @throws ParseErrorException
+     */
+    public Object invalidMethod(Context context, String reference, Object 
object, 
+            String method, Info info)
+    {
+        if (reference == null)
+        {
+            reportInvalidReference(object.getClass().getName() + "." + method, 
info);
+        }
+        else
+        {
+            reportInvalidReference(reference, info);
+        }
+        return null;
+    }
+
+    /**
+     * Collect the error and/or throw an exception, depending on configuration.
+     *
+     * @param context the context when the reference was found invalid
+     * @param reference string with complete invalid reference
+     * @param object the object referred to, or null if not found
+     * @param method the name of the (non-existent) method
+     * @param info contains template, line, column details
+     * @param always returns false
+     * @throws ParseErrorException
+     */
+    public boolean invalidSetMethod(Context context, String leftreference, 
String rightreference, Info info)
+    {
+        reportInvalidReference(leftreference, info);
+        return false;
+    }
+
+
+    /**
+     * Check for an invalid reference and collect the error or throw an 
exception 
+     * (depending on configuration).
+     * 
+     * @throws ParseErrorException
+     */
+    private void reportInvalidReference(String reference, Info info)
+    {
+        InvalidReferenceInfo invalidReferenceInfo = new 
InvalidReferenceInfo(reference, info);
+        invalidReferences.add(invalidReferenceInfo);
+        
+        if (stopOnFirstInvalidReference)
+        {
+            throw new ParseErrorException(
+                    "Error in page - invalid reference.  ",
+                    info,
+                    invalidReferenceInfo.getInvalidReference());
+        }
+    }
+
+
+    /**
+     * All invalid references during the processing of this page.
+     * @return a List of InvalidReferenceInfo objects
+     */
+    public List getInvalidReferences()
+    {
+        return invalidReferences;
+    }
+    
+
+    /**
+     * Called automatically when event cartridge is initialized.
+     * @param rs RuntimeServices object assigned during initialization
+     */
+    public void setRuntimeServices(RuntimeServices rs)
+    {
+        stopOnFirstInvalidReference = rs.getConfiguration().getBoolean(
+                EVENTHANDLER_INVALIDREFERENCE_EXCEPTION,
+                false);        
+    }
+    
+}

Propchange: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/implement/ReportInvalidReferences.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/app/event/implement/ReportInvalidReferences.java
------------------------------------------------------------------------------
    svn:keywords = Id Author Date Revision

Modified: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/exception/ParseErrorException.java
URL: 
http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/exception/ParseErrorException.java?view=diff&rev=463213&r1=463212&r2=463213
==============================================================================
--- 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/exception/ParseErrorException.java
 (original)
+++ 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/exception/ParseErrorException.java
 Thu Oct 12 04:52:06 2006
@@ -17,6 +17,7 @@
  */
 
 import org.apache.velocity.runtime.parser.ParseException;
+import org.apache.velocity.util.introspection.Info;
 
 /**
  *  Application-level exception thrown when a resource of any type
@@ -53,6 +54,11 @@
     private String templateName = "*unset*";
 
     /**
+     * If applicable, contains the invalid syntax or reference that triggered 
this exception
+     */
+    private String invalidSyntax;
+
+    /**
      * Create a ParseErrorException with the given message.
      *
      * @param exceptionMessage the error exception message
@@ -93,6 +99,39 @@
         }
     }
 
+
+    /**
+     * Create a ParseErrorRuntimeException with the given message and info
+     * 
+     * @param exceptionMessage the error exception message
+     * @param info an Info object with the current template info
+     */
+    public ParseErrorException(String exceptionMessage, Info info)
+    {
+        super(exceptionMessage);
+        columnNumber = info.getColumn();
+        lineNumber = info.getLine();
+        templateName = info.getTemplateName();        
+    }    
+
+    /**
+     * Create a ParseErrorRuntimeException with the given message and info
+     * 
+     * @param exceptionMessage the error exception message
+     * @param info an Info object with the current template info
+     * @param invalidSyntax the invalid syntax or reference triggering this 
exception
+     */
+    public ParseErrorException(String exceptionMessage, 
+            Info info, String invalidSyntax)
+    {
+        super(exceptionMessage);
+        columnNumber = info.getColumn();
+        lineNumber = info.getLine();
+        templateName = info.getTemplateName();  
+        this.invalidSyntax = invalidSyntax;       
+    }    
+
+
     /**
      * Return the column number of the parsing error, or -1 if not defined.
      *
@@ -124,4 +163,17 @@
     {
         return templateName;
     }
+
+    /**
+     * Return the invalid syntax or reference that triggered this error, or 
null
+     * if not defined.
+     * 
+     * @return Return the invalid syntax or reference that triggered this 
error, or null
+     * if not defined
+     */
+    public String getInvalidSyntax()
+    {
+        return invalidSyntax;
+    }
+
 }

Modified: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java
URL: 
http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java?view=diff&rev=463213&r1=463212&r2=463213
==============================================================================
--- 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java
 (original)
+++ 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java
 Thu Oct 12 04:52:06 2006
@@ -253,6 +253,14 @@
      */
     public static final String EVENTHANDLER_INCLUDE = 
"eventhandler.include.class";
 
+    /**
+     * The <code>eventhandler.invalidreferences.class</code> property
+     * specifies a list of the [EMAIL PROTECTED]
+     * org.apache.velocity.app.event.InvalidReferenceEventHandler}
+     * implementations to use.
+     */
+    public static final String EVENTHANDLER_INVALIDREFERENCES = 
"eventhandler.invalidreferences.class";
+
 
     /*
      * ----------------------------------------------------------------------

Modified: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java
URL: 
http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java?view=diff&rev=463213&r1=463212&r2=463213
==============================================================================
--- 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java
 (original)
+++ 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java
 Thu Oct 12 04:52:06 2006
@@ -31,6 +31,7 @@
 import org.apache.velocity.app.event.EventCartridge;
 import org.apache.velocity.app.event.EventHandler;
 import org.apache.velocity.app.event.IncludeEventHandler;
+import org.apache.velocity.app.event.InvalidReferenceEventHandler;
 import org.apache.velocity.app.event.MethodExceptionEventHandler;
 import org.apache.velocity.app.event.NullSetEventHandler;
 import org.apache.velocity.app.event.ReferenceInsertionEventHandler;
@@ -641,6 +642,20 @@
                     
eventCartridge.addIncludeEventHandler((IncludeEventHandler) ev);
             }
         }
+
+        String[] invalidReferenceSet = 
configuration.getStringArray(RuntimeConstants.EVENTHANDLER_INVALIDREFERENCES);
+        if ( invalidReferenceSet != null )
+        {
+            for ( int i=0; i < invalidReferenceSet.length; i++ )
+            {
+                EventHandler ev = 
initializeSpecificEventHandler(invalidReferenceSet[i],RuntimeConstants.EVENTHANDLER_INVALIDREFERENCES,InvalidReferenceEventHandler.class);
+                if (ev != null)
+                {
+                    
eventCartridge.addInvalidReferenceEventHandler((InvalidReferenceEventHandler) 
ev);
+                }
+            }
+        }
+
 
     }
 

Modified: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTMethod.java
URL: 
http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTMethod.java?view=diff&rev=463213&r1=463212&r2=463213
==============================================================================
--- 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTMethod.java
 (original)
+++ 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTMethod.java
 Thu Oct 12 04:52:06 2006
@@ -50,6 +50,8 @@
     private String methodName = "";
     private int paramCount = 0;
 
+    protected Info uberInfo;
+
     /**
      * @param id
      */
@@ -89,6 +91,12 @@
         super.init(  context, data );
 
         /*
+         * make an uberinfo - saves new's later on
+         */
+
+        uberInfo = new Info(context.getCurrentTemplateName(),
+                getLine(),getColumn());
+        /*
          *  this is about all we can do
          */
 
@@ -191,7 +199,9 @@
              */
 
             if (method == null)
+            {
                 return null;
+            }
         }
         catch( MethodInvocationException mie )
         {
@@ -396,5 +406,14 @@
             return result;
         } 
     }
+
+    /**
+     * @return Returns the methodName.
+     */
+    public String getMethodName()
+    {
+        return methodName;
+    }
+    
     
 }

Modified: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java
URL: 
http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java?view=diff&rev=463213&r1=463212&r2=463213
==============================================================================
--- 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java
 (original)
+++ 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java
 Thu Oct 12 04:52:06 2006
@@ -173,7 +173,8 @@
 
         if (result == null)
         {
-            return null;
+            return EventHandlerUtil.invalidGetMethod(rsvc, context, 
+                    "$" + rootString, null, null, uberInfo);
         }
 
         /*
@@ -191,15 +192,58 @@
 
         try
         {
+            Object previousResult = result; 
+            int failedChild = -1;
             for (int i = 0; i < numChildren; i++)
             {
+                previousResult = result;
                 result = jjtGetChild(i).execute(result,context);
                 if (result == null)
                 {
+                    failedChild = i;
                     break;
                 }
             }
 
+            if (result == null)
+            {
+                if (failedChild == -1)
+                {
+                    result = EventHandlerUtil.invalidGetMethod(rsvc, context, 
+                            "$" + rootString, previousResult, null, uberInfo); 
                   
+                }
+                else
+                {
+                    StringBuffer name = new 
StringBuffer("$").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)

Modified: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java
URL: 
http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java?view=diff&rev=463213&r1=463212&r2=463213
==============================================================================
--- 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java
 (original)
+++ 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java
 Thu Oct 12 04:52:06 2006
@@ -25,6 +25,7 @@
 import org.apache.velocity.runtime.RuntimeConstants;
 import org.apache.velocity.runtime.parser.Parser;
 import org.apache.velocity.runtime.parser.ParserVisitor;
+import org.apache.velocity.util.introspection.Info;
 
 /**
  * Node for the #set directive
@@ -41,6 +42,11 @@
     boolean logOnNull = false;
 
     /**
+     *  This is really immutable after the init, so keep one for this node
+     */
+    protected Info uberInfo;
+
+    /**
      * @param id
      */
     public ASTSetDirective(int id)
@@ -81,6 +87,9 @@
 
         super.init( context, data );
 
+        uberInfo = new Info(context.getCurrentTemplateName(),
+                getLine(), getColumn());
+
         right = getRightHandSide();
         left = getLeftHandSide();
 
@@ -119,7 +128,7 @@
         if( !rsvc.getBoolean(RuntimeConstants.SET_NULL_ALLOWED,false) )
         {
             if ( value == null )
-            {
+            {                
                 /*
                  *  first, are we supposed to say anything anyway?
                  */
@@ -134,18 +143,35 @@
                                       + ", column " + getColumn() + "]");
                     }
                 }
-
+                
+                String rightReference = null;
+                if (right instanceof ASTExpression)
+                {
+                    rightReference = ((ASTExpression) 
right).getLastToken().image;
+                }
+                EventHandlerUtil.invalidSetMethod(rsvc, context, 
leftReference, rightReference, uberInfo);
+                
                 return false;
             }
         }
 
         if ( value == null )
         {
+            String rightReference = null;
+            if (right instanceof ASTExpression)
+            {
+                rightReference = ((ASTExpression) right).getLastToken().image;
+            }
+            EventHandlerUtil.invalidSetMethod(rsvc, context, leftReference, 
rightReference, uberInfo);
+
             /*
              * if RHS is null it doesn't matter if LHS is simple or complex
              * because the LHS is removed from context
              */
             context.remove( leftReference );
+
+            return false;
+
         }
         else
         {

Modified: 
jakarta/velocity/engine/trunk/src/test/org/apache/velocity/test/BuiltInEventHandlerTestCase.java
URL: 
http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/test/org/apache/velocity/test/BuiltInEventHandlerTestCase.java?view=diff&rev=463213&r1=463212&r2=463213
==============================================================================
--- 
jakarta/velocity/engine/trunk/src/test/org/apache/velocity/test/BuiltInEventHandlerTestCase.java
 (original)
+++ 
jakarta/velocity/engine/trunk/src/test/org/apache/velocity/test/BuiltInEventHandlerTestCase.java
 Thu Oct 12 04:52:06 2006
@@ -22,6 +22,7 @@
 import java.io.StringWriter;
 import java.io.Writer;
 import java.util.ArrayList;
+import java.util.List;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
@@ -29,11 +30,14 @@
 import org.apache.velocity.Template;
 import org.apache.velocity.VelocityContext;
 import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.app.event.EventCartridge;
 import org.apache.velocity.app.event.implement.EscapeHtmlReference;
 import org.apache.velocity.app.event.implement.EscapeJavaScriptReference;
 import org.apache.velocity.app.event.implement.EscapeReference;
 import org.apache.velocity.app.event.implement.EscapeSqlReference;
 import org.apache.velocity.app.event.implement.EscapeXmlReference;
+import org.apache.velocity.app.event.implement.InvalidReferenceInfo;
+import org.apache.velocity.app.event.implement.ReportInvalidReferences;
 import org.apache.velocity.context.Context;
 import org.apache.velocity.runtime.RuntimeConstants;
 
@@ -95,6 +99,59 @@
        return new TestSuite(BuiltInEventHandlerTestCase.class);
     }
 
+
+
+    /**
+     * Test reporting of invalid syntax
+     * @throws Exception
+     */
+    public void testReportInvalidReferences1() throws Exception
+    {
+        VelocityEngine ve = new VelocityEngine();
+        ReportInvalidReferences reporter = new ReportInvalidReferences();
+        ve.init();
+
+        VelocityContext context = new VelocityContext();
+        EventCartridge ec = new EventCartridge();
+        ec.addEventHandler(reporter);
+        ec.attachToContext(context);
+
+        context.put("a1","test");
+        context.put("b1","test");
+        Writer writer = new StringWriter();
+
+        ve.evaluate(context,writer,"test","$a1 $c1 $a1.length() $a1.foobar()");
+
+        List errors = reporter.getInvalidReferences();
+        assertEquals(2,errors.size());
+        assertEquals("$c1",((InvalidReferenceInfo) 
errors.get(0)).getInvalidReference());
+        assertEquals("$a1.foobar()",((InvalidReferenceInfo) 
errors.get(1)).getInvalidReference());
+    }
+
+    public void testReportInvalidReferences2() throws Exception
+    {
+        VelocityEngine ve = new VelocityEngine();
+        ve.setProperty("eventhandler.invalidreference.exception","true");
+        ReportInvalidReferences reporter = new ReportInvalidReferences();
+        ve.init();
+
+        VelocityContext context = new VelocityContext();
+        EventCartridge ec = new EventCartridge();
+        ec.addEventHandler(reporter);
+        ec.attachToContext(context);
+
+        context.put("a1","test");
+        context.put("b1","test");
+        Writer writer = new StringWriter();
+
+        ve.evaluate(context,writer,"test","$a1 no problem");
+
+        try {
+            ve.evaluate(context,writer,"test","$a1 $c1 $a1.length() 
$a1.foobar()");
+            fail ("Expected exception.");
+        } catch (RuntimeException E) {}
+        
+    }
 
     /**
      * Test escaping

Added: 
jakarta/velocity/engine/trunk/src/test/org/apache/velocity/test/InvalidEventHandlerTestCase.java
URL: 
http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/test/org/apache/velocity/test/InvalidEventHandlerTestCase.java?view=auto&rev=463213
==============================================================================
--- 
jakarta/velocity/engine/trunk/src/test/org/apache/velocity/test/InvalidEventHandlerTestCase.java
 (added)
+++ 
jakarta/velocity/engine/trunk/src/test/org/apache/velocity/test/InvalidEventHandlerTestCase.java
 Thu Oct 12 04:52:06 2006
@@ -0,0 +1,472 @@
+package org.apache.velocity.test;
+
+/*
+ * 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.
+ */
+
+import java.io.StringWriter;
+import java.io.Writer;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.app.event.EventCartridge;
+import org.apache.velocity.app.event.InvalidReferenceEventHandler;
+import org.apache.velocity.context.Context;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.RuntimeServices;
+import org.apache.velocity.util.RuntimeServicesAware;
+import org.apache.velocity.util.introspection.Info;
+
+/**
+ * Tests event handling for all event handlers except IncludeEventHandler.  
This is tested
+ * separately due to its complexity.
+ *
+ * @author <a href="mailto:[EMAIL PROTECTED]">Geir Magnusson Jr.</a>
+ * @version $Id$
+ */
+public class InvalidEventHandlerTestCase
+extends TestCase
+{
+    /**
+     * Default constructor.
+     */
+    public InvalidEventHandlerTestCase(String name)
+    {
+        super(name);
+    }
+    
+    public static Test suite ()
+    {
+        return new TestSuite(InvalidEventHandlerTestCase.class);
+    }
+    
+    public void testManualEventHandlers()
+    throws Exception
+    {
+        TestEventCartridge te = new TestEventCartridge();
+        
+        /**
+         * Test attaching the event cartridge to the context
+         */
+        VelocityEngine ve = new VelocityEngine();
+        ve.init();
+        
+        /*
+         *  lets make a Context and add the event cartridge
+         */
+        
+        VelocityContext inner = new VelocityContext();
+        
+        /*
+         *  Now make an event cartridge, register all the
+         *  event handlers (at once) and attach it to the
+         *  Context
+         */
+        
+        EventCartridge ec = new EventCartridge();
+        ec.addEventHandler(te);
+        ec.attachToContext( inner );
+        
+        doTestInvalidReferenceEventHandler1(ve, inner);
+        doTestInvalidReferenceEventHandler2(ve, inner);
+        doTestInvalidReferenceEventHandler3(ve, inner);
+        doTestInvalidReferenceEventHandler4(ve, inner);
+    }
+
+    /**
+     * Test assigning the event handlers via properties
+     */
+
+    public void testConfigurationEventHandlers()
+            throws Exception
+    {
+        VelocityEngine ve = new VelocityEngine();
+        ve.setProperty(RuntimeConstants.EVENTHANDLER_INVALIDREFERENCES, 
TestEventCartridge.class.getName());
+
+        ve.init();
+        doTestInvalidReferenceEventHandler1(ve, null);
+        doTestInvalidReferenceEventHandler2(ve, null);
+        doTestInvalidReferenceEventHandler3(ve, null);
+        doTestInvalidReferenceEventHandler4(ve, null);
+    }
+
+    /**
+     * Test deeper structures
+     * @param ve
+     * @param vc
+     * @throws Exception
+     */
+    private void doTestInvalidReferenceEventHandler4(VelocityEngine ve, 
VelocityContext vc)
+    throws Exception
+    {
+        VelocityContext context = new VelocityContext(vc);
+
+        Tree test = new Tree();
+        test.setField("10");
+        Tree test2 = new Tree();
+        test2.setField("12");
+        test.setChild(test2);
+        
+        context.put("tree",test);
+        String s;
+        Writer w;
+        
+        // show work fine
+        s = "$tree.Field $tree.field $tree.child.Field";
+        w = new StringWriter();
+        ve.evaluate( context, w, "mystring", s );
+        
+        s = "$tree.x $tree.field.x $tree.child.y $tree.child.Field.y";
+        w = new StringWriter();
+        ve.evaluate( context, w, "mystring", s );
+        
+    }
+    
+    /**
+     * Test invalid #set
+     * @param ve
+     * @param vc
+     * @throws Exception
+     */
+    private void doTestInvalidReferenceEventHandler3(VelocityEngine ve, 
VelocityContext vc)
+    throws Exception
+    {
+        VelocityContext context = new VelocityContext(vc);
+        context.put("a1",new Integer(5));
+        context.put("a4",new Integer(5));
+        context.put("b1","abc");
+        
+        String s;
+        Writer w;
+        
+        // good object, bad right hand side
+        s = "#set($xx = $a1.afternoon())";
+        w = new StringWriter();
+        try {
+            ve.evaluate( context, w, "mystring", s );
+            fail("Expected exception.");
+        } catch (RuntimeException e) {}
+        
+        // good object, bad right hand reference
+        s = "#set($yy = $q1)";
+        w = new StringWriter();
+        try {
+            ve.evaluate( context, w, "mystring", s );
+            fail("Expected exception.");
+        } catch (RuntimeException e) {}
+        
+    }
+
+    /**
+     * Test invalid method calls
+     * @param ve
+     * @param vc
+     * @throws Exception
+     */
+    private void doTestInvalidReferenceEventHandler2(VelocityEngine ve, 
VelocityContext vc)
+    throws Exception
+    {
+        VelocityContext context = new VelocityContext(vc);
+        context.put("a1",new Integer(5));
+        context.put("a4",new Integer(5));
+        context.put("b1","abc");
+        
+        String s;
+        Writer w;
+        
+        // good object, bad method
+        s = "$a1.afternoon()";
+        w = new StringWriter();
+        try {
+            ve.evaluate( context, w, "mystring", s );
+            fail("Expected exception.");
+        } catch (RuntimeException e) {}
+        
+        // bad object, bad method -- fails on get
+        s = "$zz.daylight()";
+        w = new StringWriter();
+        try {
+            ve.evaluate( context, w, "mystring", s );
+            fail("Expected exception.");
+        } catch (RuntimeException e) {}
+
+        // change result
+        s = "$b1.baby()";
+        w = new StringWriter();
+        ve.evaluate( context, w, "mystring", s );
+        assertEquals("www",w.toString());        
+    }
+    
+    /**
+     * Test invalid gets/references
+     * @param ve
+     * @param vc
+     * @throws Exception
+     */
+    private void doTestInvalidReferenceEventHandler1(VelocityEngine ve, 
VelocityContext vc)
+    throws Exception
+    {
+        String result;
+        
+        VelocityContext context = new VelocityContext(vc);
+        context.put("a1",new Integer(5));
+        context.put("a4",new Integer(5));
+        context.put("b1","abc");
+        
+        // normal - should be no calls to handler
+        String s = "$a1 $a1.intValue() $b1 $b1.length() #set($c1 = '5')";
+        Writer w = new StringWriter();
+        ve.evaluate( context, w, "mystring", s );
+        
+        // good object, bad property
+        s = "$a1.foobar";
+        w = new StringWriter();
+        try {
+            ve.evaluate( context, w, "mystring", s );
+            fail("Expected exception.");
+        } catch (RuntimeException e) {}
+        
+        // bad object, bad property            
+        s = "$a2.foobar";
+        w = new StringWriter();
+        try {
+            ve.evaluate( context, w, "mystring", s );
+            fail("Expected exception.");
+        } catch (RuntimeException e) {}
+        
+        // bad object, no property            
+        s = "$a3";
+        w = new StringWriter();
+        try {
+            ve.evaluate( context, w, "mystring", s );
+            fail("Expected exception.");
+        } catch (RuntimeException e) {}
+        
+        // good object, bad property; change the value
+        s = "$a4.foobar";
+        w = new StringWriter();
+        ve.evaluate( context, w, "mystring", s );
+        result = w.toString();
+        assertEquals("zzz", result);
+        
+    }
+    
+    
+
+    /**
+     * Test assigning the event handlers via properties
+     */
+    
+    public static class TestEventCartridge
+    implements InvalidReferenceEventHandler,
+    RuntimeServicesAware
+    {
+        private RuntimeServices rs;
+        
+        public TestEventCartridge()
+        {
+        }
+        
+        /**
+         * Required by EventHandler
+         */
+        public void setRuntimeServices( RuntimeServices rs )
+        {
+            // make sure this is only called once
+            if (this.rs == null)
+                this.rs = rs;
+            
+            else
+                fail("initialize called more than once.");
+        }
+        
+        
+        public Object invalidGetMethod(Context context, String reference, 
Object object, String property, Info info)
+        {
+            // as a test, make sure this EventHandler is initialized
+            if (rs == null)
+                fail ("Event handler not initialized!");
+            
+            // good object, bad property
+            if (reference.equals("$a1.foobar"))
+            {
+                assertEquals(new Integer(5),object);
+                assertEquals("foobar",property);
+                throw new RuntimeException("expected exception");
+            }
+            
+            // bad object, bad property            
+            else if (reference.equals("$a2"))
+            {
+                assertNull(object);
+                assertNull(property);
+                throw new RuntimeException("expected exception");
+            }
+            
+            // bad object, no property            
+            else if (reference.equals("$a3"))
+            {
+                assertNull(object);
+                assertNull(property);
+                throw new RuntimeException("expected exception");
+            }
+            
+            // good object, bad property; change the value
+            else if (reference.equals("$a4.foobar"))
+            {
+                assertEquals(new Integer(5),object);
+                assertEquals("foobar",property);
+                return "zzz";
+            }
+
+            // bad object, bad method -- fail on the object
+            else if (reference.equals("$zz"))
+            {
+                assertNull(object);
+                assertNull(property);
+                throw new RuntimeException("expected exception");
+            }
+
+            // pass q1 through
+            else if (reference.equals("$q1"))
+            {
+
+            }
+
+            
+            else if (reference.equals("$tree.x"))
+            {
+                assertEquals("x",property);
+            }
+
+            else if (reference.equals("$tree.field.x"))
+            {
+                assertEquals("x",property);
+            }
+
+            else if (reference.equals("$tree.child.y"))
+            {
+                assertEquals("y",property);
+            }
+            
+            else if (reference.equals("$tree.child.Field.y"))
+            {
+                assertEquals("y",property);
+            }
+            
+            else
+            {
+                fail("invalidGetMethod: unexpected reference: " + reference);
+            }
+            return null;
+        }
+        
+        public Object invalidMethod(Context context, String reference, Object 
object, String method, Info info)
+        {
+            // as a test, make sure this EventHandler is initialized
+            if (rs == null)
+                fail ("Event handler not initialized!");
+
+            // good reference, bad method
+            if (object.getClass().equals(Integer.class))
+            {
+                assertEquals("$a1.afternoon()",reference);
+                assertEquals("afternoon",method);
+                throw new RuntimeException("expected exception");
+            }
+
+            else if (object.getClass().equals(String.class) && 
"baby".equals(method))
+            {
+                return "www";
+            }
+
+            else
+            { 
+                fail("Unexpected invalid method.  " + method);
+            }
+
+            return null;
+        }        
+    
+
+        public boolean invalidSetMethod(Context context, String leftreference, 
String rightreference, Info info)
+        {
+
+            // as a test, make sure this EventHandler is initialized
+            if (rs == null)
+                fail ("Event handler not initialized!");
+
+            // good object, bad method
+            if (leftreference.equals("xx"))
+            {
+                assertEquals("q1.afternoon()",rightreference);
+                throw new RuntimeException("expected exception");
+            }
+            if (leftreference.equals("yy"))
+            {
+                assertEquals("$q1",rightreference);
+                throw new RuntimeException("expected exception");
+            }
+            else
+            { 
+                fail("Unexpected left hand side.  " + leftreference);
+            }
+            
+            return false;
+        }
+
+    }
+
+    public static class Tree
+    {
+        String field;
+        Tree child;
+        
+        public Tree()
+        {
+            
+        }
+
+        public String getField()
+        {
+            return field;
+        }
+
+        public void setField(String field)
+        {
+            this.field = field;
+        }
+
+        public Tree getChild()
+        {
+            return child;
+        }
+
+        public void setChild(Tree child)
+        {
+            this.child = child;
+        }
+
+        public String testMethod() 
+        {
+            return "123";
+        }
+    }
+    
+}

Propchange: 
jakarta/velocity/engine/trunk/src/test/org/apache/velocity/test/InvalidEventHandlerTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
jakarta/velocity/engine/trunk/src/test/org/apache/velocity/test/InvalidEventHandlerTestCase.java
------------------------------------------------------------------------------
    svn:keywords = Id Author Date Revision



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to