coliver     2003/02/23 11:20:25

  Modified:    src/java/org/apache/cocoon/components/flow/javascript
                        system.js ScriptablePointer.java
                        ScriptablePropertyPointer.java
                        ScriptablePropertyHandler.java
  Log:
  'Updated to support using the Cocoon flow layer with XMLForm'
  
  Revision  Changes    Path
  1.7       +264 -0    
xml-cocoon2/src/java/org/apache/cocoon/components/flow/javascript/system.js
  
  Index: system.js
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/flow/javascript/system.js,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- system.js 9 Jan 2003 03:41:37 -0000       1.6
  +++ system.js 23 Feb 2003 19:20:25 -0000      1.7
  @@ -112,3 +112,267 @@
       cocoon.outputModuleRollback(type);
     }
   }
  +
  +//
  +// XMLForm Support
  +//
  +
  +/**
  + * Creates a new JavaScript wrapper of a Form object
  + * see org.apache.cocoon.components.xmlform.Form
  + * @param id form id
  + * @param validatorNS Namespace of validator
  + * @param validatorDoc Validator document
  + */
  +
  +function XForm(id, validatorNS, validatorDoc) {
  +    cocoon.createSession();
  +    this.id = id;
  +    this.lastContinuation = null;
  +    XForm.forms[id] = this;
  +    this.validatorNS = validatorNS;
  +    this.validatorDoc = validatorDoc;
  +    this.dead = false;
  +}
  +
  +/**
  + * Global variable that stores XForm instances by id
  + */
  +XForm.forms = {};
  +
  +/**
  + * Return the model object of this form
  + * @return a Java bean, JavaScript, DOM, or JDOM object 
  + */
  +XForm.prototype.getModel = function() {
  +    return this.form.getModel();
  +}
  +
  +/**
  + * Set the model object of this form
  + * @param model Any Java bean, JavaScript, DOM, or JDOM object 
  + */
  +XForm.prototype.setModel = function(model) {
  +    this.form = 
  +     new Packages.org.apache.cocoon.components.xmlform.Form(this.id, 
  +                                                            model);
  +    this.form.setAutoValidate(false);
  +    if (this.validatorNS != undefined && this.validatorDoc != undefined) {
  +     this._setValidator(this.validatorNS, this.validatorDoc);
  +    }
  +}
  +
  +/**
  + * Creates a new web continuation
  + * @param lastCont previous web continuation
  + * @param timeToLive expiration time for this continuation
  + * @return a new WebContinuation instance
  + */
  +XForm.prototype.start = function(lastCont, timeToLive) {
  +    var k = new Continuation();
  +    var kont = new WebContinuation(cocoon, k, 
  +                                lastCont, timeToLive);
  +    return kont;
  +} 
  +
  +/**
  + * Adds a violation to this form
  + * @param xpath xpath expression of field that contains invalid data
  + * @param message error message
  + */
  +XForm.prototype.addViolation = function(xpath, message) {
  +    var violation = 
  +       new Packages.org.apache.cocoon.components.validation.Violation();
  +    violation.path = xpath;
  +    violation.message = message;
  +    var list = new java.util.LinkedList();
  +    list.add(violation);
  +    try {
  +     this.form.addViolations(list);
  +    } catch (e) {
  +     print(e);
  +     if (e instanceof java.lang.Throwable) {
  +         e.printStackTrace();
  +     }
  +    }
  +}
  +
  +/**
  + * Computes the value of an xpath expression against the model of this form
  + * @param expr xpath expression
  + * @return result of computing <code>expr</code>
  + */
  +XForm.prototype.xpath = function(expr) {
  +    var ctx = new 
Packages.org.apache.commons.jxpath.JXPathContext.newContext(this.form.getModel());
  +    return ctx.getValue(expr);
  +}
  +
  +XForm.prototype._sendView = function(uri, lastCont, timeToLive) {
  +  var k = new Continuation();
  +  var kont = new WebContinuation(cocoon, k, lastCont, timeToLive);
  +  var bizData = this.form.getModel();
  +  if (bizData == undefined) {
  +      bizData = null;
  +  }
  +  cocoon.forwardTo("cocoon://" + cocoon.environment.getURIPrefix() + uri,
  +                   bizData, kont);
  +  this.lastContinuation = kont;
  +  suicide();
  +}
  +
  +/**
  + * Sends view to presentation pipeline and waits for subsequent submission.
  + * Automatically resends view if validation fails.
  + * Creates two continuations: one immediately before the page submission
  + * and one immediately after. These are used to implement automated support
  + * for back/forward navigation in the form. When you move forward in the
  + * form the second continuation is invoked. When you move back from the
  + * following page the first continuation is invoked.
  + * @param phase view to send (and phase to validate)
  + * @param uri presentation pipeline resource identifier
  + * @param validator optional function invoked to perform validation
  + */
  +XForm.prototype.sendView = function(phase, uri, validator) {
  +    var lastCont = this.lastContinuation;
  +    this.form.clearViolations();
  +    var view = this.form.getFormView(cocoon.environment.objectModel);
  +    while (true) {
  +     var k = this.start(lastCont);
  +     if (cocoon.request == null) {
  +         // this continuation has been invalidated
  +         this.dead = true;
  +         handleInvalidContinuation();
  +         suicide();
  +     }
  +     cocoon.request.setAttribute("view", view);
  +     try {
  +         this.form.save(cocoon.environment.objectModel, "request");
  +     } catch (e if (e instanceof java.lang.IllegalStateException)) {
  +         if (cocoon.session.getAttribute(this.id) != null) {
  +             // someone else has taken my session
  +             this.dead = true;
  +             cocoon.removeSession();
  +             handleInvalidContinuation();
  +             suicide();
  +         }
  +         throw e;
  +     }
  +     this._sendView(uri, k);
  +     if (this.dead || cocoon.request == null) {
  +         // this continuation has been invalidated
  +         handleInvalidContinuation();
  +         suicide();
  +     }
  +     this.form.populate(cocoon.environment.objectModel);
  +     if (validator != undefined) {
  +         validator(this);
  +     }
  +     this.form.validate(phase);
  +     if (this.form.violationsAsSortedSet == null ||
  +         this.form.violationsAsSortedSet.size() == 0) {
  +         break;
  +     }
  +    }
  +}
  +
  +XForm.prototype._setValidator = function(schNS, schDoc) {
  +    // if validator params are not specified, then
  +    // there is no validation by default
  +    if (schNS == null || schDoc == null ) return null;
  +    var resolver = cocoon.environment;
  +    var schemaSrc = resolver.resolveURI( schDoc );
  +    try {
  +     var is = 
Packages.org.apache.cocoon.components.source.SourceUtil.getInputSource(schemaSrc);
  +     var schf = 
Packages.org.apache.cocoon.components.validation.SchemaFactory.lookup ( schNS );
  +     var sch = schf.compileSchema ( is );
  +     this.form.setValidator(sch.newValidator());
  +    } finally {
  +     resolver.release(schemaSrc);
  +    }
  +}
  +
  +/**
  + * Sends view to presentation pipeline but doesn't wait for submission
  + * @param view view to send
  + * @param uri presentation pipeline uri
  + */
  +
  +XForm.prototype.finish = function(view, uri) {
  +    try {
  +     this.form.save(cocoon.environment.objectModel, "request");
  +    } catch (e if (e instanceof java.lang.IllegalStateException)) {
  +     if (cocoon.session.getAttribute(this.id) != null) {
  +         // someone else has taken my session
  +         this.dead = true;
  +         cocoon.removeSession();
  +         handleInvalidContinuation();
  +         suicide();
  +     }
  +     throw e;
  +    }
  +    cocoon.forwardTo("cocoon://" + cocoon.environment.getURIPrefix() + uri,
  +                  this.form.getModel(), null);
  +    delete XForm.forms[this.id]; // delete myself
  +    this.dead = true;
  +    cocoon.removeSession();
  +    if (this.lastContinuation != null) {
  +     this.lastContinuation.invalidate();
  +     this.lastContinuation = null;
  +    }
  +    
  +}
  +
  +/**
  + * Entry point to a flow-based XMLForm application. Replaces the functionality
  + * of XMLForm actions.
  + * @param application Name of a JavaScript function that represents the page flow 
for a form
  + * @param id form id
  + * @param validator_ns XML namespace of validator
  + * @param validator_doc validator document
  + */
  +
  +function xmlForm(application, id, validator_ns, validator_doc) {
  +    function getCommand() {
  +     if (cocoon.request == null) {
  +         return undefined;
  +     }
  +     var enum_ = cocoon.request.parameterNames;
  +     var command = undefined;
  +     while (enum_.hasMoreElements()) {
  +         var paramName = enum_.nextElement();
  +         // search for the command
  +         if 
(paramName.startsWith(Packages.org.apache.cocoon.Constants.ACTION_PARAM_PREFIX)) {
  +             command =
  +                 
paramName.substring(Packages.org.apache.cocoon.Constants.ACTION_PARAM_PREFIX.length(), 
paramName.length());
  +             break;
  +         }
  +     }
  +     // command encodes the continuation id for "back" or "next" actions
  +     return command;
  +    }
  +    var command = getCommand();
  +    if (command != undefined) {
  +     var xform = XForm.forms[id];
  +     if (xform != undefined) {
  +         // invoke a continuation 
  +         var continuationsMgr =
  +             
cocoon.componentManager.lookup(Packages.org.apache.cocoon.components.flow.ContinuationsManager.ROLE);
  +         var wk = continuationsMgr.lookupWebContinuation(command);
  +         cocoon.componentManager.release(continuationsMgr);
  +         if (wk != null) {
  +             var jswk = wk.userObject;
  +             xform.form.clearViolations();
  +             jswk.continuation(jswk);
  +         } else {
  +             handleInvalidContinuation(command);
  +         }
  +     }
  +    } 
  +    // Just start a new instance of the application
  +    cocoon.session.removeAttribute(id);
  +    this[application](new XForm(id, validator_ns, validator_doc));
  +}
  +
  +
  +
  +
  
  
  
  1.2       +15 -0     
