You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by sy...@apache.org on 2005/08/18 20:07:53 UTC

svn commit: r233343 [1/3] - in /cocoon/trunk/src: java/org/apache/cocoon/ java/org/apache/cocoon/components/flow/ java/org/apache/cocoon/components/flow/javascript/ java/org/apache/cocoon/components/flow/javascript/fom/ java/org/apache/cocoon/component...

Author: sylvain
Date: Thu Aug 18 11:06:44 2005
New Revision: 233343

URL: http://svn.apache.org/viewcvs?rev=233343&view=rev
Log:
Porting Cocoon stacktraces to trunk

Added:
    cocoon/trunk/src/java/org/apache/cocoon/components/flow/javascript/LocationTrackingDebugger.java   (with props)
    cocoon/trunk/src/java/org/apache/cocoon/generation/ExceptionGenerator.java   (with props)
    cocoon/trunk/src/java/org/apache/cocoon/util/ExceptionUtils.java   (with props)
    cocoon/trunk/src/java/org/apache/cocoon/util/location/Locatable.java   (with props)
    cocoon/trunk/src/java/org/apache/cocoon/util/location/LocatableException.java   (with props)
    cocoon/trunk/src/java/org/apache/cocoon/util/location/LocatedException.java   (with props)
    cocoon/trunk/src/java/org/apache/cocoon/util/location/LocatedRuntimeException.java   (with props)
    cocoon/trunk/src/java/org/apache/cocoon/util/location/Location.java   (with props)
    cocoon/trunk/src/java/org/apache/cocoon/util/location/LocationImpl.java   (with props)
    cocoon/trunk/src/java/org/apache/cocoon/util/location/MultiLocatable.java   (with props)
    cocoon/trunk/src/test/org/apache/cocoon/util/location/
    cocoon/trunk/src/test/org/apache/cocoon/util/location/LocationTestCase.java   (with props)
    cocoon/trunk/src/webapp/stylesheets/system/exception2html.xslt   (with props)
Removed:
    cocoon/trunk/src/java/org/apache/cocoon/util/location/LocatorToAttributesPipe.java
    cocoon/trunk/src/java/org/apache/cocoon/xml/NamespaceSupport.java
Modified:
    cocoon/trunk/src/java/org/apache/cocoon/ConnectionResetException.java
    cocoon/trunk/src/java/org/apache/cocoon/ProcessingException.java
    cocoon/trunk/src/java/org/apache/cocoon/ResourceNotFoundException.java
    cocoon/trunk/src/java/org/apache/cocoon/components/flow/InvalidContinuationException.java
    cocoon/trunk/src/java/org/apache/cocoon/components/flow/javascript/fom/FOM_JavaScriptInterpreter.java
    cocoon/trunk/src/java/org/apache/cocoon/components/notification/DefaultNotifyingBuilder.java
    cocoon/trunk/src/java/org/apache/cocoon/components/pipeline/AbstractProcessingPipeline.java
    cocoon/trunk/src/java/org/apache/cocoon/components/pipeline/VirtualProcessingPipeline.java
    cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNode.java
    cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNodeBuilder.java
    cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/ConcreteTreeProcessor.java
    cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java
    cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/InvokeContext.java
    cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/ProcessingNode.java
    cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/CallFunctionNode.java
    cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/ErrorHandlerHelper.java
    cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/FlowNode.java
    cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/MountNode.java
    cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SerializeNode.java
    cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/variables/VariableResolver.java
    cocoon/trunk/src/java/org/apache/cocoon/selection/ExceptionSelector.java
    cocoon/trunk/src/java/org/apache/cocoon/sitemap/ExecutionContext.java
    cocoon/trunk/src/java/org/apache/cocoon/sitemap/SitemapParameters.java
    cocoon/trunk/src/java/org/apache/cocoon/transformation/TraxTransformer.java
    cocoon/trunk/src/java/org/apache/cocoon/util/location/LocationAttributes.java
    cocoon/trunk/src/java/org/apache/cocoon/util/log/CocoonLogFormatter.java
    cocoon/trunk/src/java/org/apache/cocoon/util/log/CocoonStreamTargetFactory.java
    cocoon/trunk/src/java/org/apache/cocoon/util/log/CocoonTargetFactory.java
    cocoon/trunk/src/java/org/apache/cocoon/util/log/ExtensiblePatternFormatter.java
    cocoon/trunk/src/java/org/apache/cocoon/util/log/XMLCocoonLogFormatter.java
    cocoon/trunk/src/java/org/apache/cocoon/xml/AbstractXMLPipe.java
    cocoon/trunk/src/java/org/apache/cocoon/xml/NamespacesTable.java
    cocoon/trunk/src/test/org/apache/cocoon/xml/NamespacesTableTestCase.java
    cocoon/trunk/src/webapp/sitemap.xmap

Modified: cocoon/trunk/src/java/org/apache/cocoon/ConnectionResetException.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/ConnectionResetException.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/ConnectionResetException.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/ConnectionResetException.java Thu Aug 18 11:06:44 2005
@@ -20,7 +20,7 @@
  * due to a connection reset by peer.
  *
  * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
