001 
002 /*
003  *  JScripter Standard 1.0 - To Script In Java
004  *  Copyright (C) 2008-2011  J.J.Liu<jianjunliu@126.com> <http://www.jscripter.org>
005  *  
006  *  This program is free software: you can redistribute it and/or modify
007  *  it under the terms of the GNU Affero General Public License as published by
008  *  the Free Software Foundation, either version 3 of the License, or
009  *  (at your option) any later version.
010  *  
011  *  This program is distributed in the hope that it will be useful,
012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014  *  GNU Affero General Public License for more details.
015  *  
016  *  You should have received a copy of the GNU Affero General Public License
017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
018  */
019 
020 package jsx.http.rpc;
021 
022 import js.ArrayLike;
023 import js.Index;
024 import js.ObjectLike;
025 import js.user.JsDocument;
026 import js.user.JsXMLHttpRequest;
027 import jsx.Code;
028 import jsx.http.Ajax;
029 import jsx.http.Http;
030 import jsx.http.event.HTTPLoaded;
031 import jsx.http.event.OnHTTPLoaded;
032 
033 /**
034  * <p>An abstract base class for XMLHTTP remote objects.</p>
035  * 
036  * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
037  */
038 public abstract class XMLHttpRemote extends HttpRemote
039 {
040     /**
041      * <p>A typical constructor which simply invokes the typical constructor of the 
042      * superclass passing the initializing object as argument.</p>
043      * @param ini An object of {@link ObjectLike} for configuration. 
044      * @since 1.0
045      */
046     protected XMLHttpRemote(ObjectLike ini) {
047         super(ini);
048     }
049 
050     /**
051      * <p>A typical constructor which simply invokes the typical constructor of the 
052      * superclass passing the {@link XMLHttpRemote} object as argument.</p>
053      * @param o An object of {@link XMLHttpRemote}. 
054      * @since 1.0
055      */
056     protected XMLHttpRemote(XMLHttpRemote o) {
057         super(o);
058     }
059 
060     /**
061      * <p>A typical constructor for creating fields of this type.</p>
062      * @param base The base object of the field being created. 
063      * @param idx The {@link js.Index} in the base object for the field being created. 
064      * @since 1.0
065      */
066     protected XMLHttpRemote(XMLHttpRemote base, Index<? extends XMLHttpRemote> idx) {
067         super(base.get(idx));
068     }
069 
070     /**
071      * <p>Calls a remote method with the current instance.</p>
072      * @param url A HTTP resource locator of the remote method. 
073      * @param args An array of arguments for the invocation. 
074      * @return The value returned from the invocation. The value can only be a number, 
075      * string or {@link ObjectLike}. 
076      * @since 1.0
077      */
078     @Override
079     protected final Object call(String url, ArrayLike<?> args) {
080         JsXMLHttpRequest http = Http.create();
081         Http.open(http, "POST", url, false);
082         Http.setRequestHeader(
083                 http,
084                 Code.hyphen("Content", "type"),
085                 Code.sub("text", "xml")
086         );
087         XMLHttpClient c = new XMLHttpClient();
088         Http.send(http, c.body(this, args));
089         JsDocument response = Http.responseXML(http);
090         c.updateContext(response);
091         Object ret = c.getReturn(response);
092         c.release();
093         return ret;
094     }
095 
096     /**
097      * <p>Client-side XML & HTTP serialization contexts for asynchronous connections.</p>
098      * <p>A {@link Caller} is also an event listener that handles {@link HTTPLoaded} events 
099      * fired from its underlying {@link Ajax} connection.</p>
100      * 
101      * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
102      */
103     public abstract class Caller extends XMLHttpClient implements OnHTTPLoaded
104     {
105         private final String url;
106         private final Ajax ajax;
107 
108         /**
109          * <p>A typical constructor which invokes the typical constructor of the 
110          * superclass without arguments, creates an {@link Ajax} connection and then listens
111          * the connection for {@link HTTPLoaded} events.</p>
112          * @param url A HTTP resource locator of the connection. 
113          * @since 1.0
114          */
115         protected Caller(String url) {
116             super();
117             this.url = url;
118             ajax = new Ajax();
119             ajax.addListener(HTTPLoaded.class, this);
120         }
121 
122         /**
123          * <p>Calls back with a return value.</p>
124          * <p>The subclasses implements this method to get return value from the asynchronous
125          * call connection.</p>
126          * @param ret The return value.
127          * @since 1.0
128          */
129         protected abstract void callback(Object ret);
130 
131         /**
132          * <p>Initiates an asynchronous call through the connection with the specified arguments.</p>
133          * @param args An array of arguments.
134          * @since 1.0
135          */
136         public final void call(final ArrayLike<?> args) {
137             release();
138             ajax.post(url, body(XMLHttpRemote.this, args));
139         }
140 
141         /**
142          * <p>Performs an action on the dispatched event.</p>
143          * <p>This method retrieves the XML response, updates the calling context and 
144          * calls {@link #callback(Object)} with the return value.</p>
145          * @param evt The event dispatched to this listener.
146          * @since 1.0
147          */
148         public void onEvent(HTTPLoaded evt) {
149             JsDocument response = Http.responseXML(ajax.http());
150             updateContext(response);
151             callback(getReturn(response));
152             release();
153         }
154     }
155 }