You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by mr...@apache.org on 2005/11/27 08:10:27 UTC

svn commit: r349187 [4/6] - in /struts/flow/trunk: ./ src/examples/WEB-INF/ src/examples/WEB-INF/guess/ src/examples/WEB-INF/portlet/ src/examples/WEB-INF/remote/ src/examples/remote/ src/java/ src/java/org/apache/struts/flow/ src/java/org/apache/strut...

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/javascript/fom/PageLocalScopeHolder.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/javascript/fom/PageLocalScopeHolder.java?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/javascript/fom/PageLocalScopeHolder.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/javascript/fom/PageLocalScopeHolder.java Sat Nov 26 23:10:08 2005
@@ -0,0 +1,89 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts.flow.core.javascript.fom;
+
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.ScriptableObject;
+
+/**
+ * @version CVS $Id: PageLocalScopeHolder.java 36239 2004-08-11 18:28:06Z vgritsenko $
+ */
+public class PageLocalScopeHolder implements PageLocalScope {
+
+    private Scriptable scope;
+    private PageLocalScopeImpl delegate;
+
+    public PageLocalScopeHolder(Scriptable scope) {
+        this.scope = scope;
+    }
+
+    public boolean has(PageLocal local, String name) {
+        return delegate.has(local, name);
+    }
+
+    public boolean has(PageLocal local, int index) {
+        return delegate.has(local, index);
+    }
+
+    public Object get(PageLocal local, String name) {
+        return delegate.get(local, name);
+    }
+
+    public Object get(PageLocal local, int index) {
+        return delegate.get(local, index);
+    }
+
+    public void put(PageLocal local, String name, Object value) {
+        delegate.put(local, name, value);
+    }
+
+    public void put(PageLocal local, int index, Object value) {
+        delegate.put(local, index, value);
+    }
+
+    public void delete(PageLocal local, String name) {
+        delegate.delete(local, name);
+    }
+
+    public void delete(PageLocal local, int index) {
+        delegate.delete(local, index);
+    }
+
+    public Object[] getIds(PageLocal local) {
+        return delegate.getIds(local);
+    }
+
+    public Object getDefaultValue(PageLocal local, Class hint) {
+        return delegate.getDefaultValue(local, hint);
+    }
+
+    public void setDelegate(PageLocalScopeImpl delegate) {
+        this.delegate = delegate;
+    }
+
+    public PageLocalScopeImpl getDelegate() {
+        return delegate;
+    }
+
+    public PageLocal createPageLocal() {
+        PageLocalImpl pageLocal = new PageLocalImpl();
+        pageLocal.setPrototype(ScriptableObject.getClassPrototype(scope,
+                                                                  pageLocal.getClassName()));
+        pageLocal.setParentScope(scope);
+        pageLocal.setPageLocalScope(this);
+        return pageLocal;
+    }
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/javascript/fom/PageLocalScopeHolder.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/javascript/fom/PageLocalScopeImpl.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/javascript/fom/PageLocalScopeImpl.java?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/javascript/fom/PageLocalScopeImpl.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/javascript/fom/PageLocalScopeImpl.java Sat Nov 26 23:10:08 2005
@@ -0,0 +1,136 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts.flow.core.javascript.fom;
+
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.Scriptable;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * @version CVS $Id: PageLocalScopeImpl.java 36239 2004-08-11 18:28:06Z vgritsenko $
+ */
+public class PageLocalScopeImpl implements PageLocalScope {
+
+    private Map locals;
+    private Scriptable scope;
+
+    public PageLocalScopeImpl(Scriptable scope) {
+        locals = new HashMap();
+        this.scope = scope;
+    }
+
+    private Scriptable newObject() {
+        try {
+            return Context.getCurrentContext().newObject(scope);
+        } catch (Exception ignored) {
+            // can't happen here
+            ignored.printStackTrace();
+            throw new Error("error: " + ignored);
+        }
+    }
+
+    private PageLocalScopeImpl(PageLocalScopeImpl toBeCloned) {
+        this.scope = toBeCloned.scope;
+        locals = new HashMap();
+        Iterator iter = toBeCloned.locals.entrySet().iterator();
+        while (iter.hasNext()) {
+            Map.Entry e = (Map.Entry)iter.next();
+            Object key = e.getKey();
+            Object value = e.getValue();
+            // clone it
+            Scriptable obj = (Scriptable)value;
+            Scriptable newObj = newObject();
+            Object[] ids = obj.getIds();
+            for (int i = 0; i < ids.length; i++) {
+                String name = ids[i].toString();
+                newObj.put(name, newObj, obj.get(name, obj));
+            }
+            value = newObj;
+            locals.put(key, value);
+        }
+   }
+
+    private Scriptable resolve(PageLocal local) {
+        final Object id = local.getId();
+        Scriptable result = (Scriptable)locals.get(id);
+        if (result == null) {
+            locals.put(id, result = newObject());
+        }
+        return result;
+    }
+
+    public boolean has(PageLocal local, String name) {
+        Scriptable obj = resolve(local);
+        return obj.has(name, obj);
+    }
+
+    public boolean has(PageLocal local, int index) {
+        Scriptable obj = resolve(local);
+        return obj.has(index, obj);
+    }
+
+    public Object get(PageLocal local, String name) {
+        Scriptable obj = resolve(local);
+        return obj.get(name, obj);
+    }
+
+    public Object get(PageLocal local, int index) {
+        Scriptable obj = resolve(local);
+        return obj.get(index, obj);
+    }
+
+    public void put(PageLocal local, String name, Object value) {
+        Scriptable obj = resolve(local);
+        obj.put(name, obj, value);
+    }
+
+    public void put(PageLocal local, int index, Object value) {
+        Scriptable obj = resolve(local);
+        obj.put(index, obj, value);
+    }
+
+    public void delete(PageLocal local, String name) {
+        Scriptable obj = resolve(local);
+        obj.delete(name);
+    }
+
+    public void delete(PageLocal local, int index) {
+        Scriptable obj = resolve(local);
+        obj.delete(index);
+    }
+
+    public Object[] getIds(PageLocal local) {
+        Scriptable obj = resolve(local);
+        return obj.getIds();
+    }
+
+    public Object getDefaultValue(PageLocal local, Class hint) {
+        Scriptable obj = resolve(local);
+        return obj.getDefaultValue(hint);
+    }
+
+    public PageLocalScopeImpl duplicate() {
+        return new PageLocalScopeImpl(this);
+    }
+
+    public PageLocal createPageLocal() {
+        // not used
+        return null;
+    }
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/javascript/fom/PageLocalScopeImpl.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/javascript/fom/fom_system.js
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/javascript/fom/fom_system.js?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/javascript/fom/fom_system.js (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/javascript/fom/fom_system.js Sat Nov 26 23:10:08 2005
@@ -0,0 +1,56 @@
+/*
+* Copyright 1999-2004 The Apache Software Foundation
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+FOM_Flow.suicide = new Continuation();
+
+FOM_Flow.prototype.forwardAndWait = function(uri, bizData, fun, ttl) {
+    this.forward(uri, bizData,
+                  new FOM_WebContinuation(new Continuation(), 
+                                          this.continuation, ttl));
+    if (fun) {
+        if (!(fun instanceof Function)) {
+            throw "Expected a function instead of: " + fun;
+        }
+        fun();
+    }
+    FOM_Flow.suicide();
+}
+
+FOM_Flow.prototype.handleContinuation = function(k, wk) {
+    k(wk);
+}
+
+FOM_Flow.prototype.createWebContinuation = function(ttl) {
+   var wk = this.makeWebContinuation(new Continuation(), ttl);
+   wk.setBookmark(true);
+   return wk;
+}
+
+/**
+ * Exit the current flowscript invocation.
+ * <p>
+ * There are some flowscript use cases where we want to stop the current 
+ * flowscript without creating a continuation, as we don't want the user 
+ * to go back to the script.
+ * <p>
+ * An example is a "login" function where the caller function expects this 
+ * function to exit only if login is successful, but that has to handle 
+ * e.g. a registration process that includes a "cancel" button.
+ */
+FOM_Flow.prototype.exit = function() {
+    FOM_Flow.suicide();
+}
+
+

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/javascript/fom/fom_system.js
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/location/Locatable.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/location/Locatable.java?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/location/Locatable.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/location/Locatable.java Sat Nov 26 23:10:08 2005
@@ -0,0 +1,32 @@
+/*
+ * 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.struts.flow.core.location;
+
+/**
+ * A interface that should be implemented by objects knowning their location (i.e. where they
+ * have been created from).
+ * 
+ * @since 2.1.8
+ * @version $Id: Locatable.java 233343 2005-08-18 18:06:44Z sylvain $
+ */
+public interface Locatable {
+    /**
+     * Get the location of this object
+     * 
+     * @return the location
+     */
+    Location getLocation();
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/location/Locatable.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocatableException.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocatableException.java?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocatableException.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocatableException.java Sat Nov 26 23:10:08 2005
@@ -0,0 +1,41 @@
+/*
+ * 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.struts.flow.core.location;
+
+/**
+ * Extension of {@link Locatable} for exceptions.
+ * <p>
+ * In order to dump location information in the stacktrace, the <code>getMessage()</code> method of
+ * a {@link Locatable} exception should return a concatenation of the raw message (given in the
+ * constructor) and the exception's location, e.g. "<code>foo failed (file.xml:12:3)</code>". However,
+ * {@link Locatable}-aware classes will want to handle the raw message (i.e. "<code>foo failed</code>")
+ * and location separately. This interface gives access to the raw message.
+ * <p>
+ * <strong>Note:</strong> care should be taken for locatable exceptions to use only immutable and
+ * serializable implementations of {@link Location} ({@see org.apache.struts.flow.core.location.LocationImpl#get(Location)}).
+ * 
+ * @since 2.1.8
+ * @version $Id: LocatableException.java 233343 2005-08-18 18:06:44Z sylvain $
+ */
+public interface LocatableException extends Locatable {
+    
+    /**
+     * Get the raw message of the exception (the one used in the constructor)
+     * 
+     * @return the raw message
+     */
+    public String getRawMessage();
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocatableException.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocatedException.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocatedException.java?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocatedException.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocatedException.java Sat Nov 26 23:10:08 2005
@@ -0,0 +1,154 @@
+/*
+ * 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.struts.flow.core.location;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.commons.lang.exception.NestableException;
+
+/**
+ * A cascading and located <code>Exception</code>. It is also {@link MultiLocatable} to easily build
+ * stack traces.
+ *
+ * @since 2.1.8
+ * @version $Id: LocatedException.java 291771 2005-09-26 22:32:55Z vgritsenko $
+ */
+public class LocatedException extends NestableException
+                              implements LocatableException, MultiLocatable {
+
+    private List locations;
+
+    public LocatedException(String message) {
+        this(message, null, null);
+    }
+
+    public LocatedException(String message, Throwable cause) {
+        this(message, cause, null);
+    }
+
+    public LocatedException(String message, Location location) {
+        this(message, null, location);
+    }
+
+    public LocatedException(String message, Throwable cause, Location location) {
+        super(message, cause);
+        ensureCauseChainIsSet(cause);
+        addCauseLocations(this, cause);
+        addLocation(location);
+    }
+
+    /**
+     * Crawl the cause chain and ensure causes are properly set using {@ link Throwable#initCause}.
+     * This is needed because some exceptions (e.g. SAXException) don't have a {@ link Throwable#getCause}
+     * that is used to print stacktraces.
+     */
+    public static void ensureCauseChainIsSet(Throwable thr) {
+        // Loop either until null or encountering exceptions that use this method.
+        while (thr != null && !(thr instanceof LocatedRuntimeException) && !(thr instanceof LocatedException)) {
+            Throwable parent = ExceptionUtils.getCause(thr);
+            if (thr.getCause() == null && parent != null) {
+                thr.initCause(parent);
+            }
+            thr = parent;
+        }
+    }
+
+    /**
+     * Add to the location stack all locations of an exception chain. This allows to have all possible
+     * location information in the stacktrace, as some exceptions like SAXParseException don't output
+     * their location in printStackTrace().
+     * <p>
+     * Traversal of the call chain stops at the first <code>Locatable</code> exception which is supposed
+     * to handle the loction of its causes by itself.
+     * <p>
+     * This method is static as a convenience for {@link LocatedRuntimeException other implementations}
+     * of locatable exceptions.
+     *
+     * @param self the current locatable exception
+     * @param cause a cause of <code>self</code>
+     */
+    public static void addCauseLocations(MultiLocatable self, Throwable cause) {
+        if (cause == null || cause instanceof Locatable) {
+            // Locatable handles its location itself
+            return;
+        }
+        // Add parent location first
+        addCauseLocations(self, ExceptionUtils.getCause(cause));
+        // then ourselve's
+        Location loc = LocationUtils.getLocation(cause);
+        if (LocationUtils.isKnown(loc)) {
+            // Get the exception's short name
+            String name = cause.getClass().getName();
+            int pos = name.lastIndexOf('.');
+            if (pos != -1) {
+                name = name.substring(pos+1);
+            }
+            loc = new LocationImpl("[" + name + "]", loc.getURI(), loc.getLineNumber(), loc.getColumnNumber());
+            self.addLocation(loc);
+        }
+    }
+
+    public Location getLocation() {
+        return locations == null ? null : (Location)locations.get(0);
+    }
+
+    public List getLocations() {
+        return locations == null ? Collections.EMPTY_LIST : locations;
+    }
+
+    public String getRawMessage() {
+        return super.getMessage();
+    }
+
+    /**
+     * Standard way of building the message of a {@link LocatableException}, as a Java-like
+     * stack trace of locations.
+     *
+     * @param message the exception's message, given by <code>super.getMessage()</code> (can be null)
+     * @param locations the location list (can be null)
+     *
+     * @return the message, or <code>null</code> no message and locations were given.
+     */
+    public static String getMessage(String message, List locations) {
+        if (locations == null || locations.isEmpty()) {
+            return message;
+        }
+
+        // Produce a Java-like stacktrace with locations
+        StringBuffer buf = message == null ? new StringBuffer() : new StringBuffer(message);
+        for (int i = 0; i < locations.size(); i++) {
+            buf.append("\n\tat ").append(LocationUtils.toString((Location)locations.get(i)));
+        }
+        return buf.toString();
+    }
+
+    public String getMessage() {
+        return getMessage(super.getMessage(), locations);
+    }
+
+    public void addLocation(Location loc) {
+        if (LocationUtils.isUnknown(loc))
+            return;
+
+        if (locations == null) {
+            this.locations = new ArrayList(1); // Start small
+        }
+        locations.add(LocationImpl.get(loc));
+    }
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocatedException.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocatedRuntimeException.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocatedRuntimeException.java?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocatedRuntimeException.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocatedRuntimeException.java Sat Nov 26 23:10:08 2005
@@ -0,0 +1,96 @@
+/*
+ * 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.struts.flow.core.location;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.lang.exception.NestableRuntimeException;
+
+/**
+ * A cascading and located <code>RuntimeException</code>. It is also {@link MultiLocatable} to easily build
+ * location stack traces.
+ * <p>
+ * If a <code>LocatedRuntimeException</code> is built with a location and a cause which is also a
+ * <code>LocatedRuntimeException</code>, then the default behavior is to add the location to the cause
+ * exception and immediately rethrow the cause. This avoids exception nesting and builds a location
+ * stack.
+ * 
+ * @since 2.1.8
+ * @version $Id: LocatedRuntimeException.java 290845 2005-09-21 22:04:27Z sylvain $
+ */
+public class LocatedRuntimeException extends NestableRuntimeException implements LocatableException, MultiLocatable {
+    
+    private List locations;
+
+    public LocatedRuntimeException(String message) {
+        this(message, null, null, true);
+    }
+    
+    public LocatedRuntimeException(String message, Throwable cause) throws LocatedRuntimeException {
+        this(message, cause, null, true);
+    }
+    
+    public LocatedRuntimeException(String message, Location location) {
+        this(message, null, location, true);
+    }
+    
+    public LocatedRuntimeException(String message, Throwable cause, Location location) throws LocatedRuntimeException {
+        this(message, cause, location, true);
+    }
+
+    public LocatedRuntimeException(String message, Throwable cause, Location location, boolean rethrowLocated)
+        throws LocatedRuntimeException {
+        super(message, cause);
+        if (rethrowLocated && cause instanceof LocatedRuntimeException) {
+            LocatedRuntimeException lreCause = (LocatedRuntimeException)cause;
+            lreCause.addLocation(location);
+            // Rethrow the cause
+            throw lreCause;
+        }
+
+        LocatedException.ensureCauseChainIsSet(cause);
+        LocatedException.addCauseLocations(this, cause);
+        addLocation(location);
+    }
+
+    public Location getLocation() {
+        return locations == null ? null : (Location)locations.get(0);
+    }
+
+    public List getLocations() {
+        return locations == null ? Collections.EMPTY_LIST : locations;
+    }
+
+    public String getRawMessage() {
+        return super.getMessage();
+    }
+
+    public String getMessage() {
+        return LocatedException.getMessage(super.getMessage(), locations);
+    }
+    
+    public void addLocation(Location loc) {
+        if (LocationUtils.isUnknown(loc))
+            return;
+
+        if (locations == null) {
+            this.locations = new ArrayList(1); // Start small
+        }
+        locations.add(LocationImpl.get(loc));
+    }
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocatedRuntimeException.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/location/Location.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/location/Location.java?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/location/Location.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/location/Location.java Sat Nov 26 23:10:08 2005
@@ -0,0 +1,62 @@
+/*
+ * 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.struts.flow.core.location;
+
+
+/**
+ * A location in a resource. The location is composed of the URI of the resource, and 
+ * the line and column numbers within that resource (when available), along with a description.
+ * <p>
+ * Locations are mostly provided by {@link Locatable}s objects.
+ * 
+ * @since 2.1.8
+ * @version $Id: Location.java 233343 2005-08-18 18:06:44Z sylvain $
+ */
+public interface Location {
+    
+    /**
+     * Constant for unknown locations.
+     */
+    public static final Location UNKNOWN = LocationImpl.UNKNOWN;
+    
+    /**
+     * Get the description of this location
+     * 
+     * @return the description (can be <code>null</code>)
+     */
+    public String getDescription();
+    
+    /**
+     * Get the URI of this location
+     * 
+     * @return the URI (<code>null</code> if unknown).
+     */
+    public String getURI();
+    /**
+     * Get the line number of this location
+     * 
+     * @return the line number (<code>-1</code> if unknown)
+     */
+    public int getLineNumber();
+    
+    /**
+     * Get the column number of this location
+     * 
+     * @return the column number (<code>-1</code> if unknown)
+     */
+    public int getColumnNumber();
+
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/location/Location.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocationAttributes.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocationAttributes.java?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocationAttributes.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocationAttributes.java Sat Nov 26 23:10:08 2005
@@ -0,0 +1,349 @@
+/*
+ * 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.struts.flow.core.location;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ * A class to handle location information stored in attributes.
+ * These attributes are typically setup using {@link org.apache.struts.flow.core.location.LocationAttributes.Pipe}
+ * which augments the SAX stream with additional attributes, e.g.:
+ * <pre>
+ * &lt;root xmlns:loc="http://apache.org/cocoon/location"
+ *       loc:src="file://path/to/file.xml"
+ *       loc:line="1" loc:column="1"&gt;
+ *   &lt;foo loc:src="file://path/to/file.xml" loc:line="2" loc:column="3"/&gt;
+ * &lt;/root&gt;
+ * </pre>
+ * 
+ * @see org.apache.struts.flow.core.location.LocationAttributes.Pipe
+ * @since 2.1.8
+ * @version $Id: LocationAttributes.java 328390 2005-10-25 15:37:05Z sylvain $
+ */
+public class LocationAttributes {
+    /** Prefix for the location namespace */
+    public static final String PREFIX = "loc";
+    /** Namespace URI for location attributes */
+    public static final String URI = "http://apache.org/cocoon/location";
+
+    /** Attribute name for the location URI */
+    public static final String SRC_ATTR  = "src";
+    /** Attribute name for the line number */
+    public static final String LINE_ATTR = "line";
+    /** Attribute name for the column number */
+    public static final String COL_ATTR  = "column";
+
+    /** Attribute qualified name for the location URI */
+    public static final String Q_SRC_ATTR  = "loc:src";
+    /** Attribute qualified name for the line number */
+    public static final String Q_LINE_ATTR = "loc:line";
+    /** Attribute qualified name for the column number */
+    public static final String Q_COL_ATTR  = "loc:column";
+    
+    // Private constructor, we only have static methods
+    private LocationAttributes() {
+        // Nothing
+    }
+    
+    /**
+     * Add location attributes to a set of SAX attributes.
+     * 
+     * @param locator the <code>Locator</code> (can be null)
+     * @param attrs the <code>Attributes</code> where locator information should be added
+     * @return
+     */
+    public static Attributes addLocationAttributes(Locator locator, Attributes attrs) {
+        if (locator == null || attrs.getIndex(URI, SRC_ATTR) != -1) {
+            // No location information known, or already has it
+            return attrs;
+        }
+        
+        // Get an AttributeImpl so that we can add new attributes.
+        AttributesImpl newAttrs = attrs instanceof AttributesImpl ?
+            (AttributesImpl)attrs : new AttributesImpl(attrs);
+
+        newAttrs.addAttribute(URI, SRC_ATTR, Q_SRC_ATTR, "CDATA", locator.getSystemId());
+        newAttrs.addAttribute(URI, LINE_ATTR, Q_LINE_ATTR, "CDATA", Integer.toString(locator.getLineNumber()));
+        newAttrs.addAttribute(URI, COL_ATTR, Q_COL_ATTR, "CDATA", Integer.toString(locator.getColumnNumber()));
+        
+        return newAttrs;
+    }
+    
+    /**
+     * Returns the {@link Location} of an element (SAX flavor).
+     * 
+     * @param attrs the element's attributes that hold the location information
+     * @param description a description for the location (can be null)
+     * @return a {@link Location} object
+     */
+    public static Location getLocation(Attributes attrs, String description) {
+        String src = attrs.getValue(URI, SRC_ATTR);
+        if (src == null) {
+            return Location.UNKNOWN;
+        }
+        
+        return new LocationImpl(description, src, getLine(attrs), getColumn(attrs));
+    }
+
+    /**
+     * Returns the location of an element (SAX flavor). If the location is to be kept
+     * into an object built from this element, consider using {@link #getLocation(Attributes)}
+     * and the {@link Locatable} interface.
+     * 
+     * @param attrs the element's attributes that hold the location information
+     * @return a location string as defined by {@link Location#toString()}.
+     */
+    public static String getLocationString(Attributes attrs) {
+        String src = attrs.getValue(URI, SRC_ATTR);
+        if (src == null) {
+            return LocationUtils.UNKNOWN_STRING;
+        }
+        
+        return src + ":" + attrs.getValue(URI, LINE_ATTR) + ":" + attrs.getValue(URI, COL_ATTR);
+    }
+    
+    /**
+     * Returns the URI of an element (SAX flavor)
+     * 
+     * @param attrs the element's attributes that hold the location information
+     * @return the element's URI or "<code>[unknown location]</code>" if <code>attrs</code>
+     *         has no location information.
+     */
+    public static String getURI(Attributes attrs) {
+        String src = attrs.getValue(URI, SRC_ATTR);
+        return src != null ? src : LocationUtils.UNKNOWN_STRING;
+    }
+    
+    /**
+     * Returns the line number of an element (SAX flavor)
+     * 
+     * @param attrs the element's attributes that hold the location information
+     * @return the element's line number or <code>-1</code> if <code>attrs</code>
+     *         has no location information.
+     */
+    public static int getLine(Attributes attrs) {
+        String line = attrs.getValue(URI, LINE_ATTR);
+        return line != null ? Integer.parseInt(line) : -1;
+    }
+    
+    /**
+     * Returns the column number of an element (SAX flavor)
+     * 
+     * @param attrs the element's attributes that hold the location information
+     * @return the element's column number or <code>-1</code> if <code>attrs</code>
+     *         has no location information.
+     */
+    public static int getColumn(Attributes attrs) {
+        String col = attrs.getValue(URI, COL_ATTR);
+        return col != null ? Integer.parseInt(col) : -1;
+    }
+    
+    /**
+     * Returns the {@link Location} of an element (DOM flavor).
+     * 
+     * @param attrs the element that holds the location information
+     * @param description a description for the location (if <code>null</code>, the element's name is used)
+     * @return a {@link Location} object
+     */
+    public static Location getLocation(Element elem, String description) {
+        Attr srcAttr = elem.getAttributeNodeNS(URI, SRC_ATTR);
+        if (srcAttr == null) {
+            return Location.UNKNOWN;
+        }
+
+        return new LocationImpl(description == null ? elem.getNodeName() : description,
+                srcAttr.getValue(), getLine(elem), getColumn(elem));
+    }
+    
+    /**
+     * Same as <code>getLocation(elem, null)</code>.
+     */
+    public static Location getLocation(Element elem) {
+        return getLocation(elem, null);
+    }
+   
+
+    /**
+     * Returns the location of an element that has been processed by this pipe (DOM flavor).
+     * If the location is to be kept into an object built from this element, consider using
+     * {@link #getLocation(Element)} and the {@link Locatable} interface.
+     * 
+     * @param elem the element that holds the location information
+     * @return a location string as defined by {@link Location#toString()}.
+     */
+    public static String getLocationString(Element elem) {
+        Attr srcAttr = elem.getAttributeNodeNS(URI, SRC_ATTR);
+        if (srcAttr == null) {
+            return LocationUtils.UNKNOWN_STRING;
+        }
+        
+        return srcAttr.getValue() + ":" + elem.getAttributeNS(URI, LINE_ATTR) + ":" + elem.getAttributeNS(URI, COL_ATTR);
+    }
+    
+    /**
+     * Returns the URI of an element (DOM flavor)
+     * 
+     * @param elem the element that holds the location information
+     * @return the element's URI or "<code>[unknown location]</code>" if <code>elem</code>
+     *         has no location information.
+     */
+    public static String getURI(Element elem) {
+        Attr attr = elem.getAttributeNodeNS(URI, SRC_ATTR);
+        return attr != null ? attr.getValue() : LocationUtils.UNKNOWN_STRING;
+    }
+
+    /**
+     * Returns the line number of an element (DOM flavor)
+     * 
+     * @param elem the element that holds the location information
+     * @return the element's line number or <code>-1</code> if <code>elem</code>
+     *         has no location information.
+     */
+    public static int getLine(Element elem) {
+        Attr attr = elem.getAttributeNodeNS(URI, LINE_ATTR);
+        return attr != null ? Integer.parseInt(attr.getValue()) : -1;
+    }
+
+    /**
+     * Returns the column number of an element (DOM flavor)
+     * 
+     * @param elem the element that holds the location information
+     * @return the element's column number or <code>-1</code> if <code>elem</code>
+     *         has no location information.
+     */
+    public static int getColumn(Element elem) {
+        Attr attr = elem.getAttributeNodeNS(URI, COL_ATTR);
+        return attr != null ? Integer.parseInt(attr.getValue()) : -1;
+    }
+    
+    /**
+     * Remove the location attributes from a DOM element.
+     * 
+     * @param elem the element to remove the location attributes from.
+     * @param recurse if <code>true</code>, also remove location attributes on descendant elements.
+     */
+    public static void remove(Element elem, boolean recurse) {
+        elem.removeAttributeNS(URI, SRC_ATTR);
+        elem.removeAttributeNS(URI, LINE_ATTR);
+        elem.removeAttributeNS(URI, COL_ATTR);
+        if (recurse) {
+            NodeList children = elem.getChildNodes();
+            for (int i = 0; i < children.getLength(); i++) {
+                Node child = children.item(i);
+                if (child.getNodeType() == Node.ELEMENT_NODE) {
+                    remove((Element)child, recurse);
+                }
+            }
+        }
+    }
+
+    /**
+     * A SAX filter that adds the information available from the <code>Locator</code> as attributes.
+     * The purpose of having location as attributes is to allow this information to survive transformations
+     * of the document (an XSL could copy these attributes over) or conversion of SAX events to a DOM.
+     * <p>
+     * The location is added as 3 attributes in a specific namespace to each element.
+     * <pre>
+     * &lt;root xmlns:loc="http://apache.org/cocoon/location"
+     *       loc:src="file://path/to/file.xml"
+     *       loc:line="1" loc:column="1"&gt;
+     *   &lt;foo loc:src="file://path/to/file.xml" loc:line="2" loc:column="3"/&gt;
+     * &lt;/root&gt;
+     * </pre>
+     * <strong>Note:</strong> Although this adds a lot of information to the serialized form of the document,
+     * the overhead in SAX events is not that big, as attribute names are interned, and all <code>src</code>
+     * attributes point to the same string.
+     * 
+     * @see org.apache.struts.flow.core.location.LocationAttributes
+     * @since 2.1.8
+     */
+    public static class Pipe implements ContentHandler {
+        
+        private Locator locator;
+        
+        private ContentHandler nextHandler;
+        
+        /**
+         * Create a filter. It has to be chained to another handler to be really useful.
+         */
+        public Pipe() {
+        }
+
+        /**
+         * Create a filter that is chained to another handler.
+         * @param next the next handler in the chain.
+         */
+        public Pipe(ContentHandler next) {
+            nextHandler = next;
+        }
+
+        public void setDocumentLocator(Locator locator) {
+            this.locator = locator;
+            nextHandler.setDocumentLocator(locator);
+        }
+        
+        public void startDocument() throws SAXException {
+            nextHandler.startDocument();
+            nextHandler.startPrefixMapping(LocationAttributes.PREFIX, LocationAttributes.URI);
+        }
+        
+        public void endDocument() throws SAXException {
+            endPrefixMapping(LocationAttributes.PREFIX);
+            nextHandler.endDocument();
+        }
+
+        public void startElement(String uri, String loc, String raw, Attributes attrs) throws SAXException {
+            // Add location attributes to the element
+            nextHandler.startElement(uri, loc, raw, LocationAttributes.addLocationAttributes(locator, attrs));
+        }
+
+        public void endElement(String arg0, String arg1, String arg2) throws SAXException {
+            nextHandler.endElement(arg0, arg1, arg2);
+        }
+
+        public void startPrefixMapping(String arg0, String arg1) throws SAXException {
+            nextHandler.startPrefixMapping(arg0, arg1);
+        }
+
+        public void endPrefixMapping(String arg0) throws SAXException {
+            nextHandler.endPrefixMapping(arg0);
+        }
+
+        public void characters(char[] arg0, int arg1, int arg2) throws SAXException {
+            nextHandler.characters(arg0, arg1, arg2);
+        }
+
+        public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {
+            nextHandler.ignorableWhitespace(arg0, arg1, arg2);
+        }
+
+        public void processingInstruction(String arg0, String arg1) throws SAXException {
+            nextHandler.processingInstruction(arg0, arg1);
+        }
+
+        public void skippedEntity(String arg0) throws SAXException {
+            nextHandler.skippedEntity(arg0);
+        }
+    }
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocationAttributes.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocationImpl.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocationImpl.java?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocationImpl.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocationImpl.java Sat Nov 26 23:10:08 2005
@@ -0,0 +1,175 @@
+/*
+ * 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.struts.flow.core.location;
+
+import java.io.Serializable;
+
+import org.apache.commons.lang.ObjectUtils;
+
+/**
+ * A simple immutable and serializable implementation of {@link Location}.
+ * 
+ * @since 2.1.8
+ * @version $Id: LocationImpl.java 280946 2005-09-14 21:43:05Z sylvain $
+ */
+public class LocationImpl implements Location, Serializable {
+    private final String uri;
+    private final int line;
+    private final int column;
+    private final String description;
+    
+    // Package private: outside this package, use Location.UNKNOWN.
+    static final LocationImpl UNKNOWN = new LocationImpl(null, null, -1, -1);
+
+    /**
+     * Build a location for a given URI, with unknown line and column numbers.
+     * 
+     * @param uri the resource URI
+     */
+    public LocationImpl(String description, String uri) {
+        this(description, uri, -1, -1);
+    }
+
+    /**
+     * Build a location for a given URI and line and columb numbers.
+     * 
+     * @param uri the resource URI
+     * @param line the line number (starts at 1)
+     * @param column the column number (starts at 1)
+     */
+    public LocationImpl(String description, String uri, int line, int column) {
+        if (uri == null || uri.length() == 0) {
+            this.uri = null;
+            this.line = -1;
+            this.column = -1;
+        } else {
+            this.uri = uri;
+            this.line = line;
+            this.column = column;
+        }
+        
+        if (description != null && description.length() == 0) {
+            description = null;
+        }
+        this.description = description;
+    }
+    
+    /**
+     * Copy constructor.
+     * 
+     * @param location the location to be copied
+     */
+    public LocationImpl(Location location) {
+        this(location.getDescription(), location.getURI(), location.getLineNumber(), location.getColumnNumber());
+    }
+    
+    /**
+     * Create a location from an existing one, but with a different description
+     */
+    public LocationImpl(String description, Location location) {
+        this(description, location.getURI(), location.getLineNumber(), location.getColumnNumber());
+    }
+    
+    /**
+     * Obtain a <code>LocationImpl</code> from a {@link Location}. If <code>location</code> is
+     * already a <code>LocationImpl</code>, it is returned, otherwise it is copied.
+     * <p>
+     * This method is useful when an immutable and serializable location is needed, such as in locatable
+     * exceptions.
+     * 
+     * @param location the location
+     * @return an immutable and serializable version of <code>location</code>
+     */
+    public static LocationImpl get(Location location) {
+        if (location instanceof LocationImpl) {
+            return (LocationImpl)location;
+        } else if (location == null) {
+            return UNKNOWN;
+        } else {
+            return new LocationImpl(location);
+        }
+    }
+    
+    /**
+     * Get the description of this location
+     * 
+     * @return the description (can be <code>null</code>)
+     */
+    public String getDescription() {
+        return this.description;
+    }
+    
+    /**
+     * Get the URI of this location
+     * 
+     * @return the URI (<code>null</code> if unknown).
+     */
+    public String getURI() {
+        return this.uri;
+    }
+
+    /**
+     * Get the line number of this location
+     * 
+     * @return the line number (<code>-1</code> if unknown)
+     */
+    public int getLineNumber() {
+        return this.line;
+    }
+    
+    /**
+     * Get the column number of this location
+     * 
+     * @return the column number (<code>-1</code> if unknown)
+     */
+    public int getColumnNumber() {
+        return this.column;
+    }
+
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (obj instanceof Location) {
+            Location other = (Location)obj;
+            return this.line == other.getLineNumber() && this.column == other.getColumnNumber()
+                   && ObjectUtils.equals(this.uri, other.getURI())
+                   && ObjectUtils.equals(this.description, other.getDescription());
+        }
+        
+        return false;
+    }
+    
+    public int hashCode() {
+        int hash = line ^ column;
+        if (uri != null) hash ^= uri.hashCode();
+        if (description != null) hash ^= description.hashCode();
+        
+        return hash;
+    }
+    
+    public String toString() {
+        return LocationUtils.toString(this);
+    }
+    
+    /**
+     * Ensure serialized unknown location resolve to {@link Location#UNKNOWN}.
+     */
+    private Object readResolve() {
+        return this.equals(Location.UNKNOWN) ? Location.UNKNOWN : this;
+    }
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocationImpl.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocationUtils.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocationUtils.java?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocationUtils.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocationUtils.java Sat Nov 26 23:10:08 2005
@@ -0,0 +1,271 @@
+/*
+ * 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.struts.flow.core.location;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.transform.SourceLocator;
+import javax.xml.transform.TransformerException;
+
+import org.xml.sax.Locator;
+import org.xml.sax.SAXParseException;
+
+/**
+ * Location-related utility methods.
+ *
+ * @version $Id: LocationUtils.java 280946 2005-09-14 21:43:05Z sylvain $
+ * @since 2.1.8
+ */
+public class LocationUtils {
+    
+    /**
+     * The string representation of an unknown location: "<code>[unknown location]</code>".
+     */
+    public static final String UNKNOWN_STRING = "[unknown location]";
+    
+    private static List finders = new ArrayList();
+    
+    /**
+     * An finder or object locations
+     *
+     * @since 2.1.8
+     */
+    public interface LocationFinder {
+        /**
+         * Get the location of an object
+         * @param obj the object for which to find a location
+         * @param description and optional description to be added to the object's location
+         * @return the object's location or <code>null</code> if object's class isn't handled
+         *         by this finder.
+         */
+        Location getLocation(Object obj, String description);
+    }
+
+    private LocationUtils() {
+        // Forbid instanciation
+    }
+    
+    /**
+     * Builds a string representation of a location, in the
+     * "<code><em>descripton</em> - <em>uri</em>:<em>line</em>:<em>column</em></code>"
+     * format (e.g. "<code>foo - file://path/to/file.xml:3:40</code>"). For {@link Location#UNKNOWN an unknown location}, returns
+     * {@link #UNKNOWN_STRING}.
+     * 
+     * @return the string representation
+     */
+    public static String toString(Location location) {
+        StringBuffer result = new StringBuffer();
+
+        String description = location.getDescription();
+        if (description != null) {
+            result.append(description).append(" - ");
+        }
+
+        String uri = location.getURI();
+        if (uri != null) {
+            result.append(uri).append(':').append(location.getLineNumber()).append(':').append(location.getColumnNumber());
+        } else {
+            result.append(UNKNOWN_STRING);
+        }
+        
+        return result.toString();
+    }
+
+    /**
+     * Parse a location string of the form "<code><em>uri</em>:<em>line</em>:<em>column</em></code>" (e.g.
+     * "<code>path/to/file.xml:3:40</code>") to a Location object. Additionally, a description may
+     * also optionally be present, separated with an hyphen (e.g. "<code>foo - path/to/file.xml:3.40</code>").
+     * 
+     * @param text the text to parse
+     * @return the location (possibly <code>null</code> if text was null or in an incorrect format)
+     */
+    public static LocationImpl parse(String text) throws IllegalArgumentException {
+        if (text == null || text.length() == 0) {
+            return null;
+        }
+
+        // Do we have a description?
+        String description;
+        int uriStart = text.lastIndexOf(" - "); // lastIndexOf to allow the separator to be in the description
+        if (uriStart > -1) {
+            description = text.substring(0, uriStart);
+            uriStart += 3; // strip " - "
+        } else {
+            description = null;
+            uriStart = 0;
+        }
+        
+        try {
+            int colSep = text.lastIndexOf(':');
+            if (colSep > -1) {
+                int column = Integer.parseInt(text.substring(colSep + 1));
+                
+                int lineSep = text.lastIndexOf(':', colSep - 1);
+                if (lineSep > -1) {
+                    int line = Integer.parseInt(text.substring(lineSep + 1, colSep));
+                    return new LocationImpl(description, text.substring(uriStart, lineSep), line, column);
+                }
+            } else {
+                // unkonwn?
+                if (text.endsWith(UNKNOWN_STRING)) {
+                    return LocationImpl.UNKNOWN;
+                }
+            }
+        } catch(Exception e) {
+            // Ignore: handled below
+        }
+        
+        return LocationImpl.UNKNOWN;
+    }
+
+    /**
+     * Checks if a location is known, i.e. it is not null nor equal to {@link Location#UNKNOWN}.
+     * 
+     * @param location the location to check
+     * @return <code>true</code> if the location is known
+     */
+    public static boolean isKnown(Location location) {
+        return location != null && !Location.UNKNOWN.equals(location);
+    }
+
+    /**
+     * Checks if a location is unknown, i.e. it is either null or equal to {@link Location#UNKNOWN}.
+     * 
+     * @param location the location to check
+     * @return <code>true</code> if the location is unknown
+     */
+    public static boolean isUnknown(Location location) {
+        return location == null || Location.UNKNOWN.equals(location);
+    }
+
+    /**
+     * Add a {@link LocationFinder} to the list of finders that will be queried for an object's
+     * location by {@link #getLocation(Object, String)}.
+     * <p>
+     * <b>Important:</b> LocationUtils internally stores a weak reference to the finder. This
+     * avoids creating strong links between the classloader holding this class and the finder's
+     * classloader, which can cause some weird memory leaks if the finder's classloader is to
+     * be reloaded. Therefore, you <em>have</em> to keep a strong reference to the finder in the
+     * calling code, e.g.:
+     * <pre>
+     *   private static LocationUtils.LocationFinder myFinder =
+     *       new LocationUtils.LocationFinder() {
+     *           public Location getLocation(Object obj, String desc) {
+     *               ...
+     *           }
+     *       };
+     *
+     *   static {
+     *       LocationUtils.addFinder(myFinder);
+     *   }
+     * </pre>
+     * 
+     * @param finder the location finder to add
+     */
+    public static void addFinder(LocationFinder finder) {
+        if (finder == null) {
+            return;
+        }
+
+        synchronized(LocationFinder.class) {
+            // Update a clone of the current finder list to avoid breaking
+            // any iteration occuring in another thread.
+            List newFinders = new ArrayList(finders);
+            newFinders.add(new WeakReference(finder));
+            finders = newFinders;
+        }
+    }
+    
+    /**
+     * Get the location of an object. Some well-known located classes built in the JDK are handled
+     * by this method. Handling of other located classes can be handled by adding new location finders.
+     * 
+     * @param obj the object of which to get the location
+     * @return the object's location, or {@link Location#UNKNOWN} if no location could be found
+     */
+    public static Location getLocation(Object obj) {
+        return getLocation(obj, null);
+    }
+    
+    /**
+     * Get the location of an object. Some well-known located classes built in the JDK are handled
+     * by this method. Handling of other located classes can be handled by adding new location finders.
+     * 
+     * @param obj the object of which to get the location
+     * @param description an optional description of the object's location, used if a Location object
+     *        has to be created.
+     * @return the object's location, or {@link Location#UNKNOWN} if no location could be found
+     */
+    public static Location getLocation(Object obj, String description) {
+        if (obj instanceof Locatable) {
+            return ((Locatable)obj).getLocation();
+        }
+        
+        // Check some well-known locatable exceptions
+        if (obj instanceof SAXParseException) {
+            SAXParseException spe = (SAXParseException)obj;
+            if (spe.getSystemId() != null) {
+                return new LocationImpl(description, spe.getSystemId(), spe.getLineNumber(), spe.getColumnNumber());
+            } else {
+                return Location.UNKNOWN;
+            }
+        }
+        
+        if (obj instanceof TransformerException) {
+            TransformerException ex = (TransformerException)obj;
+            SourceLocator locator = ex.getLocator();
+            if (locator != null && locator.getSystemId() != null) {
+                return new LocationImpl(description, locator.getSystemId(), locator.getLineNumber(), locator.getColumnNumber());
+            } else {
+                return Location.UNKNOWN;
+            }
+        }
+        
+        if (obj instanceof Locator) {
+            Locator locator = (Locator)obj;
+            if (locator.getSystemId() != null) {
+                return new LocationImpl(description, locator.getSystemId(), locator.getLineNumber(), locator.getColumnNumber());
+            } else {
+                return Location.UNKNOWN;
+            }
+        }
+
+        List currentFinders = finders; // Keep the current list
+        int size = currentFinders.size();
+        for (int i = 0; i < size; i++) {
+            WeakReference ref = (WeakReference)currentFinders.get(i);
+            LocationFinder finder = (LocationFinder)ref.get();
+            if (finder == null) {
+                // This finder was garbage collected: update finders
+                synchronized(LocationFinder.class) {
+                    // Update a clone of the current list to avoid breaking current iterations
+                    List newFinders = new ArrayList(finders);
+                    newFinders.remove(ref);
+                    finders = newFinders;
+                }
+            }
+            
+            Location result = finder.getLocation(obj, description);
+            if (result != null) {
+                return result;
+            }
+        }
+
+        return Location.UNKNOWN;
+    }
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/location/LocationUtils.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/location/MultiLocatable.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/location/MultiLocatable.java?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/location/MultiLocatable.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/location/MultiLocatable.java Sat Nov 26 23:10:08 2005
@@ -0,0 +1,39 @@
+package org.apache.struts.flow.core.location;
+
+import java.util.List;
+
+/**
+ * An extension of {@link Location} for classes that can hold a list of locations.
+ * It will typically be used to build location stacks.
+ * <p>
+ * The <em>first</em> location of the collection returned by {@link #getLocations()} should be
+ * be identical to the result of {@link org.apache.struts.flow.core.location.Locatable#getLocation()}.
+ * <p>
+ * If the list of locations designates a call stack, then its first element should be the deepmost
+ * location of this stack. This is consistent with the need for <code>getLocation()</code> to
+ * return the most precise location.
+ * 
+ * @since 2.1.8
+ * @version $Id: MultiLocatable.java 233343 2005-08-18 18:06:44Z sylvain $
+ */
+public interface MultiLocatable extends Locatable {
+    
+    /**
+     * Return the list of locations.
+     * 
+     * @return a list of locations, possibly empty but never null.
+     */
+    public List getLocations();
+    
+    /**
+     * Add a location to the current list of locations.
+     * <p>
+     * Implementations are free to filter locations that can be added (e.g. {@link Location#UNKNOWN}),
+     * and there is therefore no guarantee that the given location will actually be added to the list.
+     * Filtered locations are silently ignored.
+     * 
+     * @param location the location to be added.
+     */
+    public void addLocation(Location location);
+
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/location/MultiLocatable.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/location/package.html
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/location/package.html?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/location/package.html (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/location/package.html Sat Nov 26 23:10:08 2005
@@ -0,0 +1,3 @@
+<html>
+  <body>Classes and utilities used to track location information.</body>
+</html>
\ No newline at end of file

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/source/ModifiableSource.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/source/ModifiableSource.java?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/source/ModifiableSource.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/source/ModifiableSource.java Sat Nov 26 23:10:08 2005
@@ -0,0 +1,67 @@
+/* 
+ * Copyright 2002-2004 The Apache Software Foundation
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ * 
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts.flow.core.source;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A {@link Source} that can be written to.
+ * <p>
+ * As far a possible, implementations should provide a kind of transaction or
+ * buffering of data written to the source. This is especially important in
+ * stream-based systems such as Cocoon where an error that occurs during the
+ * processing should lead to cancelling data written to the source.
+ * <p>
+ * This is the role of the {@link #canCancel(OutputStream)} and
+ * {@link #cancel(OutputStream)} methods.
+ *
+ * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
+ * @version CVS $Revision: 1.4 $ $Date: 2004/02/28 11:47:26 $
+ */
+public interface ModifiableSource
+    extends Source
+{
+    /**
+     * Return an {@link OutputStream} to write to.
+     *
+     * The returned stream must be closed or cancelled by the calling code.
+     */
+    OutputStream getOutputStream() throws IOException;
+    
+    /**
+     * Delete the source 
+     */
+    void delete() throws SourceException;
+
+    /**
+     * Can the data sent to an <code>OutputStream</code> returned by
+     * {@link #getOutputStream()} be cancelled ?
+     *
+     * @return true if the stream can be cancelled
+     */
+    boolean canCancel(OutputStream stream);
+
+    /**
+     * Cancel the data sent to an <code>OutputStream</code> returned by
+     * {@link #getOutputStream()}.  Cancelling the stream will also close it.
+     *
+     * <p>After cancelling, the stream should no longer be used.</p>
+     */
+    void cancel(OutputStream stream) throws IOException;
+    
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/source/ModifiableSource.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/source/ModifiableTraversableSource.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/source/ModifiableTraversableSource.java?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/source/ModifiableTraversableSource.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/source/ModifiableTraversableSource.java Sat Nov 26 23:10:08 2005
@@ -0,0 +1,39 @@
+/* 
+ * Copyright 2002-2004 The Apache Software Foundation
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ * 
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts.flow.core.source;
+
+/**
+ * A modifiable traversable source. This adds to {@link ModifiableSource} the
+ * ability to create a directory.
+ * 
+ * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
+ * @version CVS $Revision: 1.4 $ $Date: 2004/02/28 11:47:26 $
+ */
+public interface ModifiableTraversableSource extends ModifiableSource, TraversableSource
+{
+    /**
+     * If it doesn't already exist, ensure this source is traversable
+     * (equivalent to <code>File.mkdirs()</code>)
+     * <p>
+     * If the source already exists, this method does nothing if it's already
+     * traversable, and fails otherwise.
+     */
+    public void makeCollection() throws SourceException;
+
+}
+
+

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/source/ModifiableTraversableSource.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/source/MoveableSource.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/source/MoveableSource.java?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/source/MoveableSource.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/source/MoveableSource.java Sat Nov 26 23:10:08 2005
@@ -0,0 +1,51 @@
+/* 
+ * Copyright 2002-2004 The Apache Software Foundation
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ * 
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts.flow.core.source;
+
+
+/**
+ * This class marks a source to be able to moved and copied to
+ * serveral other locations. This class should only be used if
+ * the implementations details should be hidden, otherwise
+ * the class SourceUtils can be used.
+ *
+ * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
+ * @version CVS $Id: MoveableSource.java,v 1.5 2004/02/28 11:47:26 cziegeler Exp $
+ */
+public interface MoveableSource extends Source
+{
+
+    /**
+     * Copy the current source to a specified destination.
+     *
+     * @param destination Destination of the source.
+     *
+     * @throws SourceException If an exception occurs during
+     *                         the copy.
+     */
+    void copyTo(Source destination) throws SourceException;
+
+    /**
+     * Move the current source to a specified destination.
+     *
+     * @param destination Destination of the source.
+     *
+     * @throws SourceException If an exception occurs during
+     *                         the move.
+     */
+    void moveTo(Source destination) throws SourceException;
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/source/MoveableSource.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/source/Source.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/source/Source.java?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/source/Source.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/source/Source.java Sat Nov 26 23:10:08 2005
@@ -0,0 +1,149 @@
+/* 
+ * Copyright 2002-2004 The Apache Software Foundation
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ * 
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts.flow.core.source;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * This interface provides a simple interface for accessing a source of data.
+ * <p>
+ * When the <code>Source</code> object is no longer needed
+ * it must be released using the {@link SourceResolver}. This is very similar to
+ * looking up components from a <code>ServiceSelector</code>.
+ * In fact a source object can implement most lifecycle interfaces
+ * like Composable, Initializable, Disposable etc.
+ * <p>
+ * The data content can be constant or change over time.
+ * Using the {@link #getInputStream()} method you get always the up-to-date content.
+ * <p>
+ * If you want to track changes of the source object, this interface
+ * offers you some support for it by providing a SourceValidity object.
+ * <p>
+ * How does the caching work?
+ * The first time you get a Source object, you simply ask
+ * it for it's content via getInputStream() and then get the validity
+ * object by invoking getValidity. (Further calls to getValidity always
+ * return the same object! This is not updated!)
+ * The caching algorithm can now store this validity object together
+ * with the system identifier of the source.
+ * The next time, the caching algorithm wants to check if the cached
+ * content is still valid. It has a validity object already to check
+ * against.
+ * <p>
+ * If it is still the same Source than the first time, you
+ * have to call refresh() in order to discard the stored validity
+ * in the Source object. If it is a new Source object,
+ * calling refresh() should do no harm.
+ * After that an up-to-date validity object can retrieved by calling
+ * getValidity(). This can be used to test if the content is still valid
+ * as discribed in the source validity documentation.
+ * If the content is still valid, the cache knows what to do, if not,
+ * the new content can be get using getInputStream().
+ * So either after a call to getValidity() or the getInputStream the
+ * validity object must be the same until refresh is called!
+ *
+ * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
+ * @version CVS $Revision: 1.4 $ $Date: 2004/02/28 11:47:26 $
+ */
+public interface Source
+{
+    /**
+     * Does this source exist ?
+     * 
+     * @return true if the source exists
+     */
+    boolean exists();
+    
+    /**
+     * Return an <code>InputStream</code> to read from the source.
+     * This is the data at the point of invocation of this method,
+     * so if this is Modifiable, you might get different content
+     * from two different invocations.
+     *
+     * The returned stream must be closed by the calling code.
+     * 
+     * @return the <code>InputStream</code> to read data from (never <code>null</code>).
+     * @throws IOException if some I/O problem occurs.
+     * @throws SourceNotFoundException if the source doesn't exist.
+     */
+    InputStream getInputStream()
+        throws IOException, SourceNotFoundException;
+
+    /**
+     * Get the absolute URI for this source.
+     * 
+     * @return the source URI.
+     */
+    String getURI();
+
+    /**
+     * Return the URI scheme identifier, i.e. the part preceding the fist ':' in the URI
+     * (see <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>).
+     * <p>
+     * This scheme can be used to get the {@link SourceFactory} responsible for this object.
+     * 
+     * @return the URI scheme.
+     */
+    String getScheme();
+    
+    /**
+     * Get the Validity object. This can either wrap the last modification date or
+     * some expiry information or anything else describing this object's validity.
+     * <p>
+     * If it is currently not possible to calculate such an information,
+     * <code>null</code> is returned.
+     * 
+     * @return the validity, or <code>null</code>.
+     */
+    SourceValidity getValidity();
+
+    /**
+     * Refresh the content of this object after the underlying data content has changed.
+     * <p>
+     * Some implementations may cache some values to speedup sucessive calls. Refreshing
+     * ensures you get the latest information.
+     */
+    void refresh();
+
+    /**
+     * Get the mime-type of the content described by this object.
+     * If the source is not able to determine the mime-type by itself
+     * this can be <code>null</code>.
+     * 
+     * @return the source's mime-type or <code>null</code>.
+     */
+    String getMimeType();
+
+    /**
+     * Get the content length of this source's content or -1 if the length is
+     * unknown.
+     * 
+     * @return the source's content length or -1.
+     */
+    long getContentLength();
+
+    /**
+     * Get the last modification date of this source. The date is
+     * measured in milliseconds since the epoch (00:00:00 GMT, January 1, 1970),
+     * and is <code>0</code> if it's unknown.
+     * 
+     * @return the last modification date or <code>0</code>.
+     */
+    long getLastModified();
+    
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/source/Source.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/source/SourceException.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/source/SourceException.java?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/source/SourceException.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/source/SourceException.java Sat Nov 26 23:10:08 2005
@@ -0,0 +1,67 @@
+/* 
+ * Copyright 2002-2004 The Apache Software Foundation
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ * 
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts.flow.core.source;
+
+import java.io.IOException;
+
+/**
+ * This Exception is thrown every time there is a problem in processing
+ * a source.
+ *
+ * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
+ * @version CVS $Revision: 1.4 $ $Date: 2004/02/28 11:47:26 $
+ */
+public class SourceException
+    extends IOException 
+{
+    /**
+     * The Throwable that caused this exception to be thrown.
+     */
+    private final Throwable m_throwable;
+
+    /**
+     * Construct a new <code>SourceException</code> instance.
+     *
+     * @param message the detail message for this exception.
+     */
+    public SourceException( final String message )
+    {
+        this( message, null );
+    }
+
+    /**
+     * Construct a new <code>SourceException</code> instance.
+     *
+     * @param message the detail message for this exception.
+     * @param throwable the root cause of the exception.
+     */
+    public SourceException( final String message, final Throwable throwable )
+    {
+        super( message  );
+        m_throwable = throwable;
+    }
+    
+    /**
+     * Retrieve the cause of the exception.
+     *
+     * @return the cause.
+     */
+    public final Throwable getCause()
+    {
+        return m_throwable;
+    }
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/source/SourceException.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/source/SourceFactory.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/source/SourceFactory.java?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/source/SourceFactory.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/source/SourceFactory.java Sat Nov 26 23:10:08 2005
@@ -0,0 +1,62 @@
+/* 
+ * Copyright 2002-2004 The Apache Software Foundation
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ * 
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts.flow.core.source;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Map;
+
+/**
+ * A source factory creates new source objects.
+ * <p>
+ * Source factories are used to extend the source resolving mechanism
+ * with new URI schemes. A new source factory is added in order to
+ * handle a specific prototol. The {@link SourceResolver} delegates
+ * the handling of a URI containing this new scheme to the factory,
+ * and the factory can create a corresponding {@link Source} object.
+ * 
+ * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
+ * @version $Id: SourceFactory.java,v 1.4 2004/02/28 11:47:26 cziegeler Exp $
+ */
+public interface SourceFactory {
+
+    /**
+     * Get a {@link Source} object.
+     * The factory creates a new {@link Source} object that can be used
+     * by the application. However, when this source object is not needed
+     * anymore it has to be released again using the {@link #release(Source)}
+     * method. This is achieved by using {@link SourceResolver#release(Source)} which
+     * finds the appropriate <code>SourceFactory</code>.
+     * 
+     * @param location   The URI to resolve - this URI includes the scheme.
+     * @param parameters additionnal named parameters (optionnal and can be <code>null</code>)
+     *        that drive the creation of the <code>Source</code> object. Each implementation
+     *        must specify what parameters it accepts.
+     * @return the created source object.
+     *
+     * @throws IOException if the source couldn't be created for some reason.
+     */
+    Source getSource( String location, Map parameters )
+        throws IOException, MalformedURLException;
+    
+    /**
+     * Release a {@link Source} object.
+     * 
+     * @param source the source to release.
+     */
+    void release( Source source );
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/source/SourceFactory.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/source/SourceNotFoundException.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/source/SourceNotFoundException.java?rev=349187&view=auto
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/source/SourceNotFoundException.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/source/SourceNotFoundException.java Sat Nov 26 23:10:08 2005
@@ -0,0 +1,48 @@
+/* 
+ * Copyright 2002-2004 The Apache Software Foundation
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ * 
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts.flow.core.source;
+
+/**
+ * This Exception should be thrown if the source could not be found.
+ *
+ * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
+ * @version CVS $Revision: 1.4 $ $Date: 2004/02/28 11:47:26 $
+ */
+public class SourceNotFoundException
+    extends SourceException
+{
+    /**
+     * Construct a new <code>SourceNotFoundException</code> instance.
+     *
+     * @param message The detail message for this exception.
+     */
+    public SourceNotFoundException( final String message )
+    {
+        super( message, null );
+    }
+
+    /**
+     * Construct a new <code>SourceNotFoundException</code> instance.
+     *
+     * @param message The detail message for this exception.
+     * @param throwable the root cause of the exception
+     */
+    public SourceNotFoundException( final String message, final Throwable throwable )
+    {
+        super( message, throwable );
+    }
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/source/SourceNotFoundException.java
------------------------------------------------------------------------------
    svn:executable = *



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org