xml-cocoon2/src/java/org/apache/cocoon/components/flow/javascript/ScriptablePointer.java
  
  Index: ScriptablePointer.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/flow/javascript/ScriptablePointer.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ScriptablePointer.java    20 Feb 2003 18:22:43 -0000      1.1
  +++ ScriptablePointer.java    23 Feb 2003 19:20:25 -0000      1.2
  @@ -47,6 +47,7 @@
   import org.mozilla.javascript.*;
   import org.apache.commons.jxpath.ri.QName;
   import org.apache.commons.jxpath.*;
  +import org.apache.commons.jxpath.ri.model.dynamic.*;
   import org.apache.commons.jxpath.ri.model.beans.*;
   import org.apache.commons.jxpath.ri.model.*;
   import java.util.Locale;
  @@ -65,6 +66,13 @@
           node = object;
       }
   
  +    public boolean isCollection() {
  +        if (node instanceof NativeArray) {
  +         return true;
  +     }
  +     return false;
  +    }
  +
       public ScriptablePointer(QName name,
                                Scriptable object,
                                Locale locale) {
  @@ -84,6 +92,13 @@
   
       public PropertyPointer getPropertyPointer(){
           return new ScriptablePropertyPointer(this, handler);
  +    }
  +
  +    public void setValue(Object value){
  +     System.out.println("attempt to set " + getName() + " to " + value);
  +     System.out.println("node="+node + "->" 
+java.util.Arrays.asList(node.getIds()));
  +     getParent().setValue(value);
  +     //handler.setProperty(node, getName().toString(), value);
       }
   
   }
  
  
  
  1.2       +110 -15   
