cocoon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sylv...@apache.org
Subject svn commit: r232400 [1/2] - in /cocoon/branches/BRANCH_2_1_X/src: java/org/apache/cocoon/ java/org/apache/cocoon/components/flow/javascript/ java/org/apache/cocoon/components/pipeline/ java/org/apache/cocoon/components/treeprocessor/ java/org/apache/co...
Date Fri, 12 Aug 2005 22:14:53 GMT
Author: sylvain
Date: Fri Aug 12 15:14:26 2005
New Revision: 232400

URL: http://svn.apache.org/viewcvs?rev=232400&view=rev
Log:
More Cocoon stacktraces: add description of statements in locations, dump pipeline, reduce exception nesting

Added:
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/util/location/LocationImpl.java   (with props)
Modified:
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/ProcessingException.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/flow/javascript/LocationTrackingDebugger.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/pipeline/AbstractProcessingPipeline.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNode.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNodeBuilder.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/ProcessingNode.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/CallFunctionNode.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/FlowNode.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/MountNode.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SerializeNode.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/variables/VariableResolver.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/generation/ExceptionGenerator.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/generation/JXTemplateGenerator.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/sitemap/SitemapParameters.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/transformation/BrowserUpdateTransformer.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/util/ExceptionUtils.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/util/location/Locatable.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/util/location/LocatableException.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/util/location/LocatedException.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/util/location/LocatedRuntimeException.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/util/location/Location.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/util/location/LocationAttributes.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/util/location/LocatorToAttributesPipe.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/util/location/MultiLocatable.java
    cocoon/branches/BRANCH_2_1_X/src/webapp/stylesheets/system/exception2html.xslt

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/ProcessingException.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/ProcessingException.java?rev=232400&r1=232399&r2=232400&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/ProcessingException.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/ProcessingException.java Fri Aug 12 15:14:26 2005
@@ -15,11 +15,10 @@
  */
 package org.apache.cocoon;
 
-import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.cocoon.util.ExceptionUtils;
 import org.apache.cocoon.util.location.LocatedException;
+import org.apache.cocoon.util.location.LocatedRuntimeException;
 import org.apache.cocoon.util.location.Location;
 import org.apache.cocoon.util.location.MultiLocatable;
 
@@ -65,14 +64,87 @@
         super(message, t, location);
     }
     