- * @version CVS $Id: ConnectionResetException.java,v 1.2 2004/03/05 13:02:42 bdelacretaz Exp $
+ * @version CVS $Id$
  */
 public class ConnectionResetException extends ProcessingException {
 
@@ -30,7 +30,7 @@
      * @param message a <code>String</code> value
      */
     public ConnectionResetException(String message) {
-        super(message, null);
+        super(message);
     }
 
     /**

Modified: cocoon/trunk/src/java/org/apache/cocoon/ProcessingException.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/ProcessingException.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/ProcessingException.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/ProcessingException.java Thu Aug 18 11:06:44 2005
@@ -15,14 +15,12 @@
  */
 package org.apache.cocoon;
 
-import org.apache.avalon.framework.CascadingException;
+import java.util.List;
 
-import java.io.PrintStream;
-import java.io.PrintWriter;
-
-import org.xml.sax.SAXParseException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.SourceLocator;
+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;
 
 /**
  * This Exception is thrown every time there is a problem in processing
@@ -30,15 +28,15 @@
  *
  * @author <a href="mailto:pier@apache.org">Pierpaolo Fumagalli</a>
  *         (Apache Software Foundation)
- * @version CVS $Id: ProcessingException.java,v 1.2 2004/03/05 13:02:42 bdelacretaz Exp $
+ * @version CVS $Id$
  */
-public class ProcessingException extends CascadingException {
+public class ProcessingException extends LocatedException implements MultiLocatable {
     
     /**
      * Construct a new <code>ProcessingException</code> instance.
      */
     public ProcessingException(String message) {
-        super(message, null);
+        super(message);
     }
     
     /**
@@ -58,71 +56,173 @@
         super(message, t);
     }
     
-    public String toString() {
-        StringBuffer s = new StringBuffer();
-        s.append(super.toString());
-        final Throwable t = getCause();
-        if(t!=null) {
-            s.append(": ");
-            // be more verbose try to get location info
-            s.append( extraInfo(t) );
-            s.append(t.toString());
-        }
-        return s.toString();
+    /**
+     * Construct a new <code>ProcessingException</code> that has an associated location.
+     */
+    public ProcessingException(String message, Location location) {
+        super(message, location);
     }
     
     /**
-     * Examine Throwable and try to figure out location information.
+     * Construct a new <code>ProcessingException</code> that has a parent exception
+     * and an associated location.
      * <p>
-     *   At the moment only SAXParseException, and TransformerException
-     *   are considered.
-     * </p>
-     *
-     * @return String containing location information of the format
-     *  <code>{file-name}:{line}:{column}:</code>, if no location info is 
-     *  available return empty string
-     */
-    private String extraInfo( Throwable t ) {
-        StringBuffer sb = new StringBuffer();
-        if (t instanceof SAXParseException) {
-            SAXParseException spe = (SAXParseException)t;
-            sb.append( String.valueOf(spe.getSystemId()));
-            sb.append( ":" );
-            sb.append( String.valueOf(spe.getLineNumber()));
-            sb.append( ":" );
-            sb.append( String.valueOf(spe.getColumnNumber()));
-            sb.append( ":" );
-        } else if (t instanceof TransformerException) {
-            TransformerException transformerException = (TransformerException) t;
-            SourceLocator sourceLocator = transformerException.getLocator();
-            
-            if( null != sourceLocator ) {
-                sb.append( String.valueOf(sourceLocator.getSystemId()));
-                sb.append( ":" );
-                sb.append( String.valueOf(sourceLocator.getLineNumber()));
-                sb.append( ":" );
-                sb.append( String.valueOf(sourceLocator.getColumnNumber()));
-                sb.append( ":" );
-            }
-        }
-        return sb.toString();
-    }
-    
-    public void printStackTrace() {
-        super.printStackTrace();
-        if(getCause()!=null)
-            getCause().printStackTrace();
+     * This constructor is protected to enforce the use of {@link #throwLocated(String, Throwable, Location)}
+     * which limits exception nesting as far as possible.
+     */
+    protected ProcessingException(String message, Throwable t, Location location) {
+        super(message, t, location);
     }
     
-    public void printStackTrace( PrintStream s ) {
-        super.printStackTrace(s);
-        if(getCause()!=null)
-            getCause().printStackTrace(s);
+    /**
+     * 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);
+            throw pe;
+
+        } else if (thr instanceof LocatedRuntimeException) {
+            LocatedRuntimeException re = (LocatedRuntimeException)thr;
+            re.addLocation(location);
+            // Rethrow
+            throw re;
+        }
+        
+        throw new ProcessingException(message, thr, location);
     }
     
-    public void printStackTrace( PrintWriter s ) {
-        super.printStackTrace(s);
-        if(getCause()!=null)
-            getCause().printStackTrace(s);
+    /**
+     * 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;
+        }
     }
+
+
+//    public String toString() {
+//        StringBuffer s = new StringBuffer();
+//        s.append(super.toString());
+//        final Throwable t = getCause();
+//        if(t!=null) {
+//            s.append(": ");
+//            // be more verbose try to get location info
+//            s.append( extraInfo(t) );
+//            s.append(t.toString());
+//        }
+//        return s.toString();
+//    }
+//    
+//    /**
+//     * Examine Throwable and try to figure out location information.
+//     * <p>
+//     *   At the moment only SAXParseException, and TransformerException
+//     *   are considered.
+//     * </p>
+//     *
+//     * @return String containing location information of the format
+//     *  <code>{file-name}:{line}:{column}:</code>, if no location info is 
+//     *  available return empty string
+//     */
+//    private String extraInfo( Throwable t ) {
+//        StringBuffer sb = new StringBuffer();
+//        if (t instanceof SAXParseException) {
+//            SAXParseException spe = (SAXParseException)t;
+//            sb.append( String.valueOf(spe.getSystemId()));
+//            sb.append( ":" );
+//            sb.append( String.valueOf(spe.getLineNumber()));
+//            sb.append( ":" );
+//            sb.append( String.valueOf(spe.getColumnNumber()));
+//            sb.append( ":" );
+//        } else if (t instanceof TransformerException) {
+//            TransformerException transformerException = (TransformerException) t;
+//            SourceLocator sourceLocator = transformerException.getLocator();
+//            
+//            if( null != sourceLocator ) {
+//                sb.append( String.valueOf(sourceLocator.getSystemId()));
+//                sb.append( ":" );
+//                sb.append( String.valueOf(sourceLocator.getLineNumber()));
+//                sb.append( ":" );
+//                sb.append( String.valueOf(sourceLocator.getColumnNumber()));
+//                sb.append( ":" );
+//            }
+//        }
+//        return sb.toString();
+//    }
+//    
+//    public void printStackTrace() {
+//        super.printStackTrace();
+//        if(getCause()!=null)
+//            getCause().printStackTrace();
+//    }
+//    
+//    public void printStackTrace( PrintStream s ) {
+//        super.printStackTrace(s);
+//        if(getCause()!=null)
+//            getCause().printStackTrace(s);
+//    }
+//    
+//    public void printStackTrace( PrintWriter s ) {
+//        super.printStackTrace(s);
+//        if(getCause()!=null)
+//            getCause().printStackTrace(s);
+//    }
 }

Modified: cocoon/trunk/src/java/org/apache/cocoon/ResourceNotFoundException.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/ResourceNotFoundException.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/ResourceNotFoundException.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/ResourceNotFoundException.java Thu Aug 18 11:06:44 2005
@@ -15,12 +15,14 @@
  */
 package org.apache.cocoon;
 
+import org.apache.cocoon.util.location.Location;
+
 /**
  * This Exception is thrown every time there is a problem in finding
  * a resource.
  *
  * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
- * @version CVS $Id: ResourceNotFoundException.java,v 1.2 2004/03/05 13:02:42 bdelacretaz Exp $
+ * @version CVS $Id$
  */
 public class ResourceNotFoundException extends ProcessingException {
 
@@ -28,7 +30,7 @@
      * Construct a new <code>ResourceNotFoundException</code> instance.
      */
     public ResourceNotFoundException(String message) {
-        super(message, null);
+        super(message);
     }
 
     /**
@@ -37,5 +39,13 @@
      */
     public ResourceNotFoundException(String message, Throwable t) {
         super(message, t);
+    }
+    
+    public ResourceNotFoundException(String message, Location location) {
+        super(message, location);
+    }
+    
+    public ResourceNotFoundException(String message, Throwable t, Location loc) {
+        super(message, t, loc);
     }
 }

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/flow/InvalidContinuationException.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/flow/InvalidContinuationException.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/flow/InvalidContinuationException.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/flow/InvalidContinuationException.java Thu Aug 18 11:06:44 2005
@@ -21,7 +21,7 @@
  * This Exception is thrown whenever an invalid continuation is given.
  *
  * @author <a href="mailto:tcollen@neuagency.com">Tony Collen</a>
- * @version CVS $Id: InvalidContinuationException.java,v 1.2 2004/03/05 13:02:46 bdelacretaz Exp $
+ * @version CVS $Id$
  */
 public class InvalidContinuationException extends ProcessingException {
 
@@ -29,7 +29,7 @@
      * Construct a new <code>InvalidContinuationException</code> instance.
      */
     public InvalidContinuationException(String message) {
-        super(message, null);
+        super(message);
     }
 
     /**

Added: cocoon/trunk/src/java/org/apache/cocoon/components/flow/javascript/LocationTrackingDebugger.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/flow/javascript/LocationTrackingDebugger.java?rev=233343&view=auto
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/flow/javascript/LocationTrackingDebugger.java (added)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/flow/javascript/LocationTrackingDebugger.java Thu Aug 18 11:06:44 2005
@@ -0,0 +1,122 @@
+/*
+ * Copyright 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.
+ * 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.
+ */
+package org.apache.cocoon.components.flow.javascript;
+
+import java.util.ArrayList;
+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.Scriptable;
+import org.mozilla.javascript.debug.DebugFrame;
+import org.mozilla.javascript.debug.DebuggableScript;
+import org.mozilla.javascript.debug.Debugger;
+
+/**
+ * A Rhino debugger that tracks location information when an exception is raised in some JavaScript code.
+ * It's purpose is to build a {@link org.apache.cocoon.ProcessingException} that holds the stacktrace
+ * in the JavaScript code.
+ * <p>
+ * 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 {
+    
+    private List locations;
+    private Throwable throwable;
+    
+    public void handleCompilationDone(Context cx, DebuggableScript fnOrScript, String source) {
+        // nothing
+    }
+
+    public DebugFrame getFrame(Context cx, DebuggableScript fnOrScript) {
+        return new StackTrackingFrame(fnOrScript);
+    }
+
+    /**
+     * Get an exception that reflects the known location stack
+     *
+     * @param description a description for the exception
+     * @param originalException the original exception
+     * 
+     * @return a suitable exception to throw
+     * @see ProcessingException#throwLocated(String, Throwable, Location)
+     */
+    public Exception getException(String description, Exception originalException) throws ProcessingException {
+        if (throwable == null || locations == null) {
+            // Cannot to better for now
+            return originalException;
+        }
+
+        // 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 {
+        
+        DebuggableScript script;
+        int line;
+
+        public StackTrackingFrame(DebuggableScript script) {
+            this.script = script;
+        }
+        
+        public void onEnter(Context cx, Scriptable activation, Scriptable thisObj, Object[] args) {
+            // nothing
+        }
+        
+        public void onLineChange(Context cx, int lineNumber) {
+            line = lineNumber;
+        }
+
+        public void onExceptionThrown(Context cx, Throwable ex) {
+            throwable = ex;
+        }
+
+        public void onExit(Context cx, boolean byThrow, Object resultOrException) {
+            if (byThrow) {
+                String name = null;
+                if (script.isFunction()) {
+                    name = script.getFunctionName();
+                } else {
+                    name = "[script]";
+                }
+
+                if (locations == null) {
+                    locations = new ArrayList(1); // start small
+                }
+
+                locations.add(new LocationImpl(name, script.getSourceName(), line, -1));
+
+            } else if (locations != null) {
+                // The exception was handled by the script: clear any recorded locations
+                locations = null;
+            }
+        }
+    }
+}
+

Propchange: cocoon/trunk/src/java/org/apache/cocoon/components/flow/javascript/LocationTrackingDebugger.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/trunk/src/java/org/apache/cocoon/components/flow/javascript/LocationTrackingDebugger.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/flow/javascript/fom/FOM_JavaScriptInterpreter.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/flow/javascript/fom/FOM_JavaScriptInterpreter.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/flow/javascript/fom/FOM_JavaScriptInterpreter.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/flow/javascript/fom/FOM_JavaScriptInterpreter.java Thu Aug 18 11:06:44 2005
@@ -15,14 +15,23 @@
  */
 package org.apache.cocoon.components.flow.javascript.fom;
 
-import org.apache.avalon.framework.CascadingRuntimeException;
+import java.awt.Dimension;
+import java.awt.Toolkit;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PushbackInputStream;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
 import org.apache.avalon.framework.activity.Initializable;
 import org.apache.avalon.framework.configuration.Configurable;
 import org.apache.avalon.framework.configuration.Configuration;
 import org.apache.avalon.framework.configuration.ConfigurationException;
 import org.apache.avalon.framework.service.ServiceManager;
-
-import org.apache.cocoon.ProcessingException;
 import org.apache.cocoon.ResourceNotFoundException;
 import org.apache.cocoon.components.ContextHelper;
 import org.apache.cocoon.components.flow.CompilingInterpreter;
@@ -30,13 +39,13 @@
 import org.apache.cocoon.components.flow.InvalidContinuationException;
 import org.apache.cocoon.components.flow.WebContinuation;
 import org.apache.cocoon.components.flow.javascript.JSErrorReporter;
+import org.apache.cocoon.components.flow.javascript.LocationTrackingDebugger;
 import org.apache.cocoon.components.flow.javascript.ScriptablePointerFactory;
 import org.apache.cocoon.components.flow.javascript.ScriptablePropertyHandler;
 import org.apache.cocoon.environment.ObjectModelHelper;
 import org.apache.cocoon.environment.Redirector;
 import org.apache.cocoon.environment.Request;
 import org.apache.cocoon.environment.Session;
-
 import org.apache.commons.jxpath.JXPathIntrospector;
 import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl;
 import org.apache.excalibur.source.Source;
@@ -45,7 +54,6 @@
 import org.apache.regexp.REProgram;
 import org.mozilla.javascript.Context;
 import org.mozilla.javascript.EcmaError;
-import org.mozilla.javascript.EvaluatorException;
 import org.mozilla.javascript.Function;
 import org.mozilla.javascript.JavaScriptException;
 import org.mozilla.javascript.NativeJavaClass;
@@ -58,22 +66,9 @@
 import org.mozilla.javascript.WrappedException;
 import org.mozilla.javascript.Wrapper;
 import org.mozilla.javascript.continuations.Continuation;
-import org.mozilla.javascript.tools.ToolErrorReporter;
 import org.mozilla.javascript.tools.debugger.Main;
 import org.mozilla.javascript.tools.shell.Global;
 
-import java.awt.Dimension;
-import java.awt.Toolkit;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.PushbackInputStream;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
 
 /**
  * Interface with the JavaScript interpreter.
@@ -559,6 +554,12 @@
         context.setGeneratingDebug(true);
         context.setCompileFunctionsWithDynamicScope(true);
         context.setErrorReporter(errorReporter);
+        
+        LocationTrackingDebugger locationTracker = new LocationTrackingDebugger();
+        if (!enableDebugger) {
+            //FIXME: add a "tee" debugger that allows both to be used simultaneously
+            context.setDebugger(locationTracker, null);
+        }
 
         ThreadScope thrScope = getSessionScope();
         synchronized (thrScope) {
@@ -599,25 +600,11 @@
                     thrScope.setLock(true);
                     ScriptRuntime.call(context, fun, thrScope, new Object[0], thrScope);
                 } catch (JavaScriptException ex) {
-                    EvaluatorException ee = Context.reportRuntimeError(
-                                                                       ToolErrorReporter.getMessage("msg.uncaughtJSException",
-                                                                                                    ex.getMessage()));
-                    Throwable unwrapped = unwrap(ex);
-                    if (unwrapped instanceof ProcessingException) {
-                        throw (ProcessingException) unwrapped;
-                    }
-                    throw new CascadingRuntimeException(ee.getMessage(),
-                                                        unwrapped);
+                    throw locationTracker.getException("Calling function " + funName, ex);
                 } catch (EcmaError ee) {
-                    String msg = ToolErrorReporter.getMessage("msg.uncaughtJSException", ee.toString());
-                    if (ee.getSourceName() != null) {
-                        Context.reportRuntimeError(msg, ee.getSourceName(),
-                                                   ee.getLineNumber(), ee.getLineSource(),
-                                                   ee.getColumnNumber());
-                    } else {
-                        Context.reportRuntimeError(msg);
-                    }
-                    throw new CascadingRuntimeException(ee.getMessage(), ee);
+                    throw locationTracker.getException("Calling function " + funName, ee);
+                } catch (WrappedException ee) {
+                    throw locationTracker.getException("Calling function " + funName, ee);
                 }
             } finally {
                 thrScope.setLock(false);
@@ -648,6 +635,11 @@
         context.setOptimizationLevel(OPTIMIZATION_LEVEL);
         context.setGeneratingDebug(true);
         context.setCompileFunctionsWithDynamicScope(true);
+        LocationTrackingDebugger locationTracker = new LocationTrackingDebugger();
+        if (!enableDebugger) {
+            //FIXME: add a "tee" debugger that allows both to be used simultaneously
+            context.setDebugger(locationTracker, null);
+        }
 
         // Obtain the continuation object from it, and setup the
         // FOM_Cocoon object associated in the dynamic scope of the saved
@@ -688,25 +680,27 @@
                     ScriptableObject.callMethod(cocoon,
                                                 "handleContinuation", args);
                 } catch (JavaScriptException ex) {
-                    EvaluatorException ee = Context.reportRuntimeError(
-                                                                       ToolErrorReporter.getMessage("msg.uncaughtJSException",
-                                                                                                    ex.getMessage()));
-                    Throwable unwrapped = unwrap(ex);
-                    if (unwrapped instanceof ProcessingException) {
-                        throw (ProcessingException)unwrapped;
-                    }
-                    throw new CascadingRuntimeException(ee.getMessage(),
-                                                        unwrapped);
+                    throw locationTracker.getException("Calling continuation", ex);
+//                    EvaluatorException ee = Context.reportRuntimeError(
+//                                                                       ToolErrorReporter.getMessage("msg.uncaughtJSException",
+//                                                                                                    ex.getMessage()));
+//                    Throwable unwrapped = unwrap(ex);
+//                    if (unwrapped instanceof ProcessingException) {
+//                        throw (ProcessingException)unwrapped;
+//                    }
+//                    throw new CascadingRuntimeException(ee.getMessage(),
+//                                                        unwrapped);
                 } catch (EcmaError ee) {
-                    String msg = ToolErrorReporter.getMessage("msg.uncaughtJSException", ee.toString());
-                    if (ee.getSourceName() != null) {
-                        Context.reportRuntimeError(msg, ee.getSourceName(),
-                                                   ee.getLineNumber(), ee.getLineSource(),
-                                                   ee.getColumnNumber());
-                    } else {
-                        Context.reportRuntimeError(msg);
-                    }
-                    throw new CascadingRuntimeException(ee.getMessage(), ee);
+                    throw locationTracker.getException("Calling continuation", ee);
+//                    String msg = ToolErrorReporter.getMessage("msg.uncaughtJSException", ee.toString());
+//                    if (ee.getSourceName() != null) {
+//                        Context.reportRuntimeError(msg, ee.getSourceName(),
+//                                                   ee.getLineNumber(), ee.getLineSource(),
+//                                                   ee.getColumnNumber());
+//                    } else {
+//                        Context.reportRuntimeError(msg);
+//                    }
+//                    throw new CascadingRuntimeException(ee.getMessage(), ee);
                 }
             } finally {
                 kScope.setLock(false);

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/notification/DefaultNotifyingBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/notification/DefaultNotifyingBuilder.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/notification/DefaultNotifyingBuilder.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/notification/DefaultNotifyingBuilder.java Thu Aug 18 11:06:44 2005
@@ -15,8 +15,8 @@
  */
 package org.apache.cocoon.components.notification;
 
+import org.apache.cocoon.util.ExceptionUtils;
 import org.apache.commons.lang.SystemUtils;
-import org.apache.commons.lang.exception.ExceptionUtils;
 import org.xml.sax.SAXParseException;
 
 import javax.xml.transform.SourceLocator;

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/pipeline/AbstractProcessingPipeline.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/pipeline/AbstractProcessingPipeline.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/pipeline/AbstractProcessingPipeline.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/pipeline/AbstractProcessingPipeline.java Thu Aug 18 11:06:44 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.logger.AbstractLogEnabled;
 import org.apache.avalon.framework.parameters.ParameterException;
@@ -23,7 +31,6 @@
 import org.apache.avalon.framework.service.ServiceException;
 import org.apache.avalon.framework.service.ServiceManager;
 import org.apache.avalon.framework.service.Serviceable;
-
 import org.apache.cocoon.ConnectionResetException;
 import org.apache.cocoon.ProcessingException;
 import org.apache.cocoon.Processor;
@@ -36,23 +43,15 @@
 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.Location;
+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>.
  * It is advisable to inherit from this base class instead of doing a complete
@@ -201,17 +200,17 @@
     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.generator = (Generator) this.newManager.lookup(Generator.ROLE + '/' + role);
         } catch (ServiceException ce) {
-            throw new ProcessingException("Lookup of generator '" + role + "' failed at " + getLocation(param), ce);
+            throw ProcessingException.throwLocated("Lookup of generator '" + role + "' failed", ce, getLocation(param));
         }
         this.generatorSource = source;
         this.generatorParam = param;
@@ -232,17 +231,17 @@
     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));
         }
         try {
             this.transformers.add(this.newManager.lookup(Transformer.ROLE + '/' + role));
         } catch (ServiceException ce) {
-            throw new ProcessingException("Lookup of transformer '"+role+"' failed at " + getLocation(param), ce);
+            throw ProcessingException.throwLocated("Lookup of transformer '"+role+"' failed", ce, getLocation(param));
         }
         this.transformerSources.add(source);
         this.transformerParams.add(param);
@@ -256,23 +255,23 @@
     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.serializer = (Serializer)this.newManager.lookup(Serializer.ROLE + '/' + role);
         } catch (ServiceException ce) {
-            throw new ProcessingException("Lookup of serializer '" + role + "' failed at " + getLocation(param), ce);
+            throw ProcessingException.throwLocated("Lookup of serializer '" + role + "' failed", ce, getLocation(param));
         }
         this.serializerSource = source;
         this.serializerParam = param;
