update Directory, Fountain, JSReflection, SOAP, XMLRPC to use baskets and new JS...
authorcrawshaw <crawshaw@ibex.org>
Thu, 6 Jan 2005 19:56:46 +0000 (19:56 +0000)
committercrawshaw <crawshaw@ibex.org>
Thu, 6 Jan 2005 19:56:46 +0000 (19:56 +0000)
darcs-hash:20050106195646-2eb37-c91d643766e08eb395699a04a6433c7e5e3daab0.gz

src/org/ibex/js/Directory.java
src/org/ibex/js/Fountain.java
src/org/ibex/js/JSReflection.java
src/org/ibex/js/SOAP.java
src/org/ibex/js/XMLRPC.java

index 07ef38a..0c0fc73 100644 (file)
@@ -5,7 +5,6 @@
 package org.ibex.js; 
 
 import org.ibex.util.*; 
-import java.util.*;
 import java.io.*;
 
 // FEATURE: support for move
@@ -38,7 +37,7 @@ import java.io.*;
  *  argument that points to a non-directory File, this class will
  *  delete that file and create a directory!
  */
-public class Directory extends JS {
+public class Directory extends JS.Immutable {
 
     File f;
 
@@ -66,21 +65,21 @@ public class Directory extends JS {
     public void put(JS key0, JS val) throws JSExn {
         try {
             if (key0 == null) return;
-            String key = toString(key0);
-            File f2 = new File(f.getAbsolutePath() + File.separatorChar + FileNameEncoder.encode(key));
+            String key = Script.toString(key0);
+            File f2 = new File(f.getAbsolutePath() + File.separatorChar + Encode.toFilename(key));
             destroy(f2);
             if (val == null) return;
             if (val instanceof JSPrimitive) {
                 OutputStream out = new FileOutputStream(f2);
                 Writer w = new OutputStreamWriter(out);
-                w.write(toString(val));
+                w.write(Script.toString(val));
                 w.flush();
                 out.close();
             } else {
                 Directory d2 = new Directory(f2);
                 JS.Enumeration e = val.keys();
-                while(e.hasMoreElements()) {
-                    JS k = e.nextElement();
+                while(e.hasNext()) {
+                    JS k = e.next();
                     JS v = val.get(k);
                     d2.put(k, v);
                 }
@@ -93,8 +92,8 @@ public class Directory extends JS {
     public JS get(JS key0) throws JSExn {
         try {
             if (key0 == null) return null;
-            String key = toString(key0);
-            File f2 = new File(f.getAbsolutePath() + File.separatorChar + FileNameEncoder.encode(key));
+            String key = Script.toString(key0);
+            File f2 = new File(f.getAbsolutePath() + File.separatorChar + Encode.toFilename(key));
             if (!f2.exists()) return null;
             if (f2.isDirectory()) return new Directory(f2);
             char[] chars = new char[((int)f2.length()) * 2];
@@ -110,12 +109,12 @@ public class Directory extends JS {
         }
     }
 
-    public Enumeration keys() {
+    public JS.Enumeration keys() {
         final String[] elements = f.list();
-        return new Enumeration(null) {
+        return new JS.Enumeration(null) {
                 int i = 0;
-                public boolean _hasMoreElements() { return i < elements.length; }
-                public JS _nextElement() { return Script.S(FileNameEncoder.decode(elements[i++])); }
+                public boolean _hasNext() { return i < elements.length; }
+                public JS _next() { return Script.S(Encode.fromFilename(elements[i++])); }
             };
     }
 }
index c015f4c..f1bf14b 100644 (file)
@@ -15,7 +15,7 @@ import org.ibex.net.*;
  *   be totally independent of the others (ie separate stream position
  *   and state) although they draw from the same data source.
  */
-public abstract class Fountain extends JS.O implements JS.Cloneable {
+public abstract class Fountain extends JS.Immutable implements JS.Cloneable {
 
     // Public Interface //////////////////////////////////////////////////////////////////////////////
 
@@ -23,8 +23,7 @@ public abstract class Fountain extends JS.O implements JS.Cloneable {
     public static class NotCacheableException extends Exception { }
 
     // streams are "sealed" by default to prevent accidental object leakage
-    public void put(Object key, Object val) { }
-    private Cache getCache = new Cache(100);
+    private Cache getCache = new Cache(100, true);
     protected Object _get(Object key) { return null; }
     public final Object get(Object key) {
         Object ret = getCache.get(key);
@@ -43,7 +42,7 @@ public abstract class Fountain extends JS.O implements JS.Cloneable {
         //public String toString() { return "Stream.HTTP:" + url; }
         public HTTP(String url) { while (url.endsWith("/")) url = url.substring(0, url.length() - 1); this.url = url; }
         public Object _get(Object key) { return new HTTP(url + "/" + (String)key); }
-        public String getCacheKey(Vec path) throws NotCacheableException { return url; }
+        public String getCacheKey(Basket.List path) throws NotCacheableException { return url; }
         public InputStream getInputStream() throws IOException { return new org.ibex.net.HTTP(url).GET(null, null); }
     }
 
index 4d6ec04..d6ecd75 100644 (file)
@@ -4,13 +4,11 @@
 
 package org.ibex.js; 
 
-import org.ibex.util.*; 
-import java.io.*;
-import java.util.*;
 import java.lang.reflect.*;
 
 /** Automatic JS-ification via Reflection (not for use in the core) */
-public class JSReflection extends JS {
+public class JSReflection extends JS.Immutable {
+    private static final JS.Method METHOD = new JS.Method();
 
     public static JS wrap(Object o) throws JSExn {
         if (o == null) return null;
@@ -24,28 +22,25 @@ public class JSReflection extends JS {
         throw new JSExn("Reflection object tried to return a " + o.getClass().getName());
     }
 
-    public static class Array extends JS {
+    public static class Array extends JS.Immutable {
         final Object[] arr;
         public Array(Object[] arr) { this.arr = arr; }
         // FEATURE: Add a JSCounterEnumeration
         public Enumeration keys() throws JSExn {
             return new Enumeration(null) {
                 private int n = 0;
-                public boolean _hasMoreElements() { return n < arr.length; }
-                public JS _nextElement() {
-                    return n >= arr.length ? null : Script.N(n++);
-                }
+                public boolean _hasNext() { return n < arr.length; }
+                public JS _next() { return Script.N(n++); }
             };
         }
-        public JS get(JS key) throws JSExn { return wrap(arr[toInt(key)]); }
-        public void put(JS key, JS val) throws JSExn { throw new JSExn("can't write to org.ibex.js.Reflection.Array's"); }
+        public JS get(JS key) throws JSExn { return wrap(arr[Script.toInt(key)]); }
     }
 
     // FIXME public static class Hash { }
     // FIXME public Enumeration keys() throws JSExn {  }
 
     public JS get(JS key) throws JSExn {
-        String k = toString(key);
+        String k = Script.toString(key);
         try {
             Field f = this.getClass().getField(k);
             return wrap(f.get(this));
@@ -54,7 +49,7 @@ public class JSReflection extends JS {
         } catch (SecurityException nfe) { }
 
         try {
-            Method[] methods = this.getClass().getMethods();
+            java.lang.reflect.Method[] methods = this.getClass().getMethods();
             for(int i=0; i<methods.length; i++) if (methods[i].getName().equals(k)) return METHOD;
         } catch (SecurityException nfe) { }
         return null;
@@ -64,20 +59,14 @@ public class JSReflection extends JS {
         throw new JSExn("put() not supported yet");
     }
 
-    public JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
-        String k = toString(method);
+    public JS call(JS method, JS[] args) throws JSExn {
+        String k = Script.toString(method);
         try {
-            Method[] methods = this.getClass().getMethods();
+            java.lang.reflect.Method[] methods = this.getClass().getMethods();
             for(int j=0; j<methods.length; j++) {
-                if (methods[j].getName().equals(k) && methods[j].getParameterTypes().length == nargs) {
-                    Object[] args = new Object[nargs];
-                    for(int i = 0; i<args.length; i++) {
-                        if (i==0) args[i] = a0;
-                        else if (i==1) args[i] = a1;
-                        else if (i==2) args[i] = a2;
-                        else args[i] = rest[i-3];
-                    }
-                    return wrap(methods[j].invoke(this, args));
+                if (methods[j].getName().equals(k) &&
+                    methods[j].getParameterTypes().length == args.length) {
+                    return wrap(methods[j].invoke(this, (Object[])args));
                 }
             }
         } catch (IllegalAccessException nfe) {
index 632a0a6..d1a2d61 100644 (file)
@@ -5,10 +5,7 @@
 package org.ibex.js;
 
 import java.io.*;
-import java.util.*;
-import org.ibex.net.*;
 import org.ibex.util.*;
-import org.ibex.crypto.*;
 
 /**
  *  A partial RPC-style SOAP 1.1 client. Implemented from the SOAP 1.1
@@ -44,33 +41,33 @@ public class SOAP extends XMLRPC {
         if (name.equals("SOAP-ENV:Fault")) fault = true;
  
         // add a generic struct; we'll change this if our type is different
-        objects.addElement(new JS.O());
+        objects.push(new JS.Obj());
 
         for(int i=0; i<keys.length; i++) {
             String key = keys[i];
             String value = vals[i].toString();
             if (key.endsWith("ype")) {
                 if (value.endsWith("boolean")) {
-                    objects.removeElementAt(objects.size() - 1);
-                    objects.addElement(Script.B(true));
+                    objects.pop();
+                    objects.push(Script.B(true));
                 } else if (value.endsWith("int")) {
-                    objects.removeElementAt(objects.size() - 1);
-                    objects.addElement(Script.N(0));
+                    objects.pop();
+                    objects.push(Script.N(0));
                 } else if (value.endsWith("double")) {
-                    objects.removeElementAt(objects.size() - 1);
-                    objects.addElement(Script.N(0.0));
+                    objects.pop();
+                    objects.push(Script.N(0.0));
                 } else if (value.endsWith("string")) {
-                    objects.removeElementAt(objects.size() - 1);
-                    objects.addElement(Script.S(""));
+                    objects.pop();
+                    objects.push(Script.S(""));
                 } else if (value.endsWith("base64")) {
-                    objects.removeElementAt(objects.size() - 1);
-                    objects.addElement(new byte[] { });
+                    objects.pop();
+                    objects.push(new byte[] { });
                 } else if (value.endsWith("null")) {
-                    objects.removeElementAt(objects.size() - 1);
-                    objects.addElement(null);
+                    objects.pop();
+                    objects.push(null);
                 } else if (value.endsWith("arrayType") || value.endsWith("JSArray") || key.endsWith("arrayType")) {
-                    objects.removeElementAt(objects.size() - 1);
-                    objects.addElement(new JSArray());
+                    objects.pop();
+                    objects.push(new JSArray());
                 }
             }
         }
@@ -84,54 +81,54 @@ public class SOAP extends XMLRPC {
         if (content.size() > 0 && content.toString().trim().length() > 0) {
 
             // remove ourselves
-            Object me = objects.elementAt(objects.size() - 1);
+            Object me = objects.get(objects.size() - 1);
 
             if (fault || me instanceof String) {
-                objects.removeElementAt(objects.size() - 1);
-                objects.addElement(new String(content.getBuf(), 0, content.size()).intern());
+                objects.pop();
+                objects.push(new String(content.buf, 0, content.size()).intern());
                 content.reset();
 
             } else if (me instanceof byte[]) {
-                objects.removeElementAt(objects.size() - 1);
-                objects.addElement(new Fountain.ByteArray(Base64.decode(new String(content.getBuf(), 0, content.size())), null));
+                objects.pop();
+                objects.push(new Fountain.ByteArray(Encode.fromBase64(new String(content.buf, 0, content.size())), null));
                 content.reset();                
 
             } else if (me instanceof Integer) {
-                objects.removeElementAt(objects.size() - 1);
-                objects.addElement(new Integer(new String(content.getBuf(), 0, content.size())));
+                objects.pop();
+                objects.push(new Integer(new String(content.buf, 0, content.size())));
                 content.reset();
                 
             } else if (me instanceof Boolean) {
-                objects.removeElementAt(objects.size() - 1);
-                String s = new String(content.getBuf(), 0, content.size()).trim();
-                if (s.equals("1") || s.equals("true")) objects.addElement(Boolean.TRUE);
-                else objects.addElement(Boolean.FALSE);
+                objects.pop();
+                String s = new String(content.buf, 0, content.size()).trim();
+                if (s.equals("1") || s.equals("true")) objects.push(Boolean.TRUE);
+                else objects.push(Boolean.FALSE);
                 content.reset();
                 
             } else if (me instanceof Double) {
-                objects.removeElementAt(objects.size() - 1);
-                objects.addElement(new Double(new String(content.getBuf(), 0, content.size())));
+                objects.pop();
+                objects.push(new Double(new String(content.buf, 0, content.size())));
                 content.reset();
                 
             } else {
                 // okay, we got PCDATA for what is supposedly a
                 // struct... somebody's not adding their type info...
-                String s = new String(content.getBuf(), 0, content.size()).trim();
+                String s = new String(content.buf, 0, content.size()).trim();
                 boolean hasdot = false;
                 for(int i=0; i<s.length(); i++) {
                     if (s.charAt(i) == '.') hasdot = true;
                     if (!Character.isDigit(s.charAt(i))) {
-                        objects.removeElementAt(objects.size() - 1);
-                        objects.addElement(s);
+                        objects.pop();
+                        objects.push(s);
                         return;
                     }
                 }
                 if (hasdot) {
-                    objects.removeElementAt(objects.size() - 1);
-                    objects.addElement(new Double(s));
+                    objects.pop();
+                    objects.push(new Double(s));
                 } else {
-                    objects.removeElementAt(objects.size() - 1);
-                    objects.addElement(new Integer(s));
+                    objects.pop();
+                    objects.push(new Integer(s));
                 }
                 content.reset();
             }
@@ -139,21 +136,21 @@ public class SOAP extends XMLRPC {
         }
         
         // remove ourselves
-        JS me = (JS)objects.elementAt(objects.size() - 1);
+        JS me = (JS)objects.get(objects.size() - 1);
 
         // find our parent
-        JS parent = objects.size() > 1 ? (JS)objects.elementAt(objects.size() - 2) : (JS)null;
+        JS parent = objects.size() > 1 ? (JS)objects.get(objects.size() - 2) : (JS)null;
 
         // we want to fold stuff back into the fault object
         if (objects.size() < 2) return;
 
         // our parent "should" be an aggregate type -- add ourselves to it.
         if (parent != null && parent instanceof JSArray) {
-            objects.removeElementAt(objects.size() - 1);
-            ((JSArray)parent).addElement(me);
+            objects.pop();
+            ((JSArray)parent).push(me);
 
         } else if (parent != null && parent instanceof JS) {
-            objects.removeElementAt(objects.size() - 1);
+            objects.pop();
             try {
                 ((JS)parent).put(Script.S(name), me);
             } catch (JSExn e) {
@@ -196,7 +193,7 @@ public class SOAP extends XMLRPC {
                         System.arraycopy(buf, 0, writebuf, 0, numread);
                     }
                     sb.append("              ");
-                    sb.append(new String(Base64.encode(writebuf)));
+                    sb.append(new String(Encode.toBase64(writebuf)));
                     sb.append("\r\n");
                 }
                 sb.append(((Boolean)o).booleanValue() ? "1" : "0");
@@ -228,16 +225,16 @@ public class SOAP extends XMLRPC {
 
         } else if (o instanceof JSArray) {
             JSArray a = (JSArray)o;
-            sb.append("                <" + name + " SOAP-ENC:arrayType=\"xsd:ur-type[" + a.length() + "]\">");
-            for(int i=0; i<a.length(); i++) appendObject("item", a.elementAt(i), sb);
+            sb.append("                <" + name + " SOAP-ENC:arrayType=\"xsd:ur-type[" + a.size() + "]\">");
+            for(int i=0; i<a.size(); i++) appendObject("item", a.get(i), sb);
             sb.append("</" + name + ">\r\n");
 
         } else if (o instanceof JS) {
             JS j = (JS)o;
             sb.append("                <" + name + ">");
-            Enumeration e = j.keys();
-            while(e.hasMoreElements()) {
-                Object key = e.nextElement();
+            JS.Enumeration e = j.keys();
+            while(e.hasNext()) {
+                Object key = e.next();
                 appendObject((String)key, j.get((JS)key), sb);
             }
             sb.append("</" + name + ">\r\n");
@@ -260,11 +257,11 @@ public class SOAP extends XMLRPC {
         content.append(method);
         content.append(nameSpace != null ? " xmlns=\"" + nameSpace + "\"" : "");
         content.append(">\r\n");
-        if (args.length() > 0) {
-            Enumeration e = ((JS)args.elementAt(0)).keys();
-            while(e.hasMoreElements()) {
-                JS key = (JS)e.nextElement();
-                appendObject(((JSString)key).coerceToString(), ((JS)args.elementAt(0)).get(key), content);
+        if (args.size() > 0) {
+            JS.Enumeration e = ((JS)args.get(0)).keys();
+            while(e.hasNext()) {
+                JS key = (JS)e.next();
+                appendObject(((JSString)key).coerceToString(), ((JS)args.get(0)).get(key), content);
             }
         }
         content.append("    </" + method + "></SOAP-ENV:Body></SOAP-ENV:Envelope>\r\n");
index a3dc331..44324e0 100644 (file)
@@ -5,10 +5,8 @@
 package org.ibex.js;
 
 import java.io.*;
-import java.util.*;
 import org.ibex.net.*;
 import org.ibex.util.*;
-import org.ibex.crypto.*;
 
 /**
  *  An XML-RPC client implemented as a JavaScript Host Object. See the
@@ -32,7 +30,7 @@ import org.ibex.crypto.*;
  *         convert.
  *  </ol>
  */
-public class XMLRPC extends JS {
+public class XMLRPC extends JS.Immutable {
 
     public XMLRPC(String url, String method) {
         this.http = url.startsWith("stdio:") ? HTTP.stdio : new HTTP(url);
@@ -46,11 +44,15 @@ public class XMLRPC extends JS {
 
 
     /** this holds character content as we read it in -- since there is only one per instance, we don't support mixed content */
-    protected AccessibleCharArrayWriter content = new AccessibleCharArrayWriter(100);
+    protected PublicCharArrayWriter content = new PublicCharArrayWriter(100);
+    public static final class PublicCharArrayWriter extends CharArrayWriter {
+        public PublicCharArrayWriter(int i) { super(i); }
+        public char[] buf;
+    };
     protected String url = null;         ///< the url to connect to
     protected String method = null;      ///< the method name to invoke on the remove server
     protected HTTP http = null;          ///< the HTTP connection to use
-    private Hash tracker;                ///< used to detect multi-ref data
+    private Basket.Map tracker;          ///< used to detect multi-ref data
     protected boolean fault = false;     ///< True iff the return value is a fault (and should be thrown as an exception)
 
 
@@ -75,39 +77,40 @@ public class XMLRPC extends JS {
      *  popped off the stack and inserted into the struct (third
      *  element on stack).
      */
-    protected Vec objects = null;
+    protected Basket.Array objects = null;
+    private void setLast(Object o) { objects.set(objects.size() - 1, o); }
 
 
     // Recieve ////////////////////////////////////////////////////////////////
 
     private class Helper extends XML {
-        public Helper() { super(BUFFER_SIZE); }
+        public Helper() { super(BUFFER_SIZE, true); }
 
-        public void startElement(XML.Element c) {
+        public void startElement(Tree.Element c) {
             content.reset();
             //#switch(c.getLocalName())
             case "fault": fault = true;
-            case "struct": objects.setElementAt(new JS.O(), objects.size() - 1);
-            case "array": objects.setElementAt(null, objects.size() - 1);
-            case "value": objects.addElement("");
+            case "struct": setLast(new JS.Obj());
+            case "array": setLast(null);
+            case "value": objects.add("");
             //#end
         }
         
-        public void endElement(XML.Element c) {
+        public void endElement(Tree.Element c) {
             //#switch(c.getLocalName())
-            case "int": objects.setElementAt(new Integer(new String(content.getBuf(), 0, content.size())), objects.size() - 1);
-            case "i4": objects.setElementAt(new Integer(new String(content.getBuf(), 0, content.size())), objects.size() - 1);
-            case "boolean": objects.setElementAt(content.getBuf()[0] == '1' ? Boolean.TRUE : Boolean.FALSE, objects.size() - 1);
-            case "string": objects.setElementAt(new String(content.getBuf(), 0, content.size()), objects.size() - 1);
-            case "double": objects.setElementAt(new Double(new String(content.getBuf(), 0, content.size())), objects.size() - 1);
+            case "int": setLast(new Integer(new String(content.buf, 0, content.size())));
+            case "i4": setLast(new Integer(new String(content.buf, 0, content.size())));
+            case "boolean": setLast(content.buf[0] == '1' ? Boolean.TRUE : Boolean.FALSE);
+            case "string": setLast(new String(content.buf, 0, content.size()));
+            case "double": setLast(new Double(new String(content.buf, 0, content.size())));
             case "base64":
-                objects.setElementAt(new Fountain.ByteArray(Base64.decode(new String(content.getBuf(), 0, content.size())),
-                                                          null), objects.size() - 1);
-            case "name": objects.addElement(new String(content.getBuf(), 0, content.size()));
-            case "value": if ("".equals(objects.lastElement()))
-                objects.setElementAt(new String(content.getBuf(), 0, content.size()), objects.size() - 1);
+                setLast(new Fountain.ByteArray(Encode.fromBase64(new String(content.buf, 0, content.size())),
+                                                          null));
+            case "name": objects.add(new String(content.buf, 0, content.size()));
+            case "value": if ("".equals(objects.peek()))
+                setLast(new String(content.buf, 0, content.size()));
             case "dateTime.iso8601":
-                String s = new String(content.getBuf(), 0, content.size());
+                String s = new String(content.buf, 0, content.size());
                 
                 // strip whitespace
                 int i=0;
@@ -125,33 +128,34 @@ public class XMLRPC extends JS {
                                                            (double)0
                                                            );
                     nd.setTime(JSDate.internalUTC(date));
-                    objects.setElementAt(nd, objects.size() - 1);
+                    setLast(nd);
                     
                 } catch (Exception e) {
                     throw new RuntimeException("ibex.net.rpc.xml.recieve.malformedDateTag" +
                                     "the server sent a <dateTime.iso8601> tag which was malformed: " + s);
                 }
             case "member":
-                JS memberValue = (JS)objects.elementAt(objects.size() - 1);
-                JS memberName = (JS)objects.elementAt(objects.size() - 2);
-                JS struct = (JS)objects.elementAt(objects.size() - 3);
+                JS memberValue = (JS)objects.get(objects.size() - 1);
+                JS memberName = (JS)objects.get(objects.size() - 2);
+                JS struct = (JS)objects.get(objects.size() - 3);
                 try {
                     struct.put(memberName, memberValue);
                 } catch (JSExn e) {
                     throw new Error("this should never happen");
                 }
-                objects.setSize(objects.size() - 2);
+                objects.pop();
+                objects.pop();
             case "data":
                 int i;
-                for(i=objects.size() - 1; objects.elementAt(i) != null; i--);
+                for(i=objects.size() - 1; objects.get(i) != null; i--);
                 JSArray arr = new JSArray();
                 try {
-                    for(int j = i + 1; j<objects.size(); j++) arr.put(Script.N(j - i - 1), (JS)objects.elementAt(j));
+                    for(int j = i + 1; j<objects.size(); j++) arr.put(Script.N(j - i - 1), (JS)objects.get(j));
                 } catch (JSExn e) {
                     throw new Error("this should never happen");
                 }
-                objects.setElementAt(arr, i);
-                objects.setSize(i + 1);
+                objects.set(i, arr);
+                objects.add(null);
             //#end            
             content.reset();
         }
@@ -178,9 +182,9 @@ public class XMLRPC extends JS {
         content.append(method);
         content.append("</methodName>\n");
         content.append("        <params>\n");
-        for(int i=0; i<args.length(); i++) {
+        for(int i=0; i < args.size(); i++) {
             content.append("            <param>\n");
-            appendObject(args.elementAt(i), content);
+            appendObject(args.get(i), content);
             content.append("            </param>\n");
         }
         content.append("        </params>\n");
@@ -224,7 +228,7 @@ public class XMLRPC extends JS {
                         System.arraycopy(buf, 0, writebuf, 0, numread);
                     }
                     sb.append("              ");
-                    sb.append(new String(Base64.encode(writebuf)));
+                    sb.append(new String(Encode.toBase64(writebuf)));
                     sb.append("\n");
                 }
                 sb.append("\n              </base64></value>\n");
@@ -278,7 +282,7 @@ public class XMLRPC extends JS {
             tracker.put(o, Script.B(true));
             sb.append("                <value><array><data>\n");
             JSArray a = (JSArray)o;
-            for(int i=0; i<a.length(); i++) appendObject(a.elementAt(i), sb);
+            for(int i=0; i < a.size(); i++) appendObject(a.get(i), sb);
             sb.append("                </data></array></value>\n");
 
         } else if (o instanceof JS) {
@@ -287,8 +291,8 @@ public class XMLRPC extends JS {
             JS j = (JS)o;
             sb.append("                <value><struct>\n");
             Enumeration e = j.keys();
-            while(e.hasMoreElements()) {
-                Object key = e.nextElement();
+            while (e.hasNext()) {
+                Object key = e.next();
                 sb.append("                <member><name>" + key + "</name>\n");
                 appendObject(j.get((JS)key), sb);
                 sb.append("                </member>\n");
@@ -323,33 +327,32 @@ public class XMLRPC extends JS {
     */
 
     // FIXME need to reenable backgrounding logic
-    final Object call(final JS.UnpauseCallback callback, final JSArray args) {
+    final Object call(final Pausable callback, final JSArray args) {
         try {
             if (Log.rpc) Log.info(this, "call to " + url + " : " + method);
-            if (tracker == null) tracker = new Hash();
-            if (objects == null) objects = new Vec();
+            if (tracker == null) tracker = new Basket.HashMap();
+            if (objects == null) objects = new Basket.Array();
             String request = buildRequest(args);
             if (Log.rpc) Log.info(this, "send:\n" + request);
             InputStream is = http.POST("text/xml", request, null, null);
             BufferedReader br = new BufferedReader(new InputStreamReader(is));
             try {
                 new Helper().parse(br);
-               if (fault) throw new JSExn((JS)objects.elementAt(0));
-                final JS result = (objects.size() == 0 ? (JS)null : ((JS)objects.elementAt(0)));
-                return (new Task() { public void perform() throws JSExn { callback.unpause(result); }});
+                if (fault) throw new JSExn((JS)objects.get(0));
+                final JS result = (objects.size() == 0 ? (JS)null : ((JS)objects.get(0)));
+                return (new Callable() { public Object run(Object o) throws Exception {
+                    return callback.run(result); }});
             } finally {
                 tracker.clear();
-                objects.setSize(0);
+                objects.clear();
             }
         } catch (final JSExn e) {
-            final Exception e2 = e;
-            return (new Task() { public void perform() throws JSExn { callback.unpause((JSExn)e2); }});
+            return (new Callable() { public Object run(Object o) throws Exception {
+                return callback.run(e); }});
         } catch (final IOException e) {
-            final Exception e2 = e;
-            return (new Task() { public void perform() throws JSExn { callback.unpause(new JSExn(e2.getMessage())); }});
-        } catch (final XML.Exn e) {
-            final Exception e2 = e;
-            return (new Task() { public void perform() throws JSExn { callback.unpause(new JSExn(e2.getMessage())); }});
+            final String msg = e.getMessage();
+            return (new Callable() { public Object run(Object o) throws Exception {
+                return callback.run(new JSExn(msg)); }});
         }
     }
 }