-    public static ProcessingException getLocatedException(String description, Throwable thr, Location location) {
+    /**
+     * Throw a located exception given an existing exception and the location where
+     * this exception was catched.
+     * <p>
+     * If the exception is already a <code>ProcessingException</code> or a {@link LocatedRuntimeException},
+     * the location is added to the original exception's location chain and the original exception
+     * is rethrown (<code>description</code> is ignored) to limit exception nesting. Otherwise, a new
+     * <code>ProcessingException</code> is thrown, wrapping the original exception.
+     * <p>
+     * Note: this method returns an exception as a convenience if you want to keep the <code>throw</code>
+     * semantics in the caller code, i.e. write<br>
+     * <code>&nbsp;&nbsp;throw ProcessingException.throwLocated(...);</code><br>
+     * instead of<br>
+     * <code>&nbsp;&nbsp;ProcessingException.throwLocated(...);</code><br>
+     * <code>&nbsp;&nbsp;return;</code>
+     * 
+     * @param message a message (can be <code>null</code>)
+     * @param thr the original exception (can be <code>null</code>)
+     * @param location the location (can be <code>null</code>)
+     * @return a (fake) located exception
+     * @throws ProcessingException or <code>LocatedRuntimeException</code>
+     */
+    public static ProcessingException throwLocated(String message, Throwable thr, Location location) throws ProcessingException {
         if (thr instanceof ProcessingException) {
             ProcessingException pe = (ProcessingException)thr;
             pe.addLocation(location);
-            return pe;
+            throw pe;
+
+        } else if (thr instanceof LocatedRuntimeException) {
+            LocatedRuntimeException re = (LocatedRuntimeException)thr;
+            re.addLocation(location);
+            // Rethrow
+            throw re;
         }
         
-        return new ProcessingException(description, thr, location);
+        throw new ProcessingException(message, thr, location);
+    }
+    
+    /**
+     * Throw a located exception given an existing exception and the locations where
+     * this exception was catched.
+     * <p>
+     * If the exception is already a <code>ProcessingException</code> or a {@link LocatedRuntimeException},
+     * the locations are added to the original exception's location chain and the original exception
+     * is rethrown (<code>description</code> is ignored) to limit exception nesting. Otherwise, a new
+     * <code>ProcessingException</code> is thrown, wrapping the original exception.
+     * <p>
+     * Note: this method returns an exception as a convenience if you want to keep the <code>throw</code>
+     * semantics in the caller code, i.e. write<br>
+     * <code>&nbsp;&nbsp;throw ProcessingException.throwLocated(...);</code><br>
+     * instead of<br>
+     * <code>&nbsp;&nbsp;ProcessingException.throwLocated(...);</code><br>
+     * <code>&nbsp;&nbsp;return;</code>
+     * 
+     * @param message a message (can be <code>null</code>)
+     * @param thr the original exception (can be <code>null</code>)
+     * @param locations the locations (can be <code>null</code>)
+     * @return a (fake) located exception
+     * @throws ProcessingException or <code>LocatedRuntimeException</code>
+     */
+    public static ProcessingException throwLocated(String message, Throwable thr, List locations) throws ProcessingException {
+        MultiLocatable multiloc;
+        if (thr instanceof ProcessingException) {
+            multiloc = (ProcessingException)thr;
+        } else if (thr instanceof LocatedRuntimeException) {
+            multiloc = (LocatedRuntimeException)thr;
+        } else {
+            multiloc = new ProcessingException(message, thr);
+        }
+        
+        if (locations != null) {
+            for (int i = 0; i < locations.size(); i++) {
+                multiloc.addLocation((Location)locations.get(i));
+            }
+        }
+        
+        if (multiloc instanceof LocatedRuntimeException) {
+            throw (LocatedRuntimeException)multiloc;
+        } else {
+            throw (ProcessingException)multiloc;
+        }
     }
 
 

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/flow/javascript/LocationTrackingDebugger.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/flow/javascript/LocationTrackingDebugger.java?rev=232400&r1=232399&r2=232400&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/flow/javascript/LocationTrackingDebugger.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/flow/javascript/LocationTrackingDebugger.java Fri Aug 12 15:14:26 2005
@@ -19,10 +19,10 @@
 import java.util.List;
 
 import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.util.ExceptionUtils;
 import org.apache.cocoon.util.location.Location;
+import org.apache.cocoon.util.location.LocationImpl;
 import org.mozilla.javascript.Context;
-import org.mozilla.javascript.JavaScriptException;
-import org.mozilla.javascript.NativeFunction;
 import org.mozilla.javascript.Scriptable;
 import org.mozilla.javascript.debug.DebugFrame;
 import org.mozilla.javascript.debug.DebuggableScript;
@@ -36,6 +36,7 @@
  * This debugger implementation is designed to be as lightweight and fast as possible, in order to have a
  * negligible impact on the performances of the Rhino interpreter.
  * 
+ * @since 2.1.8
  * @version $Id$
  */
 public class LocationTrackingDebugger implements Debugger {
@@ -68,7 +69,7 @@
      * Rhino 1.6 API
      */
     public DebugFrame getFrame(Context cx, DebuggableScript fnOrScript) {
-        // Rhion 1.6 API
+        // Rhino 1.6 API
         return new StackTrackingFrame(fnOrScript);
     }
 
@@ -79,27 +80,21 @@
      * @param originalException the original exception
      * 
      * @return a suitable exception to throw
-     * @see ProcessingException#getLocatedException(String, Throwable, Location)
+     * @see ProcessingException#throwLocated(String, Throwable, Location)
      */
-    public Exception getException(String description, Exception originalException) {
+    public Exception getException(String description, Exception originalException) throws ProcessingException {
         if (throwable == null || locations == null) {
             // Cannot to better for now
             return originalException;
         }
 
-        // Unwrap JavaScriptException
-        if (throwable instanceof JavaScriptException) {
-            Throwable cause = ((JavaScriptException)throwable).getWrappedException();
-            if (cause != null)
-                throwable = cause;
-        }
-        
-        ProcessingException pe = ProcessingException.getLocatedException(description, throwable, null);
-        for (int i = 0; i < locations.size(); i++) {
-            pe.addLocation((Location)locations.get(i));
-        }
-        
-        return pe;
+        // Unwrap original exception, if any, wrapped by Rhino (the wrapping
+        // class is different in Rhino+cont and Rhino 1.6)
+        Throwable cause = ExceptionUtils.getCause(throwable);
+        if (cause != null)
+            throwable = cause;
+
+        return ProcessingException.throwLocated(description, throwable, locations);
     }
 
     private class StackTrackingFrame implements DebugFrame {
@@ -131,9 +126,10 @@
 
         public void onExit(Context cx, boolean byThrow, Object resultOrException) {
             if (byThrow) {
+                  String name = null;
 // Revisit: Rhino+cont and Rhino 1.6 have different debugger APIs, and we currently don't use this information
 //                Scriptable obj = script.getScriptable();
-//                String name = obj instanceof NativeFunction ? ((NativeFunction)obj).getFunctionName() : "Top-level script";
+//                name = obj instanceof NativeFunction ? ((NativeFunction)obj).getFunctionName() : "Top-level script";
 //                if (name == null || name.length() == 0) {
 //                    name = "[unnamed]";
 //                }
@@ -142,7 +138,7 @@
                     locations = new ArrayList(1); // start small
                 }
 
-                locations.add(new Location(script.getSourceName(), line, -1));
+                locations.add(new LocationImpl(name, script.getSourceName(), line, -1));
 
             } else if (locations != null) {
                 // The exception was handled by the script: clear any recorded locations

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/pipeline/AbstractProcessingPipeline.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/pipeline/AbstractProcessingPipeline.java?rev=232400&r1=232399&r2=232400&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/pipeline/AbstractProcessingPipeline.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/pipeline/AbstractProcessingPipeline.java Fri Aug 12 15:14:26 2005
@@ -15,6 +15,14 @@
  */
 package org.apache.cocoon.components.pipeline;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
 import org.apache.avalon.excalibur.pool.Recyclable;
 import org.apache.avalon.framework.component.Component;
 import org.apache.avalon.framework.component.ComponentException;
@@ -24,7 +32,6 @@
 import org.apache.avalon.framework.parameters.ParameterException;
 import org.apache.avalon.framework.parameters.Parameterizable;
 import org.apache.avalon.framework.parameters.Parameters;
-
 import org.apache.cocoon.ConnectionResetException;
 import org.apache.cocoon.ProcessingException;
 import org.apache.cocoon.components.CocoonComponentManager;
@@ -36,23 +43,17 @@
 import org.apache.cocoon.serialization.Serializer;
 import org.apache.cocoon.sitemap.SitemapErrorHandler;
 import org.apache.cocoon.sitemap.SitemapModelComponent;
-import org.apache.cocoon.sitemap.SitemapParameters;
 import org.apache.cocoon.transformation.Transformer;
+import org.apache.cocoon.util.location.Locatable;
+import org.apache.cocoon.util.location.LocatedRuntimeException;
+import org.apache.cocoon.util.location.Location;
+import org.apache.cocoon.util.location.MultiLocatable;
+import org.apache.cocoon.xml.SaxBuffer;
 import org.apache.cocoon.xml.XMLConsumer;
 import org.apache.cocoon.xml.XMLProducer;
-import org.apache.cocoon.xml.SaxBuffer;
-
 import org.apache.excalibur.source.SourceValidity;
 import org.xml.sax.SAXException;
 
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.net.SocketException;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import java.util.StringTokenizer;
-
 /**
  * This is the base for all implementations of a <code>ProcessingPipeline</code>.
  *
@@ -219,22 +220,22 @@
     public void setGenerator(String role, String source, Parameters param, Parameters hintParam)
     throws ProcessingException {
         if (this.generator != null) {
-            throw new ProcessingException ("Generator already set. Cannot set generator '" + role +
-                                           "' at " + getLocation(param));
+            throw new ProcessingException ("Generator already set. Cannot set generator '" + role + "'",
+                    getLocation(param));
         }
         if (this.reader != null) {
-            throw new ProcessingException ("Reader already set. Cannot set generator '" + role +
-                                           "' at " + getLocation(param));
+            throw new ProcessingException ("Reader already set. Cannot set generator '" + role + "'",
+                    getLocation(param));
         }
         try {
             this.generatorSelector = (ComponentSelector) this.newManager.lookup(Generator.ROLE + "Selector");
         } catch (ComponentException ce) {
-            throw new ProcessingException("Lookup of generator selector failed at " +getLocation(param), ce);
+            throw new ProcessingException("Lookup of generator selector failed", ce, getLocation(param));
         }
         try {
             this.generator = (Generator) this.generatorSelector.select(role);
         } catch (ComponentException ce) {
-            throw new ProcessingException("Lookup of generator '" + role + "' failed at " + getLocation(param), ce);
+            throw new ProcessingException("Lookup of generator '" + role + "' failed", ce, getLocation(param));
         }
         this.generatorSource = source;
         this.generatorParam = param;
@@ -256,24 +257,24 @@
     throws ProcessingException {
         if (this.reader != null) {
             // Should normally never happen as setting a reader starts pipeline processing
-            throw new ProcessingException ("Reader already set. Cannot add transformer '" + role +
-                                           "' at " + getLocation(param));
+            throw new ProcessingException ("Reader already set. Cannot add transformer '" + role + "'",
+                    getLocation(param));
         }
         if (this.generator == null) {
-            throw new ProcessingException ("Must set a generator before adding transformer '" + role +
-                                           "' at " + getLocation(param));
+            throw new ProcessingException ("Must set a generator before adding transformer '" + role + "'",
+                    getLocation(param));
         }
         ComponentSelector selector = null;
         try {
             selector = (ComponentSelector) this.newManager.lookup(Transformer.ROLE + "Selector");
         } catch (ComponentException ce) {
-            throw new ProcessingException("Lookup of transformer selector failed at " + getLocation(param), ce);
+            throw new ProcessingException("Lookup of transformer selector failed", ce, getLocation(param));
         }
         try {
             this.transformers.add(selector.select(role));
             this.transformerSelectors.add(selector);
         } catch (ComponentException ce) {
-            throw new ProcessingException("Lookup of transformer '"+role+"' failed at " + getLocation(param), ce);
+            throw new ProcessingException("Lookup of transformer '"+role+"' failed", ce, getLocation(param));
         }
         this.transformerSources.add(source);
         this.transformerParams.add(param);
@@ -287,28 +288,28 @@
     throws ProcessingException {
         if (this.serializer != null) {
             // Should normally not happen as adding a serializer starts pipeline processing
-            throw new ProcessingException ("Serializer already set. Cannot set serializer '" + role +
-                                           "' at " + getLocation(param));
+            throw new ProcessingException ("Serializer already set. Cannot set serializer '" + role + "'",
+                    getLocation(param));
         }
         if (this.reader != null) {
             // Should normally never happen as setting a reader starts pipeline processing
-            throw new ProcessingException ("Reader already set. Cannot set serializer '" + role +
-                                           "' at " + getLocation(param));
+            throw new ProcessingException ("Reader already set. Cannot set serializer '" + role + "'",
+                    getLocation(param));
         }
         if (this.generator == null) {
-            throw new ProcessingException ("Must set a generator before setting serializer '" + role +
-                                           "' at " + getLocation(param));
+            throw new ProcessingException ("Must set a generator before setting serializer '" + role + "'",
+                    getLocation(param));
         }
 
         try {
             this.serializerSelector = (OutputComponentSelector) this.newManager.lookup(Serializer.ROLE + "Selector");
         } catch (ComponentException ce) {
-            throw new ProcessingException("Lookup of serializer selector failed at " + getLocation(param), ce);
+            throw new ProcessingException("Lookup of serializer selector failed", ce, getLocation(param));
         }
         try {
             this.serializer = (Serializer)serializerSelector.select(role);
         } catch (ComponentException ce) {
-            throw new ProcessingException("Lookup of serializer '" + role + "' failed at " + getLocation(param), ce);
+            throw new ProcessingException("Lookup of serializer '" + role + "' failed", ce, getLocation(param));
         }
         this.serializerSource = source;
         this.serializerParam = param;
@@ -325,24 +326,24 @@
     throws ProcessingException {
         if (this.reader != null) {
             // Should normally never happen as setting a reader starts pipeline processing
-            throw new ProcessingException ("Reader already set. Cannot set reader '" + role +
-                                           "' at " + getLocation(param));
+            throw new ProcessingException ("Reader already set. Cannot set reader '" + role + "'",
+                    getLocation(param));
         }
         if (this.generator != null) {
             // Should normally never happen as setting a reader starts pipeline processing
-            throw new ProcessingException ("Generator already set. Cannot use reader '" + role +
-                                           "' at " + getLocation(param));
+            throw new ProcessingException ("Generator already set. Cannot use reader '" + role + "'",
+                    getLocation(param));
         }
 
         try {
             this.readerSelector = (OutputComponentSelector) this.newManager.lookup(Reader.ROLE + "Selector");
         } catch (ComponentException ce) {
-            throw new ProcessingException("Lookup of reader selector failed at " + getLocation(param), ce);
+            throw new ProcessingException("Lookup of reader selector failed", ce, getLocation(param));
         }
         try {
             this.reader = (Reader)readerSelector.select(role);
         } catch (ComponentException ce) {
-            throw new ProcessingException("Lookup of reader '"+role+"' failed at " + getLocation(param), ce);
+            throw new ProcessingException("Lookup of reader '"+role+"' failed", ce, getLocation(param));
         }
         this.readerSource = source;
         this.readerParam = param;
@@ -410,10 +411,8 @@
                     this.serializerParam
                 );
             }
-        } catch (SAXException e) {
-            throw new ProcessingException("Could not setup pipeline.", e);
-        } catch (IOException e) {
-            throw new ProcessingException("Could not setup pipeline.", e);
+        } catch (Exception e) {
+            handleException(e);
         }
     }
 
@@ -427,7 +426,7 @@
         // Connect next component.
         producer.setConsumer(consumer);
     }
-
+    
     /**
      * Connect the XML pipeline.
      */
@@ -581,11 +580,8 @@
                     this.generator.generate();
                 }
             }
-        } catch (ProcessingException e) {
-            throw e;
         } catch (Exception e) {
-            // TODO: Unwrap SAXException ?
-            throw ProcessingException.getLocatedException("Failed to execute pipeline.", e, null);
+            handleException(e);
         }
 
         return true;
@@ -603,12 +599,8 @@
 	            // should this checking be done somewhere else??
 	            this.expires = readerParam.getParameterAsLong("expires");
             }
-        } catch (SAXException e){
-            throw new ProcessingException("Failed to execute reader pipeline.", e);
-        } catch (ParameterException e) {
-            throw new ProcessingException("Expires parameter needs to be of type long.",e);
-        } catch (IOException e){
-            throw new ProcessingException("Failed to execute reader pipeline.", e);
+        } catch (Exception e){
+            handleException(e);
         }
     }
 