@@ -288,19 +287,19 @@
     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.reader = (Reader)this.newManager.lookup(Reader.ROLE + '/' + role);
         } catch (ServiceException ce) {
-            throw new ProcessingException("Lookup of reader '"+role+"' failed at " + getLocation(param), ce);
+            throw ProcessingException.throwLocated("Lookup of reader '"+role+"' failed", ce, getLocation(param));
         }
         this.readerSource = source;
         this.readerParam = param;
@@ -367,11 +366,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);
         }
     }
 
@@ -541,11 +537,8 @@
                     this.generator.generate();
                 }
             }
-        } catch (ProcessingException e) {
-            throw e;
         } catch (Exception e) {
-            // TODO: Unwrap SAXException ?
-            throw new ProcessingException("Failed to execute pipeline.", e);
+            handleException(e);
         }
 
         return true;
@@ -564,12 +557,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);
         }
     }
 
@@ -855,23 +844,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
@@ -883,10 +876,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/trunk/src/java/org/apache/cocoon/components/pipeline/VirtualProcessingPipeline.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/pipeline/VirtualProcessingPipeline.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/pipeline/VirtualProcessingPipeline.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/pipeline/VirtualProcessingPipeline.java Thu Aug 18 11:06:44 2005
@@ -15,38 +15,37 @@
  */
 package org.apache.cocoon.components.pipeline;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+
 import org.apache.avalon.excalibur.pool.Recyclable;
