cocoon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jheym...@apache.org
Subject svn commit: r330548 [15/132] - in /cocoon/whiteboard/maven2/cocoon-flat-layout: ./ cocoon-ajax-block/ cocoon-ajax-block/api/ cocoon-ajax-block/api/src/ cocoon-ajax-block/api/src/main/ cocoon-ajax-block/api/src/main/java/ cocoon-ajax-block/api/src/main/...
Date Thu, 03 Nov 2005 14:00:48 GMT
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/InvalidContinuationException.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/InvalidContinuationException.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/InvalidContinuationException.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/InvalidContinuationException.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,42 @@
+/*
+ * 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.cocoon.components.flow;
+
+import org.apache.cocoon.ProcessingException;
+
+/**
+ * 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 233343 2005-08-18 18:06:44Z sylvain $
+ */
+public class InvalidContinuationException extends ProcessingException {
+
+    /**
+     * Construct a new <code>InvalidContinuationException</code> instance.
+     */
+    public InvalidContinuationException(String message) {
+        super(message);
+    }
+
+    /**
+     * Construct a new <code>InvalidContinuationException</code> that references
+     * a parent Exception.
+     */
+    public InvalidContinuationException(String message, Throwable t) {
+        super(message, t);
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/InvalidContinuationException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/WebContinuation.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/WebContinuation.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/WebContinuation.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/WebContinuation.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,454 @@
+/*
+ * 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.cocoon.components.flow;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.commons.collections.iterators.IteratorEnumeration;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * Representation of continuations in a Web environment.
+ *
+ * <p>Because a user may click on the back button of the browser and
+ * restart a saved computation in a continuation, each
+ * <code>WebContinuation</code> becomes the parent of a subtree of
+ * continuations.
+ *
+ * <p>If there is no parent <code>WebContinuation</code>, the created
+ * continuation becomes the root of a tree of
+ * <code>WebContinuation</code>s.
+ *
+ * @author <a href="mailto:ovidiu@cup.hp.com">Ovidiu Predescu</a>
+ * @since March 19, 2002
+ * @version CVS $Id: WebContinuation.java 292158 2005-09-28 10:24:51Z sylvain $
+ */
+public class WebContinuation extends AbstractLogEnabled
+                             implements Comparable {
+
+    /**
+     * The continuation this object represents.
+     */
+    protected Object continuation;
+
+    /**
+     * The parent <code>WebContinuation</code> from which processing
+     * last started. If null, there is no parent continuation
+     * associated, and this is the first one to be created in a
+     * processing. In this case this <code>WebContinuation</code>
+     * instance becomes the root of the tree maintained by the
+     * <code>ContinuationsManager</code>.
+     *
+     * @see ContinuationsManager
+     */
+    protected WebContinuation parentContinuation;
+
+    /**
+     * The children continuations. These are continuations created by
+     * resuming the processing from the point stored by
+     * <code>continuation</code>.
+     */
+    protected List children = new ArrayList();
+
+    /**
+     * The continuation id used to represent this instance in Web pages.
+     */
+    protected String id;
+    
+    /**
+     * Interpreter id that this continuation is bound to
+     */
+    protected String interpreterId;
+
+    /**
+     * A user definable object. This is present for convenience, to
+     * store any information associated with this
+     * <code>WebContinuation</code> a particular implementation might
+     * need.
+     */
+    protected Object userObject;
+
+    /**
+     * When was this continuation accessed last time. Each time the
+     * continuation is accessed, this time is set to the time of the
+     * access.
+     */
+    protected long lastAccessTime;
+
+    /**
+     * Indicates how long does this continuation will live (in
+     * seconds). The continuation will be removed once the current time
+     * is bigger than <code>lastAccessTime + timeToLive</code>.
+     */
+    protected int timeToLive;
+
+    /**
+     * Holds the <code>ContinuationsDisposer</code> to call when this continuation
+     * gets invalidated.
+     */
+    protected ContinuationsDisposer disposer;
+
+    /**
+     * The attributes of this continuation
+     */
+    private Map attributes;
+
+    /**
+     * Create a <code>WebContinuation</code> object. Saves the object in
+     * the hash table of continuations maintained by
+     * <code>manager</code> (this is done as a side effect of obtaining
+     * and identifier from it).
+     *
+     * @param continuation an <code>Object</code> value
+     * @param parentContinuation a <code>WebContinuation</code> value
+     * @param timeToLive time this continuation should live
+     * @param disposer a <code>ContinuationsDisposer</code> to call when this
+     * continuation gets invalidated.
+     */
+    WebContinuation(String id,
+                    Object continuation,
+                    WebContinuation parentContinuation,
+                    int timeToLive,
+                    String interpreterId,
+                    ContinuationsDisposer disposer) {
+        this.id = id;
+        this.continuation = continuation;
+        this.parentContinuation = parentContinuation;
+        this.updateLastAccessTime();
+        this.timeToLive = timeToLive;
+        this.interpreterId = interpreterId;
+        this.disposer = disposer;
+
+        if (parentContinuation != null) {
+            this.parentContinuation.children.add(this);
+        }
+    }
+
+    /**
+     * Get an attribute of this continuation
+     * 
+     * @param name the attribute name.
+     */
+    public Object getAttribute(String name) {
+        if (this.attributes == null)
+            return null;
+        
+        return this.attributes.get(name);
+    }
+    
+    /**
+     * Set an attribute of this continuation
+     * 
+     * @param name the attribute name
+     * @param value its value
+     */
+    public void setAttribute(String name, Object value) {
+        if (this.attributes == null) {
+            this.attributes = Collections.synchronizedMap(new HashMap());
+        }
+        
+        this.attributes.put(name, value);
+    }
+    
+    /**
+     * Remove an attribute of this continuation
+     * 
+     * @param name the attribute name
+     */
+    public void removeAttribute(String name) {
+        if (this.attributes == null)
+            return;
+        
+        this.attributes.remove(name);
+    }
+    
+    /**
+     * Enumerate the attributes of this continuation.
+     * 
+     * @return an enumeration of strings
+     */
+    public Enumeration getAttributeNames() {
+        if (this.attributes == null)
+            return new IteratorEnumeration();
+        
+        ArrayList keys = new ArrayList(this.attributes.keySet());
+        return new IteratorEnumeration(keys.iterator());
+    }
+
+    /**
+     * Return the continuation object.
+     *
+     * @return an <code>Object</code> value
+     */
+    public Object getContinuation() {
+        updateLastAccessTime();
+        return continuation;
+    }
+
+    /**
+     * Return the ancestor continuation situated <code>level</code>s
+     * above the current continuation. The current instance is
+     * considered to be at level 0. The parent continuation of the
+     * receiving instance at level 1, its parent is at level 2 relative
+     * to the receiving instance. If <code>level</code> is bigger than
+     * the depth of the tree, the root of the tree is returned.
+     *
+     * @param level an <code>int</code> value
+     * @return a <code>WebContinuation</code> value
+     */
+    public WebContinuation getContinuation(int level) {
+        if (level <= 0) {
+            updateLastAccessTime();
+            return this;
+        } else if (parentContinuation == null) {
+            return this;
+        } else {
+            return parentContinuation.getContinuation(level - 1);
+        }
+    }
+
+    /**
+     * Return the parent <code>WebContinuation</code>. Equivalent with
+     * <code>getContinuation(1)</code>.
+     *
+     * @return a <code>WebContinuation</code> value
+     */
+    public WebContinuation getParentContinuation() {
+        return parentContinuation;
+    }
+
+    /**
+     * Return the children <code>WebContinuation</code> which were
+     * created as a result of resuming the processing from the current
+     * <code>continuation</code>.
+     *
+     * @return a <code>List</code> value
+     */
+    public List getChildren() {
+        return children;
+    }
+
+    /**
+     * Returns the string identifier of this
+     * <code>WebContinuation</code>.
+     *
+     * @return a <code>String</code> value
+     */
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Returns the string identifier of the interpreter to which
+     * this <code>WebContinuation</code> is bound.
+     *
+     * @return a <code>String</code> value
+     */
+    public String getInterpreterId() {
+        return interpreterId;
+    }
+
+    /**
+     * Returns the last time this
+     * <code>WebContinuation</code> was accessed.
+     *
+     * @return a <code>long</code> value
+     */
+    public long getLastAccessTime() {
+        return lastAccessTime;
+    }
+
+    /**
+     * Returns the the timetolive for this
+     * <code>WebContinuation</code>.
+     *
+     * @return a <code>long</code> value
+     */
+    public long getTimeToLive() {
+        return this.timeToLive;
+    }
+
+    /**
+     * Sets the user object associated with this instance.
+     *
+     * @param obj an <code>Object</code> value
+     */
+    public void setUserObject(Object obj) {
+        this.userObject = obj;
+    }
+
+    /**
+     * Obtains the user object associated with this instance.
+     *
+     * @return an <code>Object</code> value
+     */
+    public Object getUserObject() {
+        return userObject;
+    }
+
+    /**
+     * Obtains the <code>ContinuationsDisposer</code> to call when this continuation
+     * is invalidated.
+     *
+     * @return a <code>ContinuationsDisposer</code> instance or null if there are
+     * no specific clean-up actions required.
+     */
+    ContinuationsDisposer getDisposer() {
+        return this.disposer;
+    }
+
+    /**
+     * Returns the hash code of the associated identifier.
+     *
+     * @return an <code>int</code> value
+     */
+    public int hashCode() {
+        return id.hashCode();
+    }
+
+    /**
+     * True if the identifiers are the same, false otherwise.
+     *
+     * @param another an <code>Object</code> value
+     * @return a <code>boolean</code> value
+     */
+    public boolean equals(Object another) {
+        if (another instanceof WebContinuation) {
+            return id.equals(((WebContinuation) another).id);
+        }
+        return false;
+    }
+
+    /**
+     * Compares the expiration time of this instance with that of the
+     * WebContinuation passed as argument.
+     *
+     * <p><b>Note:</b> this class has a natural ordering that is
+     * inconsistent with <code>equals</code>.</p>.
+     *
+     * @param other an <code>Object</code> value, which should be a
+     * <code>WebContinuation</code> instance
+     * @return an <code>int</code> value
+     */
+    public int compareTo(Object other) {
+        WebContinuation wk = (WebContinuation) other;
+        return (int) ((lastAccessTime + timeToLive)
+                - (wk.lastAccessTime + wk.timeToLive));
+    }
+
+    /**
+     * Debugging method.
+     *
+     * <p>Assumes the receiving instance as the root of a tree and
+     * displays the tree of continuations.
+     */
+    public void display() {
+        getLogger().debug("\nWK: Tree" + display(0));
+    }
+
+    /**
+     * Debugging method.
+     *
+     * <p>Displays the receiving instance as if it is at the
+     * <code>indent</code> depth in the tree of continuations. Each
+     * level is indented 2 spaces.
+     *
+     * @param depth an <code>int</code> value
+     */
+    protected String display(int depth) {
+        StringBuffer tree = new StringBuffer("\n");
+        for (int i = 0; i < depth; i++) {
+            tree.append("  ");
+        }
+
+        tree.append("WK: WebContinuation ")
+                .append(id)
+                .append(" ExpireTime [");
+
+        if ((lastAccessTime + timeToLive) < System.currentTimeMillis()) {
+            tree.append("Expired");
+        } else {
+            tree.append(lastAccessTime + timeToLive);
+        }
+
+        tree.append("]");
+
+        // REVISIT: is this needed for some reason?
+        // System.out.print(spaces); System.out.println("WebContinuation " + id);
+
+        int size = children.size();
+        depth++;
+
+        for (int i = 0; i < size; i++) {
+            tree.append(((WebContinuation) children.get(i)).display(depth));
+        }
+
+        return tree.toString();
+    }
+
+    /**
+     * Update the continuation in the
+     */
+    protected void updateLastAccessTime() {
+        lastAccessTime = System.currentTimeMillis();
+    }
+
+    /**
+     * Determines whether this continuation has expired
+     *
+     * @return a <code>boolean</code> value
+     */
+    public boolean hasExpired() {
+        long currentTime = System.currentTimeMillis();
+        long expireTime = this.getLastAccessTime() + this.timeToLive;
+
+        return (currentTime > expireTime);
+    }
+
+    /**
+     * Dispose this continuation. Should be called on invalidation.
+     */
+    public void dispose() {
+        // Call possible implementation-specific clean-up on this continuation.
+        if (this.disposer != null) {
+            this.disposer.disposeContinuation(this);
+        }
+        // Remove continuation object - will also serve as "disposed" flag
+        this.continuation = null;
+    }
+
+    /**
+     * Return true if this continuation was disposed of
+     */
+    public boolean disposed() {
+        return this.continuation == null;
+    }
+    
+    public boolean interpreterMatches( String interpreterId ) {
+        return StringUtils.equals( this.interpreterId, interpreterId );
+    }
+
+    public void detachFromParent() {
+        if (getParentContinuation() != null)
+            getParentContinuation().getChildren().remove(this);
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/WebContinuation.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/WebContinuationDataBean.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/WebContinuationDataBean.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/WebContinuationDataBean.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/WebContinuationDataBean.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,93 @@
+/*
+ * Copyright 1999-2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Access to continuation data for monitoring applications
+ */
+public class WebContinuationDataBean {
+
+    private static final String TYPE_JAVAFLOW = "javaflow";
+    private static final String TYPE_FLOWSCRIPT = "flowscript";
+    private static final String HAS_EXPIRED_NO = "no";
+    private static final String HAS_EXPIRED_YES = "yes";
+
+    private WebContinuation wc;
+    private SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
+    private List _children = new ArrayList();
+
+    public WebContinuationDataBean(WebContinuation wc) {
+        this.wc = wc;
+        for (Iterator it = wc.getChildren().iterator(); it.hasNext();) {
+            WebContinuationDataBean child = new WebContinuationDataBean(
+                    (WebContinuation) it.next());
+            this._children.add(child);
+        }
+    }
+
+    public String getId() {
+        return wc.getId();
+    }
+
+    public String getLastAccessTime() {
+        return formatter.format(new Date(wc.getLastAccessTime()));
+    }
+
+    public String getInterpreterId() {
+        return wc.getInterpreterId();
+    }
+
+    public String getTimeToLiveInMinutes() {
+        return Long.toString(wc.getTimeToLive() / 1000 / 60);
+    }
+
+    public String getTimeToLive() {
+        return Long.toString(wc.getTimeToLive());
+    }
+
+    public String getExpireTime() {
+        return formatter.format(new Date(wc.getLastAccessTime()
+                + wc.getTimeToLive()));
+    }
+
+    public String hasExpired() {
+        if ((wc.getLastAccessTime() + wc.getTimeToLive()) < System
+                .currentTimeMillis()) {
+            return HAS_EXPIRED_YES;
+        }
+        return HAS_EXPIRED_NO;
+
+    }
+
+    public String getType() {
+        if (wc.getUserObject().getClass().getName().indexOf(
+                "FOM_WebContinuation") > 0) {
+            return TYPE_FLOWSCRIPT;
+        }
+        return TYPE_JAVAFLOW;
+    }
+
+    public List get_children() {
+        return this._children;
+    }
+
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/WebContinuationDataBean.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/JSErrorReporter.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/JSErrorReporter.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/JSErrorReporter.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/JSErrorReporter.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,124 @@
+/*
+* 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.cocoon.components.flow.javascript;
+
+import org.apache.avalon.framework.logger.Logger;
+import org.apache.cocoon.util.location.Location;
+import org.apache.cocoon.util.location.LocationImpl;
+import org.mozilla.javascript.ErrorReporter;
+import org.mozilla.javascript.EvaluatorException;
+import org.mozilla.javascript.tools.ToolErrorReporter;
+
+/**
+ * Implements a Rhino JavaScript {@link
+ * org.mozilla.javascript.ErrorReporter}. 
+ * Like ToolErrorReporter but logs to supplied logger instead of stdout
+ *
+ * @version CVS $Id: JSErrorReporter.java 292797 2005-09-30 16:05:46Z sylvain $
+ */
+public class JSErrorReporter implements ErrorReporter
+{
+  private Logger logger;
+  private Location location;
+  private StringBuffer message;
+
+  public JSErrorReporter(Logger logger)
+  {
+      this.logger = logger;
+  }
+  
+  private void appendMessage(String text, String sourceName, int line, int column) {
+      if (location == null) {
+          location = new LocationImpl(null, sourceName, line, column);
+          message = new StringBuffer();
+      } else {
+          // Append a linefeed
+          message.append("\n");
+      }
+      
+      message.append(text);
+  }
+
+  public void error(String message,
+                    String sourceName, int line,
+                    String lineSrc, int column)
+  {
+      String errMsg = getErrorMessage("msg.error", message, 
+                                      sourceName, line, lineSrc, column);
+      appendMessage(errMsg, sourceName, line, column);
+      System.err.println(errMsg);
+      logger.error(errMsg);
+  }
+
+  public void warning(String message, String sourceName, int line,
+                      String lineSrc, int column)
+  {
+      String errMsg = getErrorMessage("msg.warning", message, 
+                                    sourceName, line, lineSrc, column);
+      appendMessage(errMsg, sourceName, line, column);
+      System.err.println(errMsg);
+      logger.warn(errMsg);
+  }
+    
+  public EvaluatorException runtimeError(String message, String sourceName,
+                                         int line, String lineSrc,
+                                         int column)
+  {
+      String errMsg = getErrorMessage("msg.error", message,
+                                      sourceName, line,
+                                      lineSrc, column);
+      appendMessage(errMsg, sourceName, line, column);
+      System.err.println(errMsg);
+      // FIXME(SW): need to build a locatable extension to EvaluatorException
+      return new EvaluatorException(this.message.toString());
+  }
+
+  /**
+   * Formats error message
+   *
+   * @param type a <code>String</code> value, indicating the error
+   * type (error or warning)
+   * @param message a <code>String</code> value, the error or warning
+   * message
+   * @param line an <code>int</code> value, the original cummulative
+   * line number
+   * @param lineSource a <code>String</code> value, the text of the
+   * line in the file
+   * @param column an <code>int</code> value, the column in
+   * <code>lineSource</code> where the error appeared
+   * @return a <code>String</code> value, the aggregated error
+   * message, with the source file and line number adjusted to the
+   * real values
+   */
+    String getErrorMessage(String type,
+                           String message,
+                           String sourceName, int line,
+                           String lineSource, int column)
+    {
+        if (line > 0) {
+            if (sourceName != null) {
+                Object[] errArgs = { sourceName, new Integer(line), message };
+                return ToolErrorReporter.getMessage("msg.format3", errArgs);
+          } else {
+              Object[] errArgs = { new Integer(line), message };
+              return ToolErrorReporter.getMessage("msg.format2", errArgs);
+            }
+        } else {
+            Object[] errArgs = { message };
+            return ToolErrorReporter.getMessage("msg.format1", errArgs);
+        }
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/JSErrorReporter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/LocationTrackingDebugger.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/LocationTrackingDebugger.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/LocationTrackingDebugger.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/LocationTrackingDebugger.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,157 @@
+/*
+ * 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.location.Location;
+import org.apache.cocoon.util.location.LocationImpl;
+import org.apache.cocoon.util.location.LocationUtils;
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.EcmaError;
+import org.mozilla.javascript.JavaScriptException;
+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: LocationTrackingDebugger.java 280811 2005-09-14 09:53:32Z sylvain $
+ */
+public class LocationTrackingDebugger implements Debugger {
+    
+    // Strong reference to the location finder
+    private static final LocationUtils.LocationFinder rhinoLocFinder = new LocationUtils.LocationFinder() {
+
+        public Location getLocation(Object obj, String description) {
+            if (obj instanceof EcmaError) {
+                EcmaError ex = (EcmaError)obj;
+                if (ex.getSourceName() != null) {
+                    return new LocationImpl(ex.getName(), ex.getSourceName(), ex.getLineNumber(), ex.getColumnNumber());
+                } else {
+                    return Location.UNKNOWN;
+                }
+    
+            } else if (obj instanceof JavaScriptException) {
+                JavaScriptException ex = (JavaScriptException)obj;
+                if (ex.sourceName() != null) {
+                    return new LocationImpl(description, ex.sourceName(), ex.lineNumber(), -1);
+                } else {
+                    return Location.UNKNOWN;
+                }
+            }
+            
+            return null;
+        } 
+    };
+
+    
+    static {
+        // Register what's needed to analyze exceptions produced by Rhino
+        ExceptionUtils.addCauseMethodName("getWrappedException");
+        LocationUtils.addFinder(rhinoLocFinder);
+    }
+    
+    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/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/LocationTrackingDebugger.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptableMap.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptableMap.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptableMap.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptableMap.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,126 @@
+/*
+ * 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.cocoon.components.flow.javascript;
+
+import org.mozilla.javascript.NativeJavaObject;
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.Wrapper;
+
+import java.util.Map;
+
+/**
+ * Wrap a java.util.Map for JavaScript.
+ *
+ * @version CVS $Id: ScriptableMap.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+public class ScriptableMap implements Scriptable, Wrapper {
+
+    private Map map;
+    private Scriptable prototype, parent;
+
+    public ScriptableMap() {
+    }
+
+    public ScriptableMap(Map map) {
+        this.map = map;
+    }
+
+    public String getClassName() {
+        return "Map";
+    }
+
+    public boolean has(String name, Scriptable start) {
+        return this.map.containsKey(name);
+    }
+
+    /**
+     * no numeric properties
+     */
+    public boolean has(int index, Scriptable start) {
+        return false;
+    }
+
+    public Object get(String name, Scriptable start) {
+        if (this.map.containsKey(name))
+            return this.map.get(name);
+
+        return NOT_FOUND;
+    }
+
+    public Object get(int index, Scriptable start) {
+        return NOT_FOUND;
+    }
+
+    public void put(String name, Scriptable start, Object value) {
+        if (value instanceof NativeJavaObject) {
+            value = ((NativeJavaObject)value).unwrap();
+        }
+        map.put(name, value);
+    }
+
+    public void put(int index, Scriptable start, Object value) {
+    }
+
+    public void delete(String id) {
+        map.remove(id);
+    }
+
+    public void delete(int index) {
+    }
+
+    public Scriptable getPrototype() {
+        return prototype;
+    }
+
+    public void setPrototype(Scriptable prototype) {
+        this.prototype = prototype;
+    }
+
+    public Scriptable getParentScope() {
+        return parent;
+    }
+
+    public void setParentScope(Scriptable parent) {
+        this.parent = parent;
+    }
+
+    public Object[] getIds() {
+        return this.map.keySet().toArray();
+    }
+
+    public Object getDefaultValue(Class typeHint) {
+        return this.map.toString();
+    }
+
+    public boolean hasInstance(Scriptable value) {
+        Scriptable proto = value.getPrototype();
+        while (proto != null) {
+            if (proto.equals(this)) 
+                return true;
+            proto = proto.getPrototype();
+        }
+
+        return false;
+    }
+
+    /**
+     * Return the java.util.Map that is wrapped by this class.
+     */
+    public Object unwrap() {
+        return this.map;
+    }
+
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptableMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePointer.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePointer.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePointer.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePointer.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,97 @@
+/*
+ * 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.cocoon.components.flow.javascript;
+
+import java.util.Locale;
+
+import org.apache.commons.jxpath.ri.QName;
+import org.apache.commons.jxpath.ri.model.NodePointer;
+import org.apache.commons.jxpath.ri.model.beans.PropertyPointer;
+import org.apache.commons.jxpath.ri.model.dynamic.DynamicPointer;
+import org.mozilla.javascript.NativeArray;
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.ScriptableObject;
+import org.mozilla.javascript.Wrapper;
+
+/**
+ *
+ * @version CVS $Id: ScriptablePointer.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+public class ScriptablePointer extends DynamicPointer {
+
+    Scriptable node;
+
+    final static ScriptablePropertyHandler handler = 
+        new ScriptablePropertyHandler();
+
+    public ScriptablePointer(NodePointer parent,
+                             QName name,
+                             Scriptable object) {
+        super(parent, name, object, handler);
+        node = object;
+    }
+
+    public ScriptablePointer(QName name,
+                             Scriptable object,
+                             Locale locale) {
+        super(name, object, handler, locale);
+        node = object;
+    }
+
+    public PropertyPointer getPropertyPointer(){
+        return new ScriptablePropertyPointer(this, handler);
+    }
+
+    public int getLength() {
+        Object obj = getBaseValue();
+        if (obj instanceof Scriptable) {
+            Scriptable node = (Scriptable)obj;
+            if (node instanceof NativeArray) {
+                return (int)((NativeArray)node).jsGet_length();
+            }
+            if (ScriptableObject.hasProperty(node, "length")) {
+                Object val = ScriptableObject.getProperty(node, "length");
+                if (val instanceof Number) {
+                    return ((Number)val).intValue();
+                }
+            }
+        }
+        return super.getLength();
+    }
+
+    public Object getImmediateNode() {
+        Object value;
+        if (index == WHOLE_COLLECTION) {
+            value = node;
+        } else {
+            value = ScriptableObject.getProperty(node, index);
+            if (value == Scriptable.NOT_FOUND) {
+                value = node; // hack: same behavior as ValueUtils.getValue()
+            } 
+        }
+        if (value instanceof Wrapper) {
+            value = ((Wrapper)value).unwrap();
+        }
+        return value;
+    }
+
+    public void setValue(Object value){
+        if (getParent() != null) {
+            getParent().setValue(value);
+        }
+    }
+
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePointer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePointerFactory.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePointerFactory.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePointerFactory.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePointerFactory.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,50 @@
+/*
+ * 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.cocoon.components.flow.javascript;
+
+import org.apache.commons.jxpath.ri.model.NodePointerFactory;
+import org.apache.commons.jxpath.ri.model.NodePointer;
+import org.apache.commons.jxpath.ri.QName;
+import java.util.Locale;
+import org.mozilla.javascript.Scriptable;
+
+/**
+ *
+ * @version CVS $Id: ScriptablePointerFactory.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+public class ScriptablePointerFactory implements NodePointerFactory {
+
+    public int getOrder() {
+        return 1;
+    }
+
+    public NodePointer createNodePointer(QName name, Object object,
+                                         Locale locale) {
+        if (object instanceof Scriptable) {
+            return new ScriptablePointer(name, (Scriptable)object, locale);
+        }
+        return null;
+    }
+
+    public NodePointer createNodePointer(NodePointer parent,
+                                         QName name, Object object) {
+        if (object instanceof Scriptable) {
+            return new ScriptablePointer(parent, name, 
+                                         (Scriptable)object);
+        }
+        return null;
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePointerFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePropertyHandler.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePropertyHandler.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePropertyHandler.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePropertyHandler.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,102 @@
+/*
+ * 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.cocoon.components.flow.javascript;
+
+import org.apache.commons.jxpath.DynamicPropertyHandler;
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.Function;
+import org.mozilla.javascript.JavaScriptException;
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.ScriptableObject;
+import org.mozilla.javascript.Undefined;
+import org.mozilla.javascript.Wrapper;
+
+/**
+ *
+ * @version CVS $Id: ScriptablePropertyHandler.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+public class ScriptablePropertyHandler implements DynamicPropertyHandler {
+
+    public Object getProperty(Object obj, String propertyName) {
+        Context cx = null;
+        try {
+            cx = Context.enter();
+            Scriptable s = (Scriptable)obj;
+            Object result = ScriptableObject.getProperty(s, propertyName);
+            if (result == Scriptable.NOT_FOUND) {
+                result = ScriptableObject.getProperty(s, "get" + propertyName.substring(0, 1).toUpperCase() + (propertyName.length() > 1 ? propertyName.substring(1) : ""));
+                if (result != Scriptable.NOT_FOUND &&
+                    result instanceof Function) {
+                    try {
+                        result = ((Function)result).call(cx, 
+                                                         ScriptableObject.getTopLevelScope(s), s, new Object[] {});
+                    } catch (JavaScriptException exc) {
+                        exc.printStackTrace();
+                        result = Undefined.instance;
+                    }
+                } 
+                if (result == Undefined.instance ||
+                    result == Scriptable.NOT_FOUND) {
+                    result = null;
+                }
+            } else if (result instanceof Wrapper) {
+                result = ((Wrapper)result).unwrap();
+            } else if (result == Undefined.instance) {
+                result = null;
+            }
+            return result;
+        } finally {
+            Context.exit();
+        }
+    }
+    
+    public String[] getPropertyNames(Object obj) {
+        Context.enter();
+        try {
+            Object[] ids;
+            if (obj instanceof ScriptableObject) {
+                ids = ((ScriptableObject)obj).getAllIds();
+            } else {
+                ids = ((Scriptable)obj).getIds();
+            }
+            String[] result = new String[ids.length];
+            for (int i = 0; i < result.length; i++) {
+                result[i] = (String)ids[i];
+            }
+            return result;
+        } finally {
+            Context.exit();
+        }
+    }
+    
+    public void setProperty(Object obj, String propertyName,
+                            Object value) {
+        Context.enter();
+        try {
+            if (!(value == null
+                  || value instanceof String 
+                  || value instanceof Number 
+                  || value instanceof Boolean)) {
+                value = Context.toObject(value, 
+                                         (Scriptable)obj);
+            }
+            ScriptableObject.putProperty((Scriptable)obj,
+                                         propertyName, value);
+        } finally {
+            Context.exit();
+        }
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePropertyHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePropertyPointer.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePropertyPointer.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePropertyPointer.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePropertyPointer.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,176 @@
+/*
+ * 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.cocoon.components.flow.javascript;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.jxpath.DynamicPropertyHandler;
+import org.apache.commons.jxpath.ri.model.NodePointer;
+import org.apache.commons.jxpath.ri.model.dynamic.DynamicPropertyPointer;
+import org.mozilla.javascript.NativeArray;
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.ScriptableObject;
+import org.mozilla.javascript.Undefined;
+import org.mozilla.javascript.Wrapper;
+
+/**
+ *
+ * @version CVS $Id: ScriptablePropertyPointer.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+public class ScriptablePropertyPointer extends DynamicPropertyPointer {
+
+    DynamicPropertyHandler handler;
+
+    public ScriptablePropertyPointer(NodePointer parent,
+                                     DynamicPropertyHandler handler) {
+        super(parent, handler);
+        this.handler = handler;
+    }
+
+    public int getLength() {
+        Object obj = getBaseValue();
+        if (obj instanceof Scriptable) {
+            Scriptable node = (Scriptable)obj;
+            if (node instanceof NativeArray) {
+                return (int)((NativeArray)node).jsGet_length();
+            }
+            if (ScriptableObject.hasProperty(node, "length")) {
+                Object val = ScriptableObject.getProperty(node, "length");
+                if (val instanceof Number) {
+                    return ((Number)val).intValue();
+                }
+            }
+        }
+        return super.getLength();
+    }
+
+    public Object getImmediateNode() {
+        Object value;
+        if (index == WHOLE_COLLECTION) {
+            value = getBaseValue();
+        }
+        else {
+            value = getBaseValue();
+            if (value instanceof Scriptable) {
+                Object property = 
+                    ScriptableObject.getProperty((Scriptable)value, index);
+                if (property != Scriptable.NOT_FOUND) { 
+                    value = property; // hack?
+                } 
+            } else {
+                return super.getImmediateNode();
+            }
+        }
+        if (value instanceof Wrapper) {
+            value = ((Wrapper)value).unwrap();
+        }
+        return value;
+    }
+
+    public Object getValue() {
+        Object val = getNode();
+        if (val instanceof NativeArray) {
+            NativeArray arr = (NativeArray)val;
+            List list = new LinkedList();
+            int len = (int)arr.jsGet_length();
+            for (int i = 0; i < len; i++) {
+                Object obj = arr.get(i, arr);
+                if (obj == Undefined.instance) {
+                    obj = null;
+                }
+                list.add(obj);
+            }
+            return list;
+        }
+        return super.getValue();
+    }
+
+    public void setValue(Object value){
+        if (index == WHOLE_COLLECTION){
+            handler.setProperty(getBean(), getPropertyName(), value);
+        } else {
+            Object val = handler.getProperty(getBean(), getPropertyName());
+            if (val instanceof Scriptable) {
+                ScriptableObject.putProperty((Scriptable)val, index, value);
+            } else {
+                super.setValue(value);
+            }
+        }
+    }
+
+    public void remove(){
+        if (index == WHOLE_COLLECTION){
+            handler.setProperty(getBean(), "length", new Integer(0));
+        } else {
+            Object val = handler.getProperty(getBean(), getPropertyName());
+            if (val instanceof Scriptable) {
+                try {
+                    ScriptableObject.deleteProperty((Scriptable)val, index);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            } else {
+                super.remove();
+            }
+        }
+    }
+
+    public boolean isCollection() {
+        Object obj = getBaseValue();
+        if (obj instanceof NativeArray) {
+            return true;
+        }
+        return super.isCollection();
+    }
+
+    public String asPath(){
+        Object obj = getBaseValue();
+        if (!(obj instanceof Scriptable)) {
+            return super.asPath();
+        }
+        StringBuffer buffer = new StringBuffer();
+        buffer.append(getParent().asPath());
+        if (buffer.length() == 0){
+            buffer.append("/.");
+        }
+        else if (buffer.charAt(buffer.length() - 1) == '/'){
+            buffer.append('.');
+        }
+        buffer.append("[@name = '");
+        buffer.append(escape(getPropertyName()));
+        buffer.append("']");
+        if (index != WHOLE_COLLECTION && (obj instanceof NativeArray)) {
+            buffer.append('[').append(index+1).append(']');
+        }
+        return buffer.toString();
+    }
+
+    private String escape(String string){
+        int index = string.indexOf('\'');
+        while (index != -1){
+            string = string.substring(0, index) + "&apos;" + string.substring(index + 1);
+            index = string.indexOf('\'');
+        }
+        index = string.indexOf('\"');
+        while (index != -1){
+            string = string.substring(0, index) + "&quot;" + string.substring(index + 1);
+            index = string.indexOf('\"');
+        }
+        return string;
+    }
+
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/ScriptablePropertyPointer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/fom/FOMResourceNotFoundException.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/fom/FOMResourceNotFoundException.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/fom/FOMResourceNotFoundException.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/fom/FOMResourceNotFoundException.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,35 @@
+/*
+ * Copyright 1999-2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.fom;
+
+import org.apache.avalon.framework.CascadingRuntimeException;
+
+/**
+ * The exception thrown when the FOM classes can't find the necessary
+ * resource.
+ */
+public final class FOMResourceNotFoundException extends CascadingRuntimeException
+{
+    public FOMResourceNotFoundException(String message)
+    {
+        super(message, null);
+    }
+
+    public FOMResourceNotFoundException(String message, Throwable cause)
+    {
+        super(message, cause);
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/fom/FOMResourceNotFoundException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/fom/FOM_Cocoon.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/fom/FOM_Cocoon.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/fom/FOM_Cocoon.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/flow/javascript/fom/FOM_Cocoon.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,795 @@
+/*
+ * 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.cocoon.components.flow.javascript.fom;
+
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.avalon.framework.context.Context;
+import org.apache.avalon.framework.context.ContextException;
+import org.apache.avalon.framework.logger.Logger;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.cocoon.components.ContextHelper;
+import org.apache.cocoon.components.LifecycleHelper;
+import org.apache.cocoon.components.flow.ContinuationsManager;
+import org.apache.cocoon.components.flow.WebContinuation;
+import org.apache.cocoon.components.flow.Interpreter.Argument;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Redirector;
+import org.apache.cocoon.environment.Request;
+import org.apache.cocoon.environment.Response;
+import org.apache.cocoon.environment.Session;
+import org.apache.cocoon.util.ClassUtils;
+import org.mozilla.javascript.JavaScriptException;
+import org.mozilla.javascript.NativeJavaClass;
+import org.mozilla.javascript.NativeJavaObject;
+import org.mozilla.javascript.Script;
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.ScriptableObject;
+import org.mozilla.javascript.Undefined;
+import org.mozilla.javascript.Wrapper;
+import org.mozilla.javascript.continuations.Continuation;
+
+/**
+ * Implementation of FOM (Flow Object Model).
+ *
+ * @since 2.1
+ * @author <a href="mailto:coliver.at.apache.org">Christopher Oliver</a>
+ * @author <a href="mailto:reinhard.at.apache.org">Reinhard P\u00F6tz</a>
+ * @version CVS $Id: FOM_Cocoon.java 292491 2005-09-29 17:44:16Z bloritsch $
+ */
+public class FOM_Cocoon extends ScriptableObject {
+
+    class CallContext {
+        CallContext caller;
+        Context avalonContext;
+        ServiceManager serviceManager;
+        FOM_JavaScriptInterpreter interpreter;
+        Redirector redirector;
+        Logger logger;
+        Scriptable request;
+        Scriptable response;
+        Scriptable session;
+        Scriptable context;
+        Scriptable parameters;
+        Scriptable log;
+        WebContinuation lastContinuation;
+        FOM_WebContinuation fwk;
+        PageLocalScopeImpl currentPageLocal;
+
+        public CallContext(CallContext caller,
+                           FOM_JavaScriptInterpreter interp,
+                           Redirector redirector,
+                           ServiceManager manager,
+                           Context avalonContext,
+                           Logger logger,
+                           WebContinuation lastContinuation) {
+            this.caller = caller;
+            this.interpreter = interp;
+            this.redirector = redirector;
+            this.serviceManager = manager;
+            this.avalonContext = avalonContext;
+            this.logger = logger;
+            this.lastContinuation = lastContinuation;
+            if (lastContinuation != null) {
+                fwk = new FOM_WebContinuation(lastContinuation);
+                Scriptable scope = FOM_Cocoon.this.getParentScope();
+                fwk.setParentScope(scope);
+                fwk.setPrototype(getClassPrototype(scope, fwk.getClassName()));
+                this.currentPageLocal = fwk.getPageLocal();
+            }
+            if (this.currentPageLocal != null) {
+                // "clone" the page local scope
+                this.currentPageLocal = this.currentPageLocal.duplicate();
+            } else {
+                this.currentPageLocal = new PageLocalScopeImpl(getTopLevelScope(FOM_Cocoon.this));
+            }
+            pageLocal.setDelegate(this.currentPageLocal);
+        }
+
+        public FOM_WebContinuation getLastContinuation() {
+            return fwk;
+        }
+
+        public void setLastContinuation(FOM_WebContinuation fwk) {
+            this.fwk = fwk;
+            if (fwk != null) {
+                pageLocal.setDelegate(fwk.getPageLocal());
+                this.lastContinuation = fwk.getWebContinuation();
+            } else {
+                this.lastContinuation = null;
+            }
+        }
+
+        public Scriptable getSession() {
+            if (session != null) {
+                return session;
+            }
+            Map objectModel = ContextHelper.getObjectModel(this.avalonContext);            
+            session = new FOM_Session(
+                    getParentScope(),
+                    ObjectModelHelper.getRequest(objectModel).getSession(true));
+            return session;
+        }
+
+        public Scriptable getRequest() {
+            if (request != null) {
+                return request;
+            }
+            Map objectModel = ContextHelper.getObjectModel(this.avalonContext);
+            request = new FOM_Request(
+                    getParentScope(),
+                    ObjectModelHelper.getRequest(objectModel));
+            return request;
+        }
+
+        public Scriptable getContext() {
+            if (context != null) {
+                return context;
+            }
+            Map objectModel = ContextHelper.getObjectModel(this.avalonContext);
+            context = new FOM_Context(
+                    getParentScope(),
+                    ObjectModelHelper.getContext(objectModel));
+            return context;
+        }
+
+        public Scriptable getResponse() {
+            if (response != null) {
+                return response;
+            }
+            Map objectModel = ContextHelper.getObjectModel(this.avalonContext);
+            response = org.mozilla.javascript.Context.toObject(
+                    ObjectModelHelper.getResponse(objectModel),
+                    getParentScope());
+            return response;
+        }
+
+        public Scriptable getLog() {
+            if (log != null) {
+                return log;
+            }
+            log = org.mozilla.javascript.Context.toObject(logger, getParentScope());
+            return log;
+        }
+
+        public Scriptable getParameters() {
+            return parameters;
+        }
+
+        public void setParameters(Scriptable parameters) {
+            this.parameters = parameters;
+        }
+    }
+
+    private CallContext currentCall;
+    protected PageLocalScopeHolder pageLocal;
+
+    public String getClassName() {
+        return "FOM_Cocoon";
+    }
+
+
+    // Called by FOM_JavaScriptInterpreter
+    static void init(Scriptable scope) throws Exception {
+        //FIXME(SW) what is the exact purpose of defineClass() ??
+        defineClass(scope, FOM_Cocoon.class);
+//        defineClass(scope, FOM_Request.class);
+//        defineClass(scope, FOM_Response.class);
+//        defineClass(scope, FOM_Cookie.class);
+//        defineClass(scope, FOM_Session.class);
+//        defineClass(scope, FOM_Context.class);
+//        defineClass(scope, FOM_Log.class);
+        defineClass(scope, FOM_WebContinuation.class);
+        defineClass(scope, PageLocalImpl.class);
+    }
+
+    void pushCallContext(FOM_JavaScriptInterpreter interp,
+                         Redirector redirector,
+                         ServiceManager manager,
+                         Context avalonContext,
+                         Logger logger,
+                         WebContinuation lastContinuation) {
+        if (pageLocal == null) {
+            pageLocal = new PageLocalScopeHolder(getTopLevelScope(this));
+        }
+        
+        // The call context will use the current sitemap's service manager when looking up components
+        ServiceManager sitemapManager;
+        try {
+            sitemapManager = (ServiceManager)avalonContext.get(ContextHelper.CONTEXT_SITEMAP_SERVICE_MANAGER);
+        } catch (ContextException e) {
+            throw new FOMResourceNotFoundException("Cannot get sitemap service manager", e);
+        }
+
+        this.currentCall = new CallContext(currentCall, interp, redirector, sitemapManager,
+                                           avalonContext,
+                                           logger, lastContinuation);
+    }
+
+    void popCallContext() {
+        // Clear the scope attribute
+        FOM_JavaScriptFlowHelper.setFOM_FlowScope(this.getObjectModel(), null);
+
+        this.currentCall = this.currentCall.caller;
+        // reset current page locals
+        if (this.currentCall != null) {
+            pageLocal.setDelegate(this.currentCall.currentPageLocal);
+        } else {
+            pageLocal.setDelegate(null);
+        }
+    }
+
+
+    public FOM_WebContinuation jsGet_continuation() {
+        // FIXME: This method can return invalid continuation! Is it OK to do so?
+        return currentCall.getLastContinuation();
+    }
+
+    public void jsSet_continuation(Object obj) {
+        FOM_WebContinuation fwk = (FOM_WebContinuation)unwrap(obj);
+        currentCall.setLastContinuation(fwk);
+    }
+
+    public FOM_WebContinuation jsFunction_sendPage(String uri,
+                                                   Object obj,
+                                                   Object wk)
+        throws Exception {
+        FOM_WebContinuation fom_wk = (FOM_WebContinuation)unwrap(wk);
+        if (fom_wk != null) {
+            // save page locals
+            fom_wk.setPageLocal(pageLocal.getDelegate());
+        }
+        forwardTo(uri, unwrap(obj), fom_wk);
+        return fom_wk;
+    }
+
+    public Scriptable jsFunction_createPageLocal() {
+        return pageLocal.createPageLocal();
+    }
+
+    public void jsFunction_processPipelineTo(String uri,
+                                             Object map,
+                                             Object outputStream)
+    throws Exception {
+        Object out = unwrap(outputStream);
+        if (!(out instanceof OutputStream)) {
+            throw new JavaScriptException("expected a java.io.OutputStream instead of " + out);
+        }
+        getInterpreter().process(getParentScope(), this, uri, map,
+                                 (OutputStream)out);
+    }
+
+    public void jsFunction_redirectTo(String uri, boolean isGlobal) throws Exception {
+        if (isGlobal) {
+            this.currentCall.redirector.globalRedirect(false, uri);
+        } else {
+            this.currentCall.redirector.redirect(false, uri);
+        }
+    }
+
+    public void jsFunction_sendStatus(int sc) {
+        this.currentCall.redirector.sendStatus(sc);
+    }
+
+/*
+
+ NOTE (SM): These are the hooks to the future FOM Event Model that will be
+ designed in the future. It has been postponed because we think
+ there are more important things to do at the moment, but these
+ are left here to indicate that they are planned.
+
+    public void jsFunction_addEventListener(String eventName,
+                                            Object function) {
+        // what is this?
+    }
+
+    public void jsFunction_removeEventListener(String eventName,
+                                               Object function) {
+        // what is this?
+    }
+
+*/
+
+    /**
+     * Access components.
+     *
+     * TODO: Do we want to restrict the access of sitemap components? (RP)
+     * TODO: Do we want to raise an error or return null? (RP)
+     */
+    public Object jsFunction_getComponent(String id)
+        throws Exception {
+        return org.mozilla.javascript.Context.javaToJS(getServiceManager().lookup(id), 
+                                                       getParentScope());
+    }
+
+    /**
+     * Release pooled components.
+     *
+     * @param component a component
+     */
+    public void jsFunction_releaseComponent( Object component ) throws Exception {
+        this.getServiceManager().release( unwrap(component) );
+    }
+
+    /**
+     * Load the script file specified as argument.
+     *
+     * @param filename a <code>String</code> value
+     * @return an <code>Object</code> value
+     * @exception JavaScriptException if an error occurs
+     */
+    public Object jsFunction_load( String filename )
+        throws Exception {
+        org.mozilla.javascript.Context cx =
+            org.mozilla.javascript.Context.getCurrentContext();
+        Scriptable scope = getParentScope();
+        Script script = getInterpreter().compileScript(cx, filename);
+        return script.exec( cx, scope );
+    }
+
+    /**
+     * Setup an object so that it can access the information provided to regular components.
+     * This is done by calling the various Avalon lifecycle interfaces implemented by the object, which
+     * are <code>LogEnabled</code>, <code>Contextualizable</code>, <code>Serviceable</code>
+     * and <code>Initializable</code>.
+     * <p>
+     * <code>Contextualizable</code> is of primary importance as it gives access to the whole object model
+     * (request, response, etc.) through the {@link org.apache.cocoon.components.ContextHelper} class.
+     * <p>
+     * Note that <code>Configurable</code> is ignored, as no configuration exists in a flowscript that
+     * can be passed to the object.
+     *
+     * @param obj the object to setup
+     * @return the same object (convenience that allows to write <code>var foo = cocoon.setupObject(new Foo());</code>).
+     * @throws Exception if something goes wrong during setup.
+     */
+    public Object jsFunction_setupObject(Object obj) throws Exception {
+        LifecycleHelper.setupComponent(
+             unwrap(obj),
+             this.getLogger(),
+             this.getAvalonContext(),
+             this.getServiceManager(),
+             null,// configuration
+             true);
+         return org.mozilla.javascript.Context.javaToJS(obj, getParentScope());
+    }
+
+    /**
+     * Create and setup an object so that it can access the information provided to regular components.
+     * This is done by calling the various Avalon lifecycle interfaces implemented by the object, which
+     * are <code>LogEnabled</code>, <code>Contextualizable</code>, <code>Serviceable</code>
+     * and <code>Initializable</code>.
+     * <p>
+     * <code>Contextualizable</code> is of primary importance as it gives access to the whole object model
+     * (request, response, etc.) through the {@link org.apache.cocoon.components.ContextHelper} class.
+     * <p>
+     * Note that <code>Configurable</code> is ignored, as no configuration exists in a flowscript that
+     * can be passed to the object.
+     *
+     * @param classObj the class to instantiate, either as a String or a Rhino NativeJavaClass object
+     * @return an set up instance of <code>clazz</code>
+     * @throws Exception if something goes wrong either during instantiation or setup.
+     */
+    public Object jsFunction_createObject(Object classObj) throws Exception {
+        Object result;
+
+        if (classObj instanceof String) {
+            result = ClassUtils.newInstance((String)classObj);
+
+        } else if (classObj instanceof NativeJavaClass) {
+            Class clazz = ((NativeJavaClass)classObj).getClassObject();
+            result = clazz.newInstance();
+
+        } else {
+            throw new IllegalArgumentException("cocoon.createObject expects either a String or Class argument, but got "
+                + classObj.getClass());
+        }
+
+        return jsFunction_setupObject(result);
+    }
+
+    /**
+     * Dispose an object that has been created using {@link #jsFunction_createObject(Object)}.
+     *
+     * @param obj
+     * @throws Exception
+     */
+    public void jsFunction_disposeObject(Object obj) throws Exception {
+        LifecycleHelper.decommission(obj);
+    }
+
+    /**
+     * Base JS wrapper for Cocoon's request/session/context objects.
+     * <p>
+     * FIXME(SW): The only thing added to the regular Java object is the fact that
+     * attributes can be accessed as properties. Do we want to keep this?
+     */
+    private static abstract class AttributeHolderJavaObject extends NativeJavaObject {
+        
+        private static Map classProps = new HashMap();
+        private Set propNames;
+
+        public AttributeHolderJavaObject(Scriptable scope, Object object, Class clazz) {
+            super(scope, object, clazz);
+            this.propNames = getProperties(object.getClass());
+        }
+        
+        /** Compute the names of JavaBean properties so that we can filter them our in get() */
+        private static Set getProperties(Class clazz) {
+            Set result = (Set)classProps.get(clazz);
+            if (result == null) {
+                try {
+                    PropertyDescriptor[] descriptors = Introspector.getBeanInfo(clazz).getPropertyDescriptors();
+                    result = new HashSet();
+                    for (int i = 0; i < descriptors.length; i++) {
+                        result.add(descriptors[i].getName());
+                    }
+                } catch (IntrospectionException e) {
+                    // Cannot introspect: just consider there are no properties
+                    result = Collections.EMPTY_SET;
+                }
+                classProps.put(clazz, result);
+            }
+            return result;
+        }
+        
+        
+        protected abstract Enumeration getAttributeNames();
+        protected abstract Object getAttribute(String name);
+        
+        public Object[] getIds() {
+            // Get class Ids
+            Object [] classIds = super.getIds();
+            
+            // and add attribute names
+            ArrayList idList = new ArrayList(Arrays.asList(classIds));
+            Enumeration iter = getAttributeNames();
+            while(iter.hasMoreElements()) {
+                idList.add(iter.nextElement());
+            }
+            return idList.toArray();
+        }
+        
+        public boolean has(String name, Scriptable start) {
+            return super.has(name, start) || getAttribute(name) != null;
+        }
+        
+        public Object get(String name, Scriptable start) {
+            Object result;
+            // Filter out JavaBean properties. We only want methods of the underlying object.
+            if (this.propNames.contains(name)) {
+                result = NOT_FOUND;
+            } else {
+                result = super.get(name, start);
+            }
+            if (result == NOT_FOUND) {
+                result = getAttribute(name);
+                if (result != null) {
+                    result = org.mozilla.javascript.Context.javaToJS(result, start);
+                } else {
+                    result = NOT_FOUND;
+                }
+            }
+            return result;
+        }
+    }
+
+    /**
+     * JS wrapper for Cocoon's request object.
+     * <p>
+     * Request <em>parameters</em> are also present as properties on this object.
+     * Note that this is different from <code>FOM_Context</code> and <code>FOM_Session</code>
+     * that do the same with <em>attributes</em>.
+     */
+    public static class FOM_Request extends AttributeHolderJavaObject {
+        private final Request request;
+        
+        public FOM_Request(Scriptable scope, Request request) {
+            super(scope, request, Request.class);
+            this.request = request;
+        }
+        
+        protected Enumeration getAttributeNames() {
+            return this.request.getParameterNames();
+        }
+        
+        protected Object getAttribute(String name) {
+            return this.request.getParameter(name);
+        }
+    }
+
+    /**
+     * JS wrapper for Cocoon's session object.
+     * <p>
+     * Session attributes are also present as properties on this object.
+     */
+    public static class FOM_Session extends AttributeHolderJavaObject {
+        private final Session session;
+        
+        public FOM_Session(Scriptable scope, Session session) {
+            super(scope, session, Session.class);
+            this.session = session;
+        }
+        
+        protected Enumeration getAttributeNames() {
+            return this.session.getAttributeNames();
+        }
+        
+        protected Object getAttribute(String name) {
+            return this.session.getAttribute(name);
+        }
+    }
+
+    /**
+     * JS wrapper for Cocoon's context object.
+     * <p>
+     * Context attributes are also present as properties on this object.
+     */
+    public static class FOM_Context extends AttributeHolderJavaObject {
+        private final org.apache.cocoon.environment.Context context;
+        
+        public FOM_Context(Scriptable scope, org.apache.cocoon.environment.Context context) {
+            super(scope, context, org.apache.cocoon.environment.Context.class);
+            this.context = context;
+        }
+        
+        protected Enumeration getAttributeNames() {
+            return this.context.getAttributeNames();
+        }
+        
+        protected Object getAttribute(String name) {
+            return this.context.getAttribute(name);
+        }
+    }
+
+    public Scriptable jsGet_request() {
+        return currentCall.getRequest();
+    }
+
+    public Scriptable jsGet_response() {
+        return currentCall.getResponse();
+    }
+
+    public Scriptable jsGet_log() {
+        return currentCall.getLog();
+    }
+
+    public Scriptable jsGet_context() {
+        return currentCall.getContext();
+    }
+
+    public Scriptable jsGet_session() {
+        return currentCall.getSession();
+    }
+
+    /**
+     * Get Sitemap parameters
+     *
+     * @return a <code>Scriptable</code> value whose properties represent
+     * the Sitemap parameters from <map:call>
+     */
+    public Scriptable jsGet_parameters() {
+        return getParameters();
+    }
+
+    public Scriptable getParameters() {
+        return currentCall.getParameters();
+    }
+
+    void setParameters(Scriptable value) {
+        currentCall.setParameters(value);
+    }
+
+    // unwrap Wrapper's and convert undefined to null
+    private static Object unwrap(Object obj) {
+        if (obj instanceof Wrapper) {
+            obj = ((Wrapper)obj).unwrap();
+        } else if (obj == Undefined.instance) {
+            obj = null;
+        }
+        return obj;
+    }
+
+    // Make everything available to JavaScript objects implemented in Java:
+
+    /**
+     * Get the current request
+     * @return The request
+     */
+    public Request getRequest() {
+        return ObjectModelHelper.getRequest(ContextHelper.getObjectModel(currentCall.avalonContext));
+    }
+
+    /**
+     * Get the current session
+     * @return The session (may be null)
+     */
+    public Session getSession() {
+        return ObjectModelHelper.getRequest(ContextHelper.getObjectModel(currentCall.avalonContext)).getSession(true);
+    }
+
+    /**
+     * Get the current response
+     * @return The response
+     */
+    public Response getResponse() {
+        return ObjectModelHelper.getResponse(ContextHelper.getObjectModel(currentCall.avalonContext));
+    }
+
+    /**
+     * Get the current context
+     * @return The context
+     */
+    public org.apache.cocoon.environment.Context getContext() {
+        return ObjectModelHelper.getContext(ContextHelper.getObjectModel(currentCall.avalonContext));
+    }
+
+    /**
+     * Get the current object model
+     * @return The object model
+     */
+    public Map getObjectModel() {
+        return ContextHelper.getObjectModel(currentCall.avalonContext);
+    }
+
+    private Context getAvalonContext() {
+        return currentCall.avalonContext;
+    }
+
+    private Logger getLogger() {
+        return currentCall.logger;
+    }
+
+    public ServiceManager getServiceManager() {
+        return currentCall.serviceManager;
+    }
+
+    private FOM_JavaScriptInterpreter getInterpreter() {
+        return currentCall.interpreter;
+    }
+
+    /**
+     * Required by FOM_WebContinuation. This way we do not make whole Interpreter public
+     * @return interpreter Id associated with this FOM.
+     */
+    public String getInterpreterId() {
+        return getInterpreter().getInterpreterID();
+    }
+    
+    /**
+     * Call the Cocoon Sitemap to process a page
+     * @param uri Uri to match
+     * @param bean Input to page
+     * @param fom_wk Current Web continuation (may be null)
+     */
+
+    public void forwardTo(String uri,
+                          Object bean,
+                          FOM_WebContinuation fom_wk)
+        throws Exception {
+        getInterpreter().forwardTo(getTopLevelScope(this),
+                                   this,
+                                   uri,
+                                   bean,
+                                   fom_wk,
+                                   this.currentCall.redirector);
+    }
+
+    /**
+     * Perform the behavior of <map:call continuation="blah">
+     * This can be used in cases where the continuation id is not encoded
+     * in the request in a form convenient to access in the sitemap.
+     * Your script can extract the id from the request and then call
+     * this method to process it as normal.
+     * @param kontId The continuation id
+     * @param parameters Any parameters you want to pass to the continuation (may be null)
+     */
+    public void handleContinuation(String kontId, Scriptable parameters)
+        throws Exception {
+        List list = null;
+        if (parameters == null || parameters == Undefined.instance) {
+            parameters = getParameters();
+        }
+        Object[] ids = parameters.getIds();
+        list = new ArrayList();
+        for (int i = 0; i < ids.length; i++) {
+            String name = ids[i].toString();
+            Argument arg = new Argument(name,
+                                        org.mozilla.javascript.Context.toString(getProperty(parameters, name)));
+            list.add(arg);
+        }
+        getInterpreter().handleContinuation(kontId, list, this.currentCall.redirector);
+    }
+
+    /**
+     * Return this continuation if it is valid, or first valid parent
+     */
+    private FOM_WebContinuation findValidParent(FOM_WebContinuation wk) {
+        if (wk != null) {
+            WebContinuation wc = wk.getWebContinuation();
+            while (wc != null && wc.disposed()) {
+                wc = wc.getParentContinuation();
+            }
+            if (wc != null) {
+                return new FOM_WebContinuation(wc);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Create a Bookmark WebContinuation from a JS Continuation with the last
+     * continuation of sendPageAndWait as its parent.
+     * PageLocal variables will be shared with the continuation of
+     * the next call to sendPageAndWait().
+     * @param k The JS continuation
+     * @param ttl Lifetime for this continuation (zero means no limit)
+     */
+    public FOM_WebContinuation jsFunction_makeWebContinuation(Object k,
+                                                              Object ttl)
+        throws Exception {
+        double d = org.mozilla.javascript.Context.toNumber(ttl);
+        FOM_WebContinuation result =
+            makeWebContinuation((Continuation)unwrap(k),
+                                findValidParent(jsGet_continuation()),
+                                (int)d);
+        result.setPageLocal(pageLocal.getDelegate());
+        currentCall.setLastContinuation(result);
+        return result;
+    }
+
+    /**
+     * Create a Web Continuation from a JS Continuation
+     * @param k The JS continuation (may be null - null will be returned in that case)
+     * @param parent The parent of this continuation (may be null)
+     * @param timeToLive Lifetime for this continuation (zero means no limit)
+     */
+    public FOM_WebContinuation makeWebContinuation(Continuation k,
+                                                   FOM_WebContinuation parent,
+                                                   int timeToLive)
+        throws Exception {
+        if (k == null) {
+            return null;
+        }
+        WebContinuation wk;
+        ContinuationsManager contMgr;
+        contMgr = (ContinuationsManager)
+            getServiceManager().lookup(ContinuationsManager.ROLE);
+        wk = contMgr.createWebContinuation(unwrap(k),
+                                           (parent == null ? null : parent.getWebContinuation()),
+                                           timeToLive,
+                                           getInterpreter().getInterpreterID(),
+                                           null);
+        FOM_WebContinuation result = new FOM_WebContinuation(wk);
+        result.setParentScope(getParentScope());
+        result.setPrototype(getClassPrototype(getParentScope(),
+                                              result.getClassName()));
+        return result;
+    }
+}



Mime
View raw message