xml-cocoon2/src/java/org/apache/cocoon/components/flow/javascript/ScriptablePropertyPointer.java
  
  Index: ScriptablePropertyPointer.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/flow/javascript/ScriptablePropertyPointer.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ScriptablePropertyPointer.java    20 Feb 2003 18:22:43 -0000      1.1
  +++ ScriptablePropertyPointer.java    23 Feb 2003 19:20:25 -0000      1.2
  @@ -47,10 +47,11 @@
   import org.mozilla.javascript.*;
   import org.apache.commons.jxpath.ri.QName;
   import org.apache.commons.jxpath.*;
  -import org.apache.commons.jxpath.ri.model.beans.*;
  +import org.apache.commons.jxpath.ri.model.dynamic.*;
   import org.apache.commons.jxpath.ri.model.*;
  -import org.apache.commons.jxpath.util.*;
   import java.util.Locale;
  +import java.util.LinkedList;
  +import java.util.List;
   
   public class ScriptablePropertyPointer extends DynamicPropertyPointer {
   
  @@ -66,6 +67,9 @@
           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) {
  @@ -76,32 +80,123 @@
           return super.getLength();
       }
   
  -    public Object getNodeValue() {
  -        Object 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){
  -            value = handler.getProperty(getBean(), getPropertyName());
  +            handler.setProperty(getBean(), getPropertyName(), value);
           } else {
  -            value = handler.getProperty(getBean(), getPropertyName());
  -            if (value instanceof Scriptable &&
  -                ScriptableObject.hasProperty((Scriptable)value, index)) {
  -                value = ScriptableObject.getProperty((Scriptable)value, index);
  +            Object val = handler.getProperty(getBean(), getPropertyName());
  +            if (val instanceof Scriptable) {
  +                ScriptableObject.putProperty((Scriptable)val, index, value);
               } else {
  -                return super.getNodeValue();
  +             super.setValue(value);
               }
           }
  -        return value;
       }
   
  -    public void setValue(Object value){
  +    public void remove(){
           if (index == WHOLE_COLLECTION){
  -            handler.setProperty(getBean(), getPropertyName(), value);
  +            handler.setProperty(getBean(), "length", new Integer(0));
           } else {
               Object val = handler.getProperty(getBean(), getPropertyName());
               if (val instanceof Scriptable) {
  -                ScriptableObject.putProperty((Scriptable)val, index, value);
  +             try {
  +                 ScriptableObject.deleteProperty((Scriptable)val, index);
  +             } catch (Exception e) {
  +                 e.printStackTrace();
  +             }
               } else {
  -             super.setValue(value);
  +             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("[EMAIL PROTECTED] = '");
  +        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;
  +    }
  +
  +    public Object getImmediateNode() {
  +     System.out.println("get immediate node: " + getBean() + ": " + 
  +                        getPropertyName() + ": " +
  +                        index);
  +        Object value;
  +        if (index == WHOLE_COLLECTION) {
  +            value = handler.getProperty(getBean(), getPropertyName());
  +        }
  +        else {
  +            value = handler.getProperty(getBean(), getPropertyName());
  +         if (value instanceof Scriptable) {
  +             System.out.println("getting indexed property: " + 
  +                                getPropertyName() + ": " +
  +                                index);
  +             value = ScriptableObject.getProperty((Scriptable)value, index);
  +             if (value == ScriptableObject.NOT_FOUND) {
  +                 value = null;
  +             } else if (value instanceof Wrapper) {
  +                 value = ((Wrapper)value).unwrap();
  +             } 
  +            } else {
  +                return super.getImmediateNode();
               }
           }
  +        return value;
       }
  +
   }
  
  
  
  1.2       +33 -7     
xml-cocoon2/src/java/org/apache/cocoon/components/flow/javascript/ScriptablePropertyHandler.java
  
  Index: ScriptablePropertyHandler.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/flow/javascript/ScriptablePropertyHandler.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ScriptablePropertyHandler.java    20 Feb 2003 18:22:43 -0000      1.1
  +++ ScriptablePropertyHandler.java    23 Feb 2003 19:20:25 -0000      1.2
  @@ -46,25 +46,44 @@
   package org.apache.cocoon.components.flow.javascript;
   import org.apache.commons.jxpath.DynamicPropertyHandler;
   import org.mozilla.javascript.*;
  +import java.util.List;
  +import java.util.LinkedList;
   
   public class ScriptablePropertyHandler implements DynamicPropertyHandler {
   
       public Object getProperty(Object obj, String propertyName) {
           Context cx = null;
  +     System.out.println("getProperty: " + propertyName);
           try {
               cx = Context.enter();
               Scriptable s = (Scriptable)obj;
  +         System.out.println("s="+s);
               Object result = ScriptableObject.getProperty(s, propertyName);
               if (result == ScriptableObject.NOT_FOUND) {
  -                result = null;
  +             result = ScriptableObject.getProperty(s, "get" + 
propertyName.substring(0, 1).toUpperCase() + (propertyName.length() > 1 ? 
propertyName.substring(1) : ""));
  +             if (result != ScriptableObject.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;
            }
  +         System.out.println("getProperty: " + propertyName + " = " + result);
               return result;
           } finally {
  -            cx.exit();
  +            Context.exit();
           }
       }
       
  @@ -84,7 +103,7 @@
               }
               return result;
           } finally {
  -            cx.exit();
  +            Context.exit();
           }
       }
       
  @@ -93,12 +112,19 @@
           Context cx = null;
           try {
               cx = Context.enter();
  +         System.out.println("setProperty: " + propertyName + 
  +                            " = " + Context.toObject(value, (Scriptable)obj));
  +         if (!(value == null
  +               || value instanceof String 
  +               || value instanceof Number 
  +               || value instanceof Boolean)) {
  +             value = Context.toObject(value, 
  +                                      (Scriptable)obj);
  +         }
               ScriptableObject.putProperty((Scriptable)obj,
  -                                         propertyName,
  -                                         Context.toObject(value, 
  -                                                          (Scriptable)obj));
  +                                         propertyName, value);
           } finally {
  -            cx.exit();
  +            Context.exit();
           }
       }
   }
  
  
  

Reply via email to