+import org.apache.avalon.framework.context.Context;
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
 import org.apache.avalon.framework.parameters.Parameters;
 import org.apache.avalon.framework.service.ServiceException;
 import org.apache.avalon.framework.service.ServiceManager;
 import org.apache.avalon.framework.service.Serviceable;
-import org.apache.avalon.framework.context.Context;
-
+import org.apache.cocoon.Constants;
 import org.apache.cocoon.ProcessingException;
 import org.apache.cocoon.Processor;
-import org.apache.cocoon.Constants;
 import org.apache.cocoon.environment.Environment;
 import org.apache.cocoon.environment.SourceResolver;
 import org.apache.cocoon.environment.internal.EnvironmentHelper;
 import org.apache.cocoon.generation.Generator;
 import org.apache.cocoon.serialization.Serializer;
-import org.apache.cocoon.sitemap.SitemapModelComponent;
-import org.apache.cocoon.sitemap.SitemapParameters;
 import org.apache.cocoon.sitemap.SitemapErrorHandler;
+import org.apache.cocoon.sitemap.SitemapModelComponent;
 import org.apache.cocoon.transformation.Transformer;
+import org.apache.cocoon.util.location.Locatable;
+import org.apache.cocoon.util.location.Location;
+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.util.ArrayList;
-import java.util.Iterator;
-
 /**
  * Pipeline used by virtual pipeline components
  *
@@ -157,14 +156,14 @@
     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));
         }
 
         try {
             this.generator = (Generator) this.newManager.lookup(Generator.ROLE + '/' + role);
         } catch (ServiceException ce) {
-            throw new ProcessingException("Lookup of generator '" + role + "' failed at " + getLocation(param), ce);
+            throw ProcessingException.throwLocated("Lookup of generator '" + role + "' failed", ce, getLocation(param));
         }
 
         this.generatorSource = source;
@@ -186,7 +185,7 @@
         try {
             this.transformers.add(this.newManager.lookup(Transformer.ROLE + '/' + role));
         } catch (ServiceException ce) {
-            throw new ProcessingException("Lookup of transformer '"+role+"' failed at " + getLocation(param), ce);
+            throw ProcessingException.throwLocated("Lookup of transformer '"+role+"' failed", ce, getLocation(param));
         }
         this.transformerSources.add(source);
         this.transformerParams.add(param);
@@ -200,14 +199,14 @@
     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));
         }
 
         try {
             this.serializer = (Serializer)this.newManager.lookup(Serializer.ROLE + '/' + role);
         } catch (ServiceException ce) {
-            throw new ProcessingException("Lookup of serializer '" + role + "' failed at " + getLocation(param), ce);
+            throw ProcessingException.throwLocated("Lookup of serializer '" + role + "' failed", ce, getLocation(param));
         }
         this.serializerSource = source;
         this.serializerParam = param;
@@ -605,13 +604,13 @@
         return null;
     }
 
-    protected String getLocation(Parameters param) {
-        String value = null;
-        if (param instanceof SitemapParameters) {
-            value = ((SitemapParameters) param).getStatementLocation();
+    protected Location getLocation(Parameters param) {
+        Location value = null;
+        if (param instanceof Locatable) {
+            value = ((Locatable) param).getLocation();
         }
         if (value == null) {
-            value = "[unknown location]";
+            value = Location.UNKNOWN;
         }
         return value;
     }

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNode.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNode.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNode.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNode.java Thu Aug 18 11:06:44 2005
@@ -18,6 +18,7 @@
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
 import org.apache.cocoon.sitemap.ExecutionContext;
 import org.apache.cocoon.sitemap.SitemapExecutor;
+import org.apache.cocoon.util.location.Location;
 
 /**
  *
@@ -29,7 +30,7 @@
     extends AbstractLogEnabled 
     implements ProcessingNode, ExecutionContext {
 
-    protected String location = "unknown location";
+    protected Location location = Location.UNKNOWN;
 
     /** The type of the component */
     protected String componentName;