@@ -911,23 +903,27 @@
         return expires;
     }
 
-    protected String getLocation(Parameters param) {
-        String value = null;
-        if ( param instanceof SitemapParameters ) {
-            value = ((SitemapParameters)param).getStatementLocation();
+    protected Location getLocation(Parameters param) {
+        Location location = null;
+        if (param instanceof Locatable) {
+            location = ((Locatable)param).getLocation();
         }
-        if ( value == null ) {
-            value = "[unknown location]";
+        if (location == null) {
+            location = Location.UNKNOWN;
         }
-        return value;
+        return location;
     }
 
     /**
      * Handles exception which can happen during pipeline processing.
+     * If this not a connection reset, then all locations for pipeline components are
+     * added to the exception.
+     * 
      * @throws ConnectionResetException if connection reset detected
      * @throws ProcessingException in all other cases
      */
     protected void handleException(Exception e) throws ProcessingException {
+        // Check if the client aborted the connection
         if (e instanceof SocketException) {
             if (e.getMessage().indexOf("reset") > 0
                     || e.getMessage().indexOf("aborted") > 0
@@ -939,10 +935,26 @@
             if (e.getClass().getName().endsWith("ClientAbortException")) {
                 throw new ConnectionResetException("Connection reset by peer", e);
             }
-        } else if (e instanceof ProcessingException) {
-            throw (ProcessingException) e;
-        }
+        } else if (e instanceof ConnectionResetException) {
+            // Exception comes up from a deeper pipeline
+            throw (ConnectionResetException)e;
+        }
+        
+        // Not a connection reset: add all location information        
+        if (this.reader == null) {
+            // Add all locations in reverse order
+            ArrayList locations = new ArrayList(this.transformers.size() + 2);
+            locations.add(getLocation(this.serializerParam));
+            for (int i = this.transformerParams.size() - 1; i >= 0; i--) {
+                locations.add(getLocation((Parameters)this.transformerParams.get(i)));
+            }
+            locations.add(getLocation(this.generatorParam));
+            
+            throw ProcessingException.throwLocated("Failed to process pipeline", e, locations);
 
-        throw new ProcessingException("Error executing pipeline.", e);
+        } else {
+            // Add reader location
+            throw ProcessingException.throwLocated("Failed to process reader", e, getLocation(this.readerParam));
+        }
     }
 }

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNode.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNode.java?rev=232400&r1=232399&r2=232400&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNode.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNode.java Fri Aug 12 15:14:26 2005
@@ -19,6 +19,7 @@
 
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
 import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.util.location.Location;
 
 /**
  *
@@ -28,7 +29,7 @@
 
 public abstract class AbstractProcessingNode extends AbstractLogEnabled implements ProcessingNode {
 
-    protected String location = "unknown location";
+    protected Location location = Location.UNKNOWN;
 
     /**
      * Get the <code>SourceResolver</code> in an object model.
@@ -40,14 +41,14 @@
     /**
      * Get the location of this node.
      */
-    public String getLocation() {
+    public Location getLocation() {
         return this.location;
     }
 
     /**
      * Set the location of this node.
      */
-    public void setLocation(String location) {
+    public void setLocation(Location location) {
         this.location = location;
     }
 }

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNodeBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNodeBuilder.java?rev=232400&r1=232399&r2=232400&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNodeBuilder.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNodeBuilder.java Fri Aug 12 15:14:26 2005
@@ -61,41 +61,6 @@
     }
 
     /**
-     * Get &lt;xxx:parameter&gt; elements as a <code>Map</code> of </code>ListOfMapResolver</code>s,
-     * that can be turned into parameters using <code>ListOfMapResolver.buildParameters()</code>.
-     *
-     * @return the Map of ListOfMapResolver, or <code>null</code> if there are no parameters.
-     */
-    protected Map getParameters(Configuration config) throws ConfigurationException {
-        Configuration[] children = config.getChildren("parameter");
-
-        if (children.length == 0) {
-            // Parameters are only the component's location
-            // TODO Optimize this
-            return new SitemapParameters.ExtendedHashMap(config);
-        }
-
-        Map params = new SitemapParameters.ExtendedHashMap(config, children.length+1);
-        for (int i = 0; i < children.length; i++) {
-            Configuration child = children[i];
-            if (true) { // FIXME : check namespace
-                String name = child.getAttribute("name");
-                String value = child.getAttribute("value");
-                try {
-                    params.put(
-                        VariableResolverFactory.getResolver(name, this.manager),
-                        VariableResolverFactory.getResolver(value, this.manager));
-                } catch(PatternException pe) {
-                    String msg = "Invalid pattern '" + value + " at " + child.getLocation();
-                    throw new ConfigurationException(msg, pe);
-                }
-            }
-        }
-
-        return params;
-    }
-
-    /**
      * Check if the namespace URI of the given configuraition is the same as the
      * one given by the builder.
      */

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java?rev=232400&r1=232399&r2=232400&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java Fri Aug 12 15:14:26 2005
@@ -26,6 +26,7 @@
 import org.apache.avalon.framework.component.ComponentManager;
 import org.apache.avalon.framework.component.ComponentSelector;
 import org.apache.avalon.framework.component.Recomposable;
+import org.apache.avalon.framework.configuration.AbstractConfiguration;
 import org.apache.avalon.framework.configuration.Configurable;
 import org.apache.avalon.framework.configuration.Configuration;
 import org.apache.avalon.framework.configuration.ConfigurationException;
@@ -41,6 +42,8 @@
 import org.apache.cocoon.components.treeprocessor.variables.VariableResolverFactory;
 import org.apache.cocoon.sitemap.PatternException;
 import org.apache.cocoon.sitemap.SitemapParameters;
+import org.apache.cocoon.util.location.Location;
+import org.apache.cocoon.util.location.LocationImpl;
 import org.apache.excalibur.source.Source;
 
 import java.util.ArrayList;
@@ -438,14 +441,15 @@
      */
     public ProcessingNode setupNode(ProcessingNode node, Configuration config)
       throws Exception {
+        Location location = getLocation(config);
         if (node instanceof AbstractProcessingNode) {
-            ((AbstractProcessingNode)node).setLocation(config.getLocation());
+            ((AbstractProcessingNode)node).setLocation(location);
         }
 
         this.lifecycle.setupComponent(node, false);
 
         if (node instanceof ParameterizableProcessingNode) {
-            Map params = getParameters(config);
+            Map params = getParameters(config, location);
             ((ParameterizableProcessingNode)node).setParameters(params);
         }
 
@@ -460,23 +464,56 @@
         return node;
     }
 
+    protected LocationImpl getLocation(Configuration config) {
+        String prefix = "";
+
+        if (config instanceof AbstractConfiguration) {
+            //FIXME: AbstractConfiguration has a _protected_ getPrefix() method.
+            // So make some reasonable guess on the prefix until it becomes public
+            String namespace = null;
+            try {
+                namespace = ((AbstractConfiguration)config).getNamespace();
+            } catch (ConfigurationException e) {
+                // ignore
+            }
+            if ("http://apache.org/cocoon/sitemap/1.0".equals(namespace)) {
+                prefix="map";
+            }
+        }
+        
+        StringBuffer desc = new StringBuffer().append('<');
+        if (prefix.length() > 0) {
+            desc.append(prefix).append(':').append(config.getName());
+        } else {
+            desc.append(config.getName());
+        }
+        String type = config.getAttribute("type", null);
+        if (type != null) {
+            desc.append(" type=\"").append(type).append('"');
+        }
+        desc.append('>');
+        
+        Location rawLoc = LocationImpl.valueOf(config.getLocation());
+        return new LocationImpl(desc.toString(), rawLoc.getURI(), rawLoc.getLineNumber(), rawLoc.getColumnNumber());
+    }
+
     /**
      * Get &lt;xxx:parameter&gt; elements as a <code>Map</code> of </code>ListOfMapResolver</code>s,
      * that can be turned into parameters using <code>ListOfMapResolver.buildParameters()</code>.
      *
      * @return the Map of ListOfMapResolver, or <code>null</code> if there are no parameters.
      */
-    protected Map getParameters(Configuration config) throws ConfigurationException {
+    protected Map getParameters(Configuration config, Location location) throws ConfigurationException {
 
         Configuration[] children = config.getChildren(this.parameterElement);
-
+        
         if (children.length == 0) {
             // Parameters are only the component's location
             // TODO Optimize this
-            return new SitemapParameters.ExtendedHashMap(config);
+            return new SitemapParameters.LocatedHashMap(location, 0);
         }
 
-        Map params = new SitemapParameters.ExtendedHashMap(config, children.length+1);
+        Map params = new SitemapParameters.LocatedHashMap(location, children.length+1);
         for (int i = 0; i < children.length; i++) {
             Configuration child = children[i];
             if (true) { // FIXME : check namespace

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/ProcessingNode.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/ProcessingNode.java?rev=232400&r1=232399&r2=232400&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/ProcessingNode.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/ProcessingNode.java Fri Aug 12 15:14:26 2005
@@ -18,6 +18,8 @@
 import org.apache.avalon.framework.thread.ThreadSafe;
 
 import org.apache.cocoon.environment.Environment;
+import org.apache.cocoon.util.location.Locatable;
+import org.apache.cocoon.util.location.Location;
 
 /**
  *
@@ -25,7 +27,7 @@
  * @version CVS $Id$
  */
 
-public interface ProcessingNode extends ThreadSafe {
+public interface ProcessingNode extends ThreadSafe, Locatable {
 
     /**
      * The key of the <code>SourceResolver</code> in the object model.
@@ -40,5 +42,5 @@
     /**
      * Get the location of this node.
      */
-    String getLocation();
+    Location getLocation();
 }

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/CallFunctionNode.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/CallFunctionNode.java?rev=232400&r1=232399&r2=232400&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/CallFunctionNode.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/CallFunctionNode.java Fri Aug 12 15:14:26 2005
@@ -25,7 +25,6 @@
 import org.apache.avalon.framework.configuration.Configurable;
 import org.apache.avalon.framework.configuration.Configuration;
 import org.apache.avalon.framework.configuration.ConfigurationException;
-
 import org.apache.cocoon.ProcessingException;
 import org.apache.cocoon.components.flow.Interpreter;
 import org.apache.cocoon.components.treeprocessor.AbstractProcessingNode;
@@ -35,7 +34,6 @@
 import org.apache.cocoon.environment.Environment;
 import org.apache.cocoon.environment.Redirector;
 import org.apache.cocoon.sitemap.PatternException;
-import org.apache.cocoon.util.location.Location;
 
 /**
  * Node handler for calling functions and resuming continuations in
@@ -124,10 +122,10 @@
             try {
                 interpreter.handleContinuation(continuation, params, redirector);
             } catch(Exception e) {
-                throw ProcessingException.getLocatedException("Sitemap: error calling continuation", e, Location.parse(getLocation()));
+                throw ProcessingException.throwLocated("Sitemap: error calling continuation", e, getLocation());
             }
             if (!redirector.hasRedirected()) {
-                throw new ProcessingException("Sitemap: <map:call continuation> did not send a response", Location.parse(getLocation()));
+                throw new ProcessingException("Sitemap: <map:call continuation> did not send a response", getLocation());
             }
             return true;
         }
@@ -139,15 +137,15 @@
             try {
                 interpreter.callFunction(name, params, redirector);
             } catch(Exception e) {
-                throw ProcessingException.getLocatedException("Sitemap: error calling function '" + name + "'", e, Location.parse(getLocation()));
+                throw ProcessingException.throwLocated("Sitemap: error calling function '" + name + "'", e, getLocation());
             }
             if (!redirector.hasRedirected()) {
-                throw new ProcessingException("Sitemap: <map:call function> did not send a response", Location.parse(getLocation()));
+                throw new ProcessingException("Sitemap: <map:call function> did not send a response", getLocation());
             }
             return true;
         }
 
         // Found neither continuation nor function to call
-        throw new ProcessingException("Sitemap: no function nor continuation given in <map:call function>", Location.parse(getLocation()));
+        throw new ProcessingException("Sitemap: no function nor continuation given in <map:call function>", getLocation());
     }
 }

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/FlowNode.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/FlowNode.java?rev=232400&r1=232399&r2=232400&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/FlowNode.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/FlowNode.java Fri Aug 12 15:14:26 2005
@@ -61,8 +61,8 @@
             this.interpreterSelector = (ComponentSelector) manager.lookup(Interpreter.ROLE);
             // Obtain the Interpreter instance for this language
             this.interpreter = (Interpreter) this.interpreterSelector.select(language);
-            // Set interpreter ID as location of the flow node (which includes full sitemap file path)
-            this.interpreter.setInterpreterID(this.location);
+            // Set interpreter ID as URI of the flow node (full sitemap file path)
+            this.interpreter.setInterpreterID(this.location.getURI());
         } catch (ComponentException e) {
             throw e;
         } catch (Exception e) {

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/MountNode.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/MountNode.java?rev=232400&r1=232399&r2=232400&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/MountNode.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/MountNode.java Fri Aug 12 15:14:26 2005
@@ -30,7 +30,6 @@
 import org.apache.cocoon.components.treeprocessor.TreeProcessor;
 import org.apache.cocoon.components.treeprocessor.variables.VariableResolver;
 import org.apache.cocoon.environment.Environment;
-import org.apache.cocoon.util.location.Location;
 import org.apache.commons.lang.BooleanUtils;
 
 /**
@@ -119,7 +118,7 @@
             }
         } catch(Exception e) {
             // Wrap with our location
-            throw ProcessingException.getLocatedException("Sitemap: error when calling sub-sitemap", e, Location.parse(getLocation()));
+            throw ProcessingException.throwLocated("Sitemap: error when calling sub-sitemap", e, getLocation());
 
         } finally {
             // We restore the context only if no pipeline was built. This allows the pipeline

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SerializeNode.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SerializeNode.java?rev=232400&r1=232399&r2=232400&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SerializeNode.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SerializeNode.java Fri Aug 12 15:14:26 2005
@@ -19,7 +19,6 @@
 
 import org.apache.avalon.framework.parameters.Parameters;
 import org.apache.cocoon.Constants;
-import org.apache.cocoon.ProcessingException;
 import org.apache.cocoon.components.pipeline.ProcessingPipeline;
 import org.apache.cocoon.components.treeprocessor.InvokeContext;
 import org.apache.cocoon.components.treeprocessor.ParameterizableProcessingNode;
@@ -28,7 +27,6 @@
 import org.apache.cocoon.components.treeprocessor.variables.VariableResolver;
 import org.apache.cocoon.environment.Environment;
 import org.apache.cocoon.sitemap.PatternException;
-import org.apache.cocoon.util.location.Location;
 /**
  *
  * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
@@ -119,12 +117,7 @@
 
         if (! context.isBuildingPipelineOnly()) {
             // Process pipeline
-            try {
-                return pipeline.process(env);
-            } catch(Exception e) {
-                // Indicate error location
-                throw ProcessingException.getLocatedException("Sitemap: error during pipeline execution", e, Location.parse(getLocation()));
-            }
+            return pipeline.process(env);
 
         } else {
             // Return true : pipeline is finished.

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/variables/VariableResolver.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/variables/VariableResolver.java?rev=232400&r1=232399&r2=232400&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/variables/VariableResolver.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/treeprocessor/variables/VariableResolver.java Fri Aug 12 15:14:26 2005
@@ -15,22 +15,23 @@
  */
 package org.apache.cocoon.components.treeprocessor.variables;
 
-import org.apache.avalon.framework.configuration.Configuration;
-import org.apache.avalon.framework.parameters.Parameters;
-import org.apache.cocoon.components.treeprocessor.InvokeContext;
-import org.apache.cocoon.sitemap.PatternException;
-import org.apache.cocoon.sitemap.SitemapParameters;
-
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.cocoon.components.treeprocessor.InvokeContext;
+import org.apache.cocoon.sitemap.PatternException;
+import org.apache.cocoon.sitemap.SitemapParameters;
+import org.apache.cocoon.util.location.Locatable;
+import org.apache.cocoon.util.location.Location;
+
 /**
  * Utility class for handling {...} pattern substitutions in sitemap statements.
  *
  * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
- * @version CVS $Id: VariableResolver.java,v 1.4 2004/03/08 12:07:39 cziegeler Exp $
+ * @version CVS $Id$
  */
 public abstract class VariableResolver {
 
@@ -86,14 +87,19 @@
      * @return a fully resolved <code>Parameters</code>.
      */
     public static Parameters buildParameters(Map expressions, InvokeContext context, Map objectModel) throws PatternException {
-        if (expressions == null || expressions.size() == 0) {
+        Location location;
+        if (expressions instanceof Locatable) {
+            location = ((Locatable)expressions).getLocation();
+        } else {
+            location = Location.UNKNOWN;
+        }
+        
+        if (expressions == null || expressions.size() == 0 && location.equals(Location.UNKNOWN)) {
             return Parameters.EMPTY_PARAMETERS;
         }
 
-        SitemapParameters result = new SitemapParameters();
-        if ( expressions instanceof SitemapParameters.ExtendedHashMap ) {
-            result.setStatementLocation(((SitemapParameters.ExtendedHashMap)expressions).getLocation());    
-        }
+        SitemapParameters result = new SitemapParameters(location);
+
         Iterator iter = expressions.entrySet().iterator();
         while (iter.hasNext()) {
             Map.Entry entry = (Map.Entry)iter.next();
@@ -119,9 +125,8 @@
         }
 
         Map result;
-        if ( expressions instanceof SitemapParameters.ExtendedHashMap ) {
-            Configuration config = ((SitemapParameters.ExtendedHashMap)expressions).getConfiguration();
-            result = new SitemapParameters.ExtendedHashMap(config, size );   
+        if ( expressions instanceof Locatable ) {
+            result = new SitemapParameters.LocatedHashMap(((Locatable)expressions).getLocation(), size);   
         } else {
             result = new HashMap(size);
         }

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/generation/ExceptionGenerator.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/generation/ExceptionGenerator.java?rev=232400&r1=232399&r2=232400&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/generation/ExceptionGenerator.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/generation/ExceptionGenerator.java Fri Aug 12 15:14:26 2005
@@ -33,6 +33,15 @@
 import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
 
+/**
+ * A generator that dumps an XML representation of the exception raised during a pipeline execution.
+ * <p>
+ * The Cocoon stack trace is produced, reflecting all locations the original exception went through,
+ * along with the root exception stacktrace and the full exception stacktrace.
+ * 
+ * @since 2.1.8
+ * @version $Id$
+ */
 public class ExceptionGenerator extends AbstractGenerator {
     
     private Throwable thr;
@@ -60,67 +69,53 @@
         AttributesImpl attr = new AttributesImpl();
         handler.startPrefixMapping("ex", EXCEPTION_NS);
         attr.addCDATAAttribute("class", root.getClass().getName());
-        Location loc = ExceptionUtils.getLocation(root);
+        handler.startElement(EXCEPTION_NS, "exception-report", "ex:exception-report", attr);
+        
+        // Root exception location
+        Location loc = ExceptionUtils.getLocation(root);        
         if (loc != null) {
-            attr.addCDATAAttribute("uri", loc.getURI());
-            attr.addCDATAAttribute("line", Integer.toString(loc.getLine()));
-            attr.addCDATAAttribute("column", Integer.toString(loc.getColumn()));
+            attr.clear();
+            dumpLocation(loc, attr, handler);
         }
-        handler.startElement(EXCEPTION_NS, "exception", "ex:exception", attr);
 
         // Root exception message
         attr.clear();
-        simpleElement("message", attr, root.getMessage(), handler);
+        String message = root instanceof LocatableException ? ((LocatableException)root).getRawMessage() : root.getMessage();
+        simpleElement("message", attr, message, handler);
         
-        // Locations
-        handler.startElement(EXCEPTION_NS, "locations", "ex:locations", attr);
+        // Cocoon stacktrace: dump all located exceptions in the exception stack
+        handler.startElement(EXCEPTION_NS, "cocoon-stacktrace", "ex:cocoon-stacktrace", attr);
         Throwable current = thr;
         while (current != null) {
-            if (current instanceof MultiLocatable) {
-                List locations = ((MultiLocatable)current).getLocations();
-                if (locations != null) {
-                    // Get raw message for LocatableExceptions, message otherwise
-                    String message = current instanceof LocatableException ?
-                            ((LocatableException)current).getRawMessage() :
-                            current.getMessage();
-    
-                    attr.clear();
-                    handler.startElement(EXCEPTION_NS, "location-list", "ex:location-list", attr);
-                    simpleElement("description", attr, message, handler);
-                    for (int i = 0; i < locations.size(); i++) {
+            loc = ExceptionUtils.getLocation(current);
+            if (loc != null) {
+                // One or more locations: dump it
+                handler.startElement(EXCEPTION_NS, "exception", "ex:exception", attr);
+                
+                message = current instanceof LocatableException ? ((LocatableException)current).getRawMessage() : current.getMessage();
+                simpleElement("message", attr, message, handler);
+
+                attr.clear();
+                handler.startElement(EXCEPTION_NS, "locations", "ex:locations", attr);
+                dumpLocation(loc, attr, handler);
+                
+                if (current instanceof MultiLocatable) {
+                    List locations = ((MultiLocatable)current).getLocations();
+                    for (int i = 1; i < locations.size(); i++) { // start at 1 because we already dumped the first one
                         attr.clear();
-                        dumpLocation((Location)locations.get(i), attr, null, handler);
-                    }
-                    handler.endElement(EXCEPTION_NS, "location-list", "ex:location-list");
-                }
-            } else {
-                // Not a MultiLocatable
-                loc = ExceptionUtils.getLocation(current);
-                if (loc != null) {
-                    // Get raw message for LocatableExceptions, message otherwise
-                    String message = current instanceof LocatableException ?
-                            ((LocatableException)current).getRawMessage() :
-                            current.getMessage();
-    
-                    attr.clear();                
-                    dumpLocation(loc, attr, message, handler);
-                    
-                    // Dump additional locations (explains "1" below) if it's a MultiLocatable (e.g. ProcessingException)
-                    if (current instanceof MultiLocatable) {
-                        List locations = ((MultiLocatable)current).getLocations();
-                        for (int i = 1; i < locations.size(); i++) {
-                            attr.clear();
-                            dumpLocation((Location)locations.get(i), attr, null, handler);
-                        }
+                        dumpLocation((Location)locations.get(i), attr, handler);
                     }
                 }
+                handler.endElement(EXCEPTION_NS, "locations", "ex:locations");
+                handler.endElement(EXCEPTION_NS, "exception", "ex:exception");
             }
             
+            
             // Dump parent location
             current = ExceptionUtils.getCause(current);
         }
         
-        handler.endElement(EXCEPTION_NS, "locations", "ex:locations");
+        handler.endElement(EXCEPTION_NS, "cocoon-stacktrace", "ex:cocoon-stacktrace");
         
         // Root exception stacktrace
         attr.clear();
@@ -135,16 +130,15 @@
             simpleElement("full-stacktrace", attr, trace, handler);
         }
         
-        handler.endElement(EXCEPTION_NS, "exception", "ex:exception");
+        handler.endElement(EXCEPTION_NS, "exception-report", "ex:exception-report");
         handler.endPrefixMapping("ex");
     }
     
-    private static void dumpLocation(Location loc, AttributesImpl attr, String message, ContentHandler handler) throws SAXException {
+    private static void dumpLocation(Location loc, AttributesImpl attr, ContentHandler handler) throws SAXException {
         attr.addCDATAAttribute("uri", loc.getURI());
-        attr.addCDATAAttribute("line", Integer.toString(loc.getLine()));
-        attr.addCDATAAttribute("column", Integer.toString(loc.getColumn()));
-        
-        simpleElement("location", attr, message, handler);
+        attr.addCDATAAttribute("line", Integer.toString(loc.getLineNumber()));
+        attr.addCDATAAttribute("column", Integer.toString(loc.getColumnNumber()));        
+        simpleElement("location", attr, loc.getDescription(), handler);
     }
 
     private static void simpleElement(String name, Attributes attr, String value, ContentHandler handler) throws SAXException {

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/generation/JXTemplateGenerator.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/generation/JXTemplateGenerator.java?rev=232400&r1=232399&r2=232400&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/generation/JXTemplateGenerator.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/generation/JXTemplateGenerator.java Fri Aug 12 15:14:26 2005
@@ -56,6 +56,7 @@
 import org.apache.cocoon.transformation.ServiceableTransformer;
 import org.apache.cocoon.util.jxpath.NamespacesTablePointer;
 import org.apache.cocoon.util.location.LocatedRuntimeException;
+import org.apache.cocoon.util.location.Location;
 import org.apache.cocoon.util.location.LocationAttributes;
 import org.apache.cocoon.xml.IncludeXMLConsumer;
 import org.apache.cocoon.xml.NamespacesTable;
@@ -105,7 +106,6 @@
 import org.xml.sax.SAXException;
 import org.xml.sax.ext.LexicalHandler;
 import org.xml.sax.helpers.AttributesImpl;
-import org.xml.sax.helpers.LocatorImpl;
 
 /**
  * @cocoon.sitemap.component.documentation
@@ -125,12 +125,12 @@
     
     // Quick'n dirty hack to replace all SAXParseException by a located runtime exception
     private static final class JXTException extends LocatedRuntimeException {
-        JXTException(String message, Locator loc, Throwable thr) {
-            super(message, thr, LocationAttributes.getLocation(loc));
+        JXTException(String message, Location loc, Throwable thr) {
+            super(message, thr, loc);
         }
         
-        static LocatedRuntimeException get(String message, Locator loc, Throwable thr) {
-            return LocatedRuntimeException.getLocatedException(message, thr, LocationAttributes.getLocation(loc));
+        static LocatedRuntimeException get(String message, Location loc, Throwable thr) {
+            return LocatedRuntimeException.getLocatedException(message, thr, loc);
         }
     }
 
@@ -168,8 +168,6 @@
             }
     };
 
-    private static final Locator NULL_LOCATOR = new LocatorImpl();
-
     private XMLConsumer getConsumer() {
         return this.xmlConsumer;
     }
@@ -202,18 +200,18 @@
     }
 
     /**
-     * Facade to the Locator to be set on the consumer prior to
+     * Facade to the Location to be set on the consumer prior to
      * sending other events, location member changeable
      */
-    public static class LocatorFacade implements Locator {
-        private Locator locator;
+    public static class LocationFacade implements Locator {
+        private Location locator;
 
-        public LocatorFacade(Locator initialLocator) {
-            this.locator = initialLocator;
+        public LocationFacade(Location initialLocation) {
+            this.locator = initialLocation;
         }
 
-        public void setDocumentLocator(Locator newLocator) {
-            this.locator = newLocator;
+        public void setDocumentLocation(Location newLocation) {
+            this.locator = newLocation;
         }
 
         public int getColumnNumber() {
@@ -225,11 +223,11 @@
         }
 
         public String getPublicId() {
-            return this.locator.getPublicId();
+            return null;
         }
 
         public String getSystemId() {
-            return this.locator.getSystemId();
+            return this.locator.getURI();
         }
     }
 
@@ -694,7 +692,7 @@
      * (contained in #{})
      */
 
-    private static JXTExpression compileExpr(String expr, String errorPrefix, Locator location) throws JXTException {
+    private static JXTExpression compileExpr(String expr, String errorPrefix, Location location) throws JXTException {
         try {
             return compileExpr(expr);
         } catch (Exception exc) {
@@ -751,7 +749,7 @@
      * Compile an integer expression (returns either a Compiled Expression
      * or an Integer literal)
      */
-    private static JXTExpression compileInt(String val, String msg, Locator location) throws SAXException {
+    private static JXTExpression compileInt(String val, String msg, Location location) throws SAXException {
         JXTExpression res = compileExpr(val, msg, location);
         if (res != null) {
             if (res.compiledExpression == null) {
@@ -762,7 +760,7 @@
         return null;
     }
 
-    private static JXTExpression compileBoolean(String val, String msg, Locator location) throws SAXException {
+    private static JXTExpression compileBoolean(String val, String msg, Location location) throws SAXException {
         JXTExpression res = compileExpr(val, msg, location);
         if (res != null) {
             if (res.compiledExpression == null) {
@@ -910,29 +908,19 @@
     }
 
     static class Event {
-        final Locator location;
+        final Location location;
         Event next; // in document order
-        Event(Locator locator) {
-            this.location = locator != null ? new LocatorImpl(locator) : NULL_LOCATOR;
+        Event(Location locator) {
+            this.location = locator != null ? locator : Location.UNKNOWN;
         }
 
         public String locationString() {
-            StringBuffer buf = new StringBuffer();
-            buf.append(location.getSystemId());
-            if (buf.length() > 0) {
-                buf.append(", ");
-            }
-            buf.append("Line " + location.getLineNumber());
-            int col = location.getColumnNumber();
-            if (col > 0) {
-                buf.append("." + col);
-            }
-            return buf.toString();
+            return location.toString();
         }
     }
 
     static class TextEvent extends Event {
-        TextEvent(Locator location, char[] chars, int start, int length)
+        TextEvent(Location location, char[] chars, int start, int length)
                                                           throws SAXException {
             super(location);
             StringBuffer buf = new StringBuffer();
@@ -1016,13 +1004,13 @@
     }
 
     static class Characters extends TextEvent {
-        Characters(Locator location, char[] chars, int start, int length) throws SAXException {
+        Characters(Location location, char[] chars, int start, int length) throws SAXException {
             super(location, chars, start, length);
         }
     }
 
     static class StartDocument extends Event {
-        StartDocument(Locator location) {
+        StartDocument(Location location) {
             super(location);
             templateProperties = new HashMap();
         }
@@ -1032,13 +1020,13 @@
     }
 
     static class EndDocument extends Event {
-        EndDocument(Locator location) {
+        EndDocument(Location location) {
             super(location);
         }
     }
 
     static class EndElement extends Event {
-        EndElement(Locator location, StartElement startElement) {
+        EndElement(Location location, StartElement startElement) {
             super(location);
             this.startElement = startElement;
         }
@@ -1046,7 +1034,7 @@
     }
 
     static class EndPrefixMapping extends Event {
-        EndPrefixMapping(Locator location, String prefix) {
+        EndPrefixMapping(Location location, String prefix) {
             super(location);
             this.prefix = prefix;
         }
@@ -1054,13 +1042,13 @@
     }
 
     static class IgnorableWhitespace extends TextEvent {
-        IgnorableWhitespace(Locator location, char[] chars, int start, int length) throws SAXException {
+        IgnorableWhitespace(Location location, char[] chars, int start, int length) throws SAXException {
             super(location, chars, start, length);
         }
     }
 
     static class ProcessingInstruction extends Event {
-        ProcessingInstruction(Locator location, String target, String data) {
+        ProcessingInstruction(Location location, String target, String data) {
             super(location);
             this.target = target;
             this.data = data;
@@ -1070,7 +1058,7 @@
     }
 
     static class SkippedEntity extends Event {
-        SkippedEntity(Locator location, String name) {
+        SkippedEntity(Location location, String name) {
             super(location);
             this.name = name;
         }
@@ -1127,7 +1115,7 @@
     }
 
     static class StartElement extends Event {
-        StartElement(Locator location, String namespaceURI, String localName,
+        StartElement(Location location, String namespaceURI, String localName,
                             String raw, Attributes attrs) throws SAXException {
             super(location);
             this.namespaceURI = namespaceURI;
@@ -1227,7 +1215,7 @@
     }
 
     static class StartPrefixMapping extends Event {
-        StartPrefixMapping(Locator location, String prefix, String uri) {
+        StartPrefixMapping(Location location, String prefix, String uri) {
             super(location);
             this.prefix = prefix;
             this.uri = uri;
@@ -1237,19 +1225,19 @@
     }
 
     static class EndCDATA extends Event {
-        EndCDATA(Locator location) {
+        EndCDATA(Location location) {
             super(location);
         }
     }
 
     static class EndDTD extends Event {
-        EndDTD(Locator location) {
+        EndDTD(Location location) {
             super(location);
         }
     }
 
     static class EndEntity extends Event {
-        EndEntity(Locator location, String name) {
+        EndEntity(Location location, String name) {
             super(location);
             this.name = name;
         }
@@ -1257,13 +1245,13 @@
     }
 
     static class StartCDATA extends Event {
-        StartCDATA(Locator location) {
+        StartCDATA(Location location) {
             super(location);
         }
     }
 
     static class StartDTD extends Event {
-        StartDTD(Locator location, String name, String publicId, String systemId) {
+        StartDTD(Location location, String name, String publicId, String systemId) {
             super(location);
             this.name = name;
             this.publicId = publicId;
@@ -1275,7 +1263,7 @@
     }
 
     static class StartEntity extends Event {
-        public StartEntity(Locator location, String name) {
+        public StartEntity(Location location, String name) {
             super(location);
             this.name = name;
         }
@@ -1292,7 +1280,7 @@
     }
 
     static class EndInstruction extends Event {
-        EndInstruction(Locator locator, StartInstruction startInstruction) {
+        EndInstruction(Location locator, StartInstruction startInstruction) {
             super(locator);
             this.startInstruction = startInstruction;
             startInstruction.endInstruction = this;
@@ -1871,7 +1859,7 @@
         Event lastEvent;
         Stack stack = new Stack();
         Locator locator;
-        Locator charLocation;
+        Location charLocation;
         StringBuffer charBuf;
 
         public Parser() {
@@ -1895,7 +1883,7 @@
         private void addEvent(Event ev) throws SAXException {
             if (ev != null) {
                 if (lastEvent == null) {
-                    lastEvent = startEvent = new StartDocument(locator);
+                    lastEvent = startEvent = new StartDocument(LocationAttributes.getLocation(locator, "template"));
                 } else {
                     flushChars();
                 }
@@ -1922,14 +1910,14 @@
             throws SAXException {
             if (charBuf == null) {
                 charBuf = new StringBuffer(length);
-                charLocation = locator != null ? new LocatorImpl(locator) : NULL_LOCATOR;
+                charLocation = LocationAttributes.getLocation(locator, "[text]");
             }
             charBuf.append(ch, start, length);
         }
 
         public void endDocument() throws SAXException {
             StartDocument startDoc = (StartDocument)stack.pop();
-            EndDocument endDoc = new EndDocument(locator);
+            EndDocument endDoc = new EndDocument(LocationAttributes.getLocation(locator, "template"));
             startDoc.endDocument = endDoc;
             addEvent(endDoc);
         }
@@ -1939,7 +1927,7 @@
             Event newEvent = null;
             if (NS.equals(namespaceURI)) {
                 StartInstruction startInstruction = (StartInstruction)start;
-                EndInstruction endInstruction = new EndInstruction(locator, startInstruction);
+                EndInstruction endInstruction = new EndInstruction(LocationAttributes.getLocation(locator, "<"+raw+">"), startInstruction);
                 newEvent = endInstruction;
                 if (start instanceof StartWhen) {
                     StartWhen startWhen = (StartWhen)start;
@@ -1960,7 +1948,7 @@
                 }
             } else {
                 StartElement startElement = (StartElement)start;
-                newEvent = startElement.endElement = new EndElement(locator, startElement);
+                newEvent = startElement.endElement = new EndElement(LocationAttributes.getLocation(locator, "<"+raw+">"), startElement);
             }
             addEvent(newEvent);
             if (start instanceof StartDefine) {
@@ -1970,17 +1958,17 @@
         }
 
         public void endPrefixMapping(String prefix) throws SAXException {
-            EndPrefixMapping endPrefixMapping = new EndPrefixMapping(locator, prefix);
+            EndPrefixMapping endPrefixMapping = new EndPrefixMapping(LocationAttributes.getLocation(locator, null), prefix);
             addEvent(endPrefixMapping);
         }
 
         public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
-            Event ev = new IgnorableWhitespace(locator, ch, start, length);
+            Event ev = new IgnorableWhitespace(LocationAttributes.getLocation(locator, null), ch, start, length);
             addEvent(ev);
         }
 
         public void processingInstruction(String target, String data) throws SAXException {
-            Event pi = new ProcessingInstruction(locator, target, data);
+            Event pi = new ProcessingInstruction(LocationAttributes.getLocation(locator, null), target, data);
             addEvent(pi);
         }
 
@@ -1989,17 +1977,18 @@
         }
 
         public void skippedEntity(String name) throws SAXException {
-            addEvent(new SkippedEntity(locator, name));
+            addEvent(new SkippedEntity(LocationAttributes.getLocation(locator, null), name));
         }
 
         public void startDocument() {
-            startEvent = new StartDocument(locator);
+            startEvent = new StartDocument(LocationAttributes.getLocation(locator, null));
             lastEvent = startEvent;
             stack.push(lastEvent);
         }
 
         public void startElement(String namespaceURI, String localName, String qname, Attributes attrs) throws SAXException {
             Event newEvent = null;
+            Location locator = LocationAttributes.getLocation(this.locator, "<"+qname+">");
             AttributesImpl elementAttributes = new AttributesImpl(attrs);
             int attributeCount = elementAttributes.getLength();
             for (int i = 0; i < attributeCount; i++) {
@@ -2210,7 +2199,7 @@
         }
 
         public void startPrefixMapping(String prefix, String uri) throws SAXException {
-            addEvent(new StartPrefixMapping(locator, prefix, uri));
+            addEvent(new StartPrefixMapping(LocationAttributes.getLocation(locator, null), prefix, uri));
         }
 
         public void comment(char ch[], int start, int length) throws SAXException {
@@ -2218,27 +2207,27 @@
         }
 
         public void endCDATA() throws SAXException {
-            addEvent(new EndCDATA(locator));
+            addEvent(new EndCDATA(LocationAttributes.getLocation(locator, null)));
         }
 
         public void endDTD() throws SAXException {
-            addEvent(new EndDTD(locator));
+            addEvent(new EndDTD(LocationAttributes.getLocation(locator, null)));
         }
 
         public void endEntity(String name) throws SAXException {
-            addEvent(new EndEntity(locator, name));
+            addEvent(new EndEntity(LocationAttributes.getLocation(locator, null), name));
         }
 
         public void startCDATA() throws SAXException {
-            addEvent(new StartCDATA(locator));
+            addEvent(new StartCDATA(LocationAttributes.getLocation(locator, null)));
         }
 
         public void startDTD(String name, String publicId, String systemId) throws SAXException {
-            addEvent(new StartDTD(locator, name, publicId, systemId));
+            addEvent(new StartDTD(LocationAttributes.getLocation(locator, null), name, publicId, systemId));
         }
 
         public void startEntity(String name) throws SAXException {
-            addEvent(new StartEntity(locator, name));
+            addEvent(new StartEntity(LocationAttributes.getLocation(locator, null), name));
         }
     }
 
@@ -2532,7 +2521,7 @@
         streamer.stream(node);
    }
 
-    private void call(Locator location, StartElement macroCall, final XMLConsumer consumer, MyJexlContext jexlContext,
+    private void call(Location location, StartElement macroCall, final XMLConsumer consumer, MyJexlContext jexlContext,
             JXPathContext jxpathContext, Event startEvent, Event endEvent) throws SAXException {
         try {
             execute(consumer, jexlContext, jxpathContext, macroCall, startEvent, endEvent);
@@ -2580,10 +2569,10 @@
     private void execute(final XMLConsumer consumer, MyJexlContext jexlContext, JXPathContext jxpathContext,
             StartElement macroCall, Event startEvent, Event endEvent) throws SAXException {
         Event ev = startEvent;
-        LocatorFacade loc = new LocatorFacade(ev.location);
+        LocationFacade loc = new LocationFacade(ev.location);
         consumer.setDocumentLocator(loc);
         while (ev != endEvent) {
-            loc.setDocumentLocator(ev.location);
+            loc.setDocumentLocation(ev.location);
             if (ev instanceof Characters) {
                 TextEvent text = (TextEvent)ev;
                 Iterator iter = text.substitutions.iterator();
@@ -2629,10 +2618,15 @@
             } else if (ev instanceof EndElement) {
                 EndElement endElement = (EndElement)ev;
                 StartElement startElement = endElement.startElement;
-                consumer.endElement(startElement.namespaceURI, startElement.localName, startElement.raw);
-                namespaces.leaveScope(consumer);
+                StartDefine def =
+                    (StartDefine)definitions.get(startElement.qname);
+                if (def == null) {
+                    consumer.endElement(startElement.namespaceURI, startElement.localName, startElement.raw);
+                    namespaces.leaveScope(consumer);
+                }
             } else if (ev instanceof EndPrefixMapping) {
                 EndPrefixMapping endPrefixMapping = (EndPrefixMapping)ev;
+                namespaces.removeDeclaration(endPrefixMapping.prefix);
             } else if (ev instanceof IgnorableWhitespace) {
                 TextEvent text = (TextEvent)ev;
                 characters(jexlContext, jxpathContext, text, new CharHandler() {
@@ -2682,7 +2676,7 @@
                             Object result = e.evaluate(jexlContext);
                             if (result != null) {
                                 iter = Introspector.getUberspect().getIterator(result,
-                                        new Info(ev.location.getSystemId(), ev.location.getLineNumber(), ev.location.getColumnNumber()));
+                                        new Info(ev.location.getURI(), ev.location.getLineNumber(), ev.location.getColumnNumber()));
                             }
                             if (iter == null) {
                                 iter = EMPTY_ITER;

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/sitemap/SitemapParameters.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/sitemap/SitemapParameters.java?rev=232400&r1=232399&r2=232400&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/sitemap/SitemapParameters.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/sitemap/SitemapParameters.java Fri Aug 12 15:14:26 2005
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2004 The Apache Software Foundation.
+ * Copyright 1999-2005 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.
@@ -17,68 +17,73 @@
 
 import java.util.HashMap;
 
-import org.apache.avalon.framework.configuration.Configuration;
 import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.cocoon.util.location.Locatable;
+import org.apache.cocoon.util.location.Location;
 
 /**
- * Extension to the Avalon Parameters
+ * Extension to the Avalon Parameters to give location information
  *
- * @version CVS $Id: SitemapParameters.java,v 1.3 2004/03/09 11:24:43 cziegeler Exp $
+ * @version CVS $Id$
  */
-public class SitemapParameters extends Parameters {
+public class SitemapParameters extends Parameters implements Locatable {
     
-    protected String statementLocation;
+    private Location location = Location.UNKNOWN;
     
-    /**
-    public String getParameterLocation(String name) {
-        return null;   
-    }
-    */
-    public String getStatementLocation() {
-        return this.statementLocation;   
+    public SitemapParameters(Location location) {
+        this.location = location;
     }
     
-    public void setStatementLocation(String value) {
-        this.statementLocation = value;   
+    /*
+     * Get the location of the statement defining these parameters.
+     * 
+     * @since 2.1.8
+     * @see org.apache.cocoon.util.location.Locatable#getLocation()
+     */
+    public Location getLocation() {
+        return this.location;
     }
     
     /**
-     * Return the location  - if available
+     * Get the location of a <code>Parameters</code> object, returning
+     * {@link Location#UNKNOWN} if no location could be found.
+     * 
+     * @param param
+     * @return the location
+     * @since 2.1.8
      */
-    public static String getStatementLocation(Parameters param) {
-        String value = null;
-        if ( param instanceof SitemapParameters ) {
-            value = ((SitemapParameters)param).getStatementLocation();
-        }
-        if ( value == null ) {
-            value = "[unknown location]";
+    public static Location getLocation(Parameters param) {
+        Location loc = null;
+        if (param instanceof Locatable) {
+            loc = ((Locatable)param).getLocation();
         }
-        return value;
+        return loc == null ? Location.UNKNOWN : loc;
     }
-    
-    public static class ExtendedHashMap extends HashMap {
-        
-        protected Configuration configuration;
-        
-        public ExtendedHashMap(Configuration conf) {
-            super();
-            this.configuration = conf;
+
+    /**
+     * @deprecated use {@link #getLocation(Parameters)}
+     */
+    public static String getStatementLocation(Parameters param) {
+        return getLocation(param).toString();
+    }    
+
+    /**
+     * For internal use only.
+     */
+    public static class LocatedHashMap extends HashMap implements Locatable {
+        private Location loc;
+
+        public Location getLocation() {
+            return this.loc;
         }
         
-        public ExtendedHashMap(Configuration conf, int capacity) {
-            super(capacity);
-            this.configuration = conf;
+        public LocatedHashMap(Location loc) {
+            this.loc = loc;
         }
 
-        public String getLocation() {
-            if ( this.configuration != null ) {
-                return this.configuration.getLocation();
-            } 
-            return null;
-        }
-        
-        public Configuration getConfiguration() {
-            return this.configuration;
+        public LocatedHashMap(Location loc, int size) {
+            super(size);
+            this.loc = loc;
         }
     }
 }

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/transformation/BrowserUpdateTransformer.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/transformation/BrowserUpdateTransformer.java?rev=232400&r1=232399&r2=232400&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/transformation/BrowserUpdateTransformer.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/transformation/BrowserUpdateTransformer.java Fri Aug 12 15:14:26 2005
@@ -11,7 +11,9 @@
 import org.apache.cocoon.xml.AttributesImpl;
 import org.apache.cocoon.xml.RedundantNamespacesFilter;
 import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
 import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
 
 public class BrowserUpdateTransformer extends AbstractTransformer {
     
@@ -19,19 +21,29 @@
     
     public static final String BU_NSURI = "http://apache.org/cocoon/browser-update/1.0";
     
-    private boolean ajaxMode = false;
+    private boolean ajaxRequest = false;
     
     private int replaceDepth = 0;
+    
+    private boolean inUpdateTag = false;
+    private String updateTagId = null;
+    
+    Locator locator;
 
     public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) throws ProcessingException, SAXException, IOException {
 
         Request request = ObjectModelHelper.getRequest(objectModel);
-        this.ajaxMode = request.getParameter(AJAXMODE_PARAM) != null;
+        this.ajaxRequest = request.getParameter(AJAXMODE_PARAM) != null;
+    }
+    
+    public void setDocumentLocator(Locator locator) {
+        super.setDocumentLocator(locator);
+        this.locator = locator;
     }
 
     public void startDocument() throws SAXException {
         
-        if (ajaxMode) {
+        if (ajaxRequest) {
             // Add the namespace filter to our own output.
             // This is needed as flattening bu:* elements can lead to some weird reordering of
             // namespace declarations...
@@ -45,7 +57,7 @@
         }
         
         super.startDocument();
-        if (ajaxMode) {
+        if (ajaxRequest) {
             // Add a root element. The original one is very likely to be stripped
             super.startPrefixMapping("bu", BU_NSURI);
             super.startElement(BU_NSURI, "document", "bu:document", new AttributesImpl());
@@ -54,28 +66,63 @@
     
     public void startPrefixMapping(String prefix, String uri) throws SAXException {
         // Passthrough if not in ajax mode or if in a bu:replace
-        if (!this.ajaxMode || this.replaceDepth > 0) {
+        if (!this.ajaxRequest || this.replaceDepth > 0) {
             super.startPrefixMapping(prefix, uri);
         }
     }
 
-    public void startElement(String uri, String loc, String raw, Attributes a) throws SAXException {
+    public void startElement(String uri, String loc, String raw, Attributes attrs) throws SAXException {
         if (BU_NSURI.equals(uri) && "replace".equals(loc)) {
-            if (this.ajaxMode && this.replaceDepth == 0) {
+            // Keep the id attribute. It may be null, in which case the one of the
+            // child element will be used.
+            this.updateTagId = attrs.getValue("id");
+            this.inUpdateTag = true;
+            if (this.ajaxRequest && this.replaceDepth == 0) {
                 // Pass this element through
-                super.startElement(uri, loc, raw, a);
+                super.startElement(uri, loc, raw, attrs);
             }
             replaceDepth++;
         } else {
             // Passthrough if not in ajax mode or if in a bu:replace
-            if (!this.ajaxMode || this.replaceDepth > 0) {
-                super.startElement(uri, loc, raw, a);
+            
+            // Is the enclosing element a bu:replace?
+            if (this.inUpdateTag) {
+                this.inUpdateTag = false;
+                // Is there already an id?
+                String localId = attrs.getValue("id");
+                if (localId != null) {
+                    // Yes: check it's the same
+                    if (this.updateTagId != null && !localId.equals(this.updateTagId)) {
+                        throw new SAXParseException("Id on bu:replace (" + this.updateTagId + ") and " + raw + " (" +
+                                localId + ") don't match.", this.locator);
+                    }
+                } else {
+                    // No: add it
+                    if (this.updateTagId == null) {
+                        throw new SAXParseException("Neither bu:replace nor " + raw + " have an id attribute.", this.locator);
+                    }
+                    AttributesImpl newAttrs = new AttributesImpl(attrs);
+                    newAttrs.addCDATAAttribute("id", this.updateTagId);
+                    attrs = newAttrs;
+                }
+                this.updateTagId = null;
+            }
+            if (!this.ajaxRequest || this.replaceDepth > 0) {
+                super.startElement(uri, loc, raw, attrs);
             }
         }
     }
 
     public void characters(char[] buffer, int offset, int len) throws SAXException {
-        if (!this.ajaxMode || this.replaceDepth > 0) {
+        if (this.inUpdateTag) {
+            // Check that it's only spaces
+            for (int i = offset; i < len; i++) {
+                if (!Character.isWhitespace(buffer[i])) {
+                    throw new SAXParseException("bu:replace must include a single child element and no text.", this.locator);
+                }
+            }
+        }
+        if (!this.ajaxRequest || this.replaceDepth > 0) {
             super.characters(buffer, offset, len);
         }
     }
@@ -83,13 +130,13 @@
     public void endElement(String uri, String loc, String raw) throws SAXException {
         if (BU_NSURI.equals(uri) && "replace".equals(loc)) {
             replaceDepth--;
-            if (this.ajaxMode && this.replaceDepth == 0) {
+            if (this.ajaxRequest && this.replaceDepth == 0) {
                 // Pass this element through
                 super.endElement(uri, loc, raw);
             }
         } else {
             // Passthrough if not in ajax mode or if in a bu:replace
-            if (!this.ajaxMode || this.replaceDepth > 0) {
+            if (!this.ajaxRequest || this.replaceDepth > 0) {
                 super.endElement(uri, loc, raw);
             }
         }
@@ -97,13 +144,13 @@
 
     public void endPrefixMapping(String prefix) throws SAXException {
         // Passthrough if not in ajax mode or if in a bu:replace
-        if (!this.ajaxMode || this.replaceDepth > 0) {
+        if (!this.ajaxRequest || this.replaceDepth > 0) {
             super.endPrefixMapping(prefix);
         }
     }
 
     public void endDocument() throws SAXException {
-        if (ajaxMode) {
+        if (ajaxRequest) {
             super.endElement(BU_NSURI, "document", "bu:document");
             super.endPrefixMapping("bu");
         }



Mime
View raw message