@@ -48,14 +49,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/trunk/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNodeBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNodeBuilder.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNodeBuilder.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/AbstractProcessingNodeBuilder.java Thu Aug 18 11:06:44 2005
@@ -15,15 +15,10 @@
  */
 package org.apache.cocoon.components.treeprocessor;
 
-import java.util.Map;
-
 import org.apache.avalon.framework.configuration.Configuration;
 import org.apache.avalon.framework.configuration.ConfigurationException;
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
 import org.apache.avalon.framework.service.ServiceManager;
-import org.apache.cocoon.components.treeprocessor.variables.VariableResolverFactory;
-import org.apache.cocoon.sitemap.PatternException;
-import org.apache.cocoon.sitemap.SitemapParameters;
 
 /**
  *
@@ -52,41 +47,6 @@
      */
     protected boolean hasParameters() {
         return true;
-    }
-
-    /**
-     * 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;
     }
 
     /**

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/ConcreteTreeProcessor.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/ConcreteTreeProcessor.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/ConcreteTreeProcessor.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/ConcreteTreeProcessor.java Thu Aug 18 11:06:44 2005
@@ -46,6 +46,8 @@
 import org.apache.cocoon.sitemap.LeaveSitemapEventListener;
 import org.apache.cocoon.sitemap.SitemapExecutor;
 import org.apache.cocoon.sitemap.SitemapListener;
+import org.apache.cocoon.util.location.Location;
+import org.apache.cocoon.util.location.LocationImpl;
 import org.apache.commons.jci.monitor.FilesystemAlterationListener;
 
 /**
@@ -535,8 +537,8 @@
     /**
      * @see org.apache.cocoon.sitemap.ExecutionContext#getLocation()
      */
-    public String getLocation() {
-        return "Sitemap";
+    public Location getLocation() {
+        return new LocationImpl("[sitemap]", this.wrappingProcessor.source.getURI());
     }
 
     /**

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java Thu Aug 18 11:06:44 2005
@@ -24,6 +24,7 @@
 import org.apache.avalon.excalibur.pool.Recyclable;
 import org.apache.avalon.framework.activity.Disposable;
 import org.apache.avalon.framework.activity.Initializable;
+import org.apache.avalon.framework.configuration.AbstractConfiguration;
 import org.apache.avalon.framework.configuration.Configuration;
 import org.apache.avalon.framework.configuration.ConfigurationException;
 import org.apache.avalon.framework.configuration.SAXConfigurationHandler;
@@ -43,6 +44,8 @@
 import org.apache.cocoon.sitemap.ComponentLocator;
 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 org.apache.excalibur.source.SourceResolver;
 
@@ -458,15 +461,16 @@
      */
     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);
             ((AbstractProcessingNode)node).setSitemapExecutor(this.processor.getSitemapExecutor());
         }
 
         this.itsLifecycle.setupComponent(node, false);
 
         if (node instanceof ParameterizableProcessingNode) {
-            Map params = getParameters(config);
+            Map params = getParameters(config, location);
             ((ParameterizableProcessingNode)node).setParameters(params);
         }
 
@@ -481,23 +485,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.get(config);
+        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("parameter");
 
         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/trunk/src/java/org/apache/cocoon/components/treeprocessor/InvokeContext.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/InvokeContext.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/InvokeContext.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/InvokeContext.java Thu Aug 18 11:06:44 2005
@@ -132,6 +132,14 @@
         this.processingPipelineParameters = parameters;
         this.processingPipelineObjectModel = objectModel;
     }
+    
+    public Parameters getPipelineParameters() {
+        return this.processingPipelineParameters;
+    }
+    
+    public String getPipelineType() {
+        return this.processingPipelineName;
+    }
 
     /**
      * Get the current <code>ProcessingPipeline</code>

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/ProcessingNode.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/ProcessingNode.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/ProcessingNode.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/ProcessingNode.java Thu Aug 18 11:06:44 2005
@@ -18,14 +18,16 @@
 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;
 
 /**
  *
  * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
- * @version CVS $Id: ProcessingNode.java,v 1.3 2004/05/25 13:30:10 cziegeler Exp $
+ * @version CVS $Id$
  */
 
-public interface ProcessingNode extends ThreadSafe {
+public interface ProcessingNode extends ThreadSafe, Locatable {
 
     /**
      * Process environment.
@@ -35,5 +37,5 @@
     /**
      * Get the location of this node.
      */
-    String getLocation();
+    Location getLocation();
 }

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/CallFunctionNode.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/CallFunctionNode.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/CallFunctionNode.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/CallFunctionNode.java Thu Aug 18 11:06:44 2005
@@ -95,10 +95,13 @@
         // the function call, so we invoke it here.
         String continuation = continuationId.resolve(context, env.getObjectModel());
         if (continuation != null && continuation.length() > 0) {
-            interpreter.handleContinuation(continuation, args, redirector);
+            try {
+                interpreter.handleContinuation(continuation, args, redirector);
+            } catch(Exception e) {
+                throw ProcessingException.throwLocated("Sitemap: error calling continuation", e, getLocation());
+            }
             if (!redirector.hasRedirected()) {
-                throw new ProcessingException("<map:call continuation> did not send a response, at " +
-                                              getLocation());
+                throw new ProcessingException("Sitemap: <map:call continuation> did not send a response", getLocation());
             }
             return true;
         }
@@ -107,15 +110,18 @@
         // the specified function
         String name = functionName.resolve(context, objectModel);
         if (name != null && name.length() > 0) {
-            interpreter.callFunction(name, args, redirector);
+            try {
+                interpreter.callFunction(name, args, redirector);
+            } catch(Exception e) {
+                throw ProcessingException.throwLocated("Sitemap: error calling function '" + name + "'", e, getLocation());
+            }
             if (!redirector.hasRedirected()) {
-                throw new ProcessingException("<map:call function> did not send a response, at " +
-                                              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("No function nor continuation given in <map:call function> at " + getLocation());
+        throw new ProcessingException("Sitemap: no function nor continuation given in <map:call function>", getLocation());
     }
 }

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/ErrorHandlerHelper.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/ErrorHandlerHelper.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/ErrorHandlerHelper.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/ErrorHandlerHelper.java Thu Aug 18 11:06:44 2005
@@ -30,6 +30,7 @@
 import org.apache.cocoon.components.treeprocessor.ProcessingNode;
 import org.apache.cocoon.environment.Environment;
 import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.sitemap.SitemapParameters;
 
 import java.io.IOException;
 import java.util.Map;
@@ -186,6 +187,7 @@
             errorContext.enableLogging(getLogger());
             errorContext.setRedirector(context.getRedirector());
             errorContext.service(this.manager);
+            errorContext.inform(context.getPipelineType(), context.getPipelineParameters(), env.getObjectModel());
             try {
                 // Process error handling node
                 if (node.invoke(env, errorContext)) {

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/FlowNode.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/FlowNode.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/FlowNode.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/FlowNode.java Thu Aug 18 11:06:44 2005
@@ -60,8 +60,8 @@
             this.interpreterSelector = (ServiceSelector) manager.lookup(Interpreter.ROLE + "Selector");
             // 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 (ServiceException e) {
             throw e;
         } catch (Exception e) {

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/MountNode.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/MountNode.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/MountNode.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/MountNode.java Thu Aug 18 11:06:44 2005
@@ -27,6 +27,7 @@
 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;
 
 /**
@@ -112,6 +113,10 @@
             }
             // Processor will create its own pipelines
             return processor.process(env);
+        } catch(Exception e) {
+            // Wrap with our location
+            throw ProcessingException.throwLocated("Sitemap: error when calling sub-sitemap", e, getLocation());
+
         } finally {
             // Restore context
             env.setURI(oldPrefix, oldURI);

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SerializeNode.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SerializeNode.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SerializeNode.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SerializeNode.java Thu Aug 18 11:06:44 2005
@@ -19,6 +19,7 @@
 
 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;
@@ -26,7 +27,9 @@
 import org.apache.cocoon.components.treeprocessor.ProcessingNode;
 import org.apache.cocoon.components.treeprocessor.variables.VariableResolver;
 import org.apache.cocoon.environment.Environment;
+import org.apache.cocoon.sitemap.PatternException;
 import org.apache.cocoon.sitemap.SitemapExecutor;
+import org.apache.cocoon.util.location.Location;
 /**
  *
  * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
@@ -134,7 +137,6 @@
         if (! context.isBuildingPipelineOnly()) {
             // Process pipeline
             return pipeline.process(env);
-
         }
         // Return true : pipeline is finished.
         return true;

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/variables/VariableResolver.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/variables/VariableResolver.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/variables/VariableResolver.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/variables/VariableResolver.java Thu Aug 18 11:06:44 2005
@@ -15,17 +15,18 @@
  */
 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.
  *
@@ -54,8 +55,9 @@
             VariableResolver other = (VariableResolver)object;
             return (this.originalExpr == null && other.originalExpr == null) ||
                    (this.originalExpr.equals(other.originalExpr));
+        } else {
+            return false;
         }
-        return false;
     }
 
     /**
@@ -85,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();
@@ -118,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);
         }

Added: cocoon/trunk/src/java/org/apache/cocoon/generation/ExceptionGenerator.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/generation/ExceptionGenerator.java?rev=233343&view=auto
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/generation/ExceptionGenerator.java (added)
+++ cocoon/trunk/src/java/org/apache/cocoon/generation/ExceptionGenerator.java Thu Aug 18 11:06:44 2005
@@ -0,0 +1,151 @@
+/*
+ * Copyright 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.
+ * 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.
+ */
+package org.apache.cocoon.generation;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.util.ExceptionUtils;
+import org.apache.cocoon.util.location.LocatableException;
+import org.apache.cocoon.util.location.Location;
+import org.apache.cocoon.util.location.MultiLocatable;
+import org.apache.cocoon.xml.AttributesImpl;
+import org.apache.commons.lang.SystemUtils;
+import org.xml.sax.Attributes;
+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;
+    
+    public static String EXCEPTION_NS = "http://apache.org/cocoon/exception/1.0";
+
+    public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) throws ProcessingException, SAXException, IOException {
+        super.setup(resolver, objectModel, src, par);
+        thr = (Throwable)objectModel.get(ObjectModelHelper.THROWABLE_OBJECT);
+        if (thr == null) {
+            throw new ProcessingException("ExceptionGenerator should be used in <map:handle-errors>");
+        }
+    }
+
+    public void generate() throws IOException, SAXException, ProcessingException {
+        this.contentHandler.startDocument();
+        toSAX(thr, this.contentHandler);
+        this.contentHandler.endDocument();
+    }
+    
+    public static void toSAX(Throwable thr, ContentHandler handler) throws SAXException {
+        Throwable root = ExceptionUtils.getRootCause(thr);
+        if (root == null) root = thr;
+
+        AttributesImpl attr = new AttributesImpl();
+        handler.startPrefixMapping("ex", EXCEPTION_NS);
+        attr.addCDATAAttribute("class", root.getClass().getName());
+        handler.startElement(EXCEPTION_NS, "exception-report", "ex:exception-report", attr);
+        
+        // Root exception location
+        Location loc = ExceptionUtils.getLocation(root);        
+        if (loc != null) {
+            attr.clear();
+            dumpLocation(loc, attr, handler);
+        }
+
+        // Root exception message
+        attr.clear();
+        String message = root instanceof LocatableException ? ((LocatableException)root).getRawMessage() : root.getMessage();
+        simpleElement("message", attr, message, handler);
+        
+        // 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) {
+            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, 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, "cocoon-stacktrace", "ex:cocoon-stacktrace");
+        
+        // Root exception stacktrace
+        attr.clear();
+        simpleElement("stacktrace", attr, ExceptionUtils.getStackTrace(root), handler);
+        
+        // Full stack trace (if exception is chained)
+        if (thr != root) {
+            String trace = SystemUtils.isJavaVersionAtLeast(140) ?
+                    ExceptionUtils.getStackTrace(thr) :
+                    ExceptionUtils.getFullStackTrace(thr);
+
+            simpleElement("full-stacktrace", attr, trace, handler);
+        }
+        
+        handler.endElement(EXCEPTION_NS, "exception-report", "ex:exception-report");
+        handler.endPrefixMapping("ex");
+    }
+    
+    private static void dumpLocation(Location loc, AttributesImpl attr, ContentHandler handler) throws SAXException {
+        attr.addCDATAAttribute("uri", loc.getURI());
+        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 {
+        handler.startElement(EXCEPTION_NS, name, "ex:" + name, attr);
+        if (value != null && value.length() > 0) {
+            handler.characters(value.toCharArray(), 0, value.length());
+        }
+        handler.endElement(EXCEPTION_NS, name, "ex:" + name);
+    }
+}

Propchange: cocoon/trunk/src/java/org/apache/cocoon/generation/ExceptionGenerator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/trunk/src/java/org/apache/cocoon/generation/ExceptionGenerator.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: cocoon/trunk/src/java/org/apache/cocoon/selection/ExceptionSelector.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/selection/ExceptionSelector.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/selection/ExceptionSelector.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/selection/ExceptionSelector.java Thu Aug 18 11:06:44 2005
@@ -23,7 +23,7 @@
 import org.apache.avalon.framework.parameters.Parameters;
 import org.apache.cocoon.environment.ObjectModelHelper;
 import org.apache.cocoon.util.ClassUtils;
-import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.cocoon.util.ExceptionUtils;
 
 /**
  * In a &lt;map:handle-errors>, selects depending on the exception that caused the error.
@@ -52,7 +52,7 @@
  * @author <a href="mailto:bluetkemeier@s-und-n.de">Bj&ouml;rn L&uuml;tkemeier</a>
  * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
  * @since 2.1
- * @version CVS $Id: ExceptionSelector.java,v 1.8 2004/06/24 07:32:53 cziegeler Exp $
+ * @version CVS $Id$
  */
 
 public class ExceptionSelector extends AbstractSwitchSelector implements Configurable {

Modified: cocoon/trunk/src/java/org/apache/cocoon/sitemap/ExecutionContext.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/sitemap/ExecutionContext.java?rev=233343&r1=233342&r2=233343&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/sitemap/ExecutionContext.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/sitemap/ExecutionContext.java Thu Aug 18 11:06:44 2005
@@ -15,6 +15,9 @@
  */
 package org.apache.cocoon.sitemap;
 
+import org.apache.cocoon.util.location.Locatable;
+import org.apache.cocoon.util.location.Location;
+
 
 /**
  * This context contains information about the current statement that should
@@ -23,14 +26,14 @@
  * TODO - This is not finished yet!
  * 
  * @since 2.2
- * @version CVS $Id: ExecutionContext.java,v 1.1 2004/06/09 11:59:23 cziegeler Exp $
+ * @version CVS $Id$
  */
-public interface ExecutionContext {
+public interface ExecutionContext extends Locatable {
     
     /**
      * Return the location of the statement in the sitemap.
      */
-    String getLocation();
+    Location getLocation();
     
     /**
      * Return the component type