Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / src / direct / Manager.js
1 /**
2  * @class Ext.direct.Manager
3  * <p><b><u>Overview</u></b></p>
4  *
5  * <p>Ext.Direct aims to streamline communication between the client and server
6  * by providing a single interface that reduces the amount of common code
7  * typically required to validate data and handle returned data packets
8  * (reading data, error conditions, etc).</p>
9  *
10  * <p>The Ext.direct namespace includes several classes for a closer integration
11  * with the server-side. The Ext.data namespace also includes classes for working
12  * with Ext.data.Stores which are backed by data from an Ext.Direct method.</p>
13  *
14  * <p><b><u>Specification</u></b></p>
15  *
16  * <p>For additional information consult the
17  * <a href="http://sencha.com/products/extjs/extdirect">Ext.Direct Specification</a>.</p>
18  *
19  * <p><b><u>Providers</u></b></p>
20  *
21  * <p>Ext.Direct uses a provider architecture, where one or more providers are
22  * used to transport data to and from the server. There are several providers
23  * that exist in the core at the moment:</p><div class="mdetail-params"><ul>
24  *
25  * <li>{@link Ext.direct.JsonProvider JsonProvider} for simple JSON operations</li>
26  * <li>{@link Ext.direct.PollingProvider PollingProvider} for repeated requests</li>
27  * <li>{@link Ext.direct.RemotingProvider RemotingProvider} exposes server side
28  * on the client.</li>
29  * </ul></div>
30  *
31  * <p>A provider does not need to be invoked directly, providers are added via
32  * {@link Ext.direct.Manager}.{@link Ext.direct.Manager#add add}.</p>
33  *
34  * <p><b><u>Router</u></b></p>
35  *
36  * <p>Ext.Direct utilizes a "router" on the server to direct requests from the client
37  * to the appropriate server-side method. Because the Ext.Direct API is completely
38  * platform-agnostic, you could completely swap out a Java based server solution
39  * and replace it with one that uses C# without changing the client side JavaScript
40  * at all.</p>
41  *
42  * <p><b><u>Server side events</u></b></p>
43  *
44  * <p>Custom events from the server may be handled by the client by adding
45  * listeners, for example:</p>
46  * <pre><code>
47 {"type":"event","name":"message","data":"Successfully polled at: 11:19:30 am"}
48
49 // add a handler for a 'message' event sent by the server
50 Ext.direct.Manager.on('message', function(e){
51     out.append(String.format('&lt;p>&lt;i>{0}&lt;/i>&lt;/p>', e.data));
52             out.el.scrollTo('t', 100000, true);
53 });
54  * </code></pre>
55  * @singleton
56  */
57
58 Ext.define('Ext.direct.Manager', {
59     
60     /* Begin Definitions */
61     singleton: true,
62    
63     mixins: {
64         observable: 'Ext.util.Observable'
65     },
66     
67     requires: ['Ext.util.MixedCollection'],
68     
69     statics: {
70         exceptions: {
71             TRANSPORT: 'xhr',
72             PARSE: 'parse',
73             LOGIN: 'login',
74             SERVER: 'exception'
75         }
76     },
77     
78     /* End Definitions */
79    
80     constructor: function(){
81         var me = this;
82        
83         me.addEvents(
84             /**
85              * @event event
86              * Fires after an event.
87              * @param {event} e The Ext.direct.Event type that occurred.
88              * @param {Ext.direct.Provider} provider The {@link Ext.direct.Provider Provider}.
89              */
90             'event',
91             /**
92              * @event exception
93              * Fires after an event exception.
94              * @param {event} e The Ext.direct.Event type that occurred.
95              */
96             'exception'
97         );
98         me.transactions = Ext.create('Ext.util.MixedCollection');
99         me.providers = Ext.create('Ext.util.MixedCollection');
100         
101         me.mixins.observable.constructor.call(me);
102     },
103     
104     /**
105      * Adds an Ext.Direct Provider and creates the proxy or stub methods to execute server-side methods.
106      * If the provider is not already connected, it will auto-connect.
107      * <pre><code>
108 var pollProv = new Ext.direct.PollingProvider({
109     url: 'php/poll2.php'
110 });
111
112 Ext.direct.Manager.addProvider({
113     "type":"remoting",       // create a {@link Ext.direct.RemotingProvider}
114     "url":"php\/router.php", // url to connect to the Ext.Direct server-side router.
115     "actions":{              // each property within the actions object represents a Class
116         "TestAction":[       // array of methods within each server side Class
117         {
118             "name":"doEcho", // name of method
119             "len":1
120         },{
121             "name":"multiply",
122             "len":1
123         },{
124             "name":"doForm",
125             "formHandler":true, // handle form on server with Ext.Direct.Transaction
126             "len":1
127         }]
128     },
129     "namespace":"myApplication",// namespace to create the Remoting Provider in
130 },{
131     type: 'polling', // create a {@link Ext.direct.PollingProvider}
132     url:  'php/poll.php'
133 }, pollProv); // reference to previously created instance
134      * </code></pre>
135      * @param {Object/Array} provider Accepts either an Array of Provider descriptions (an instance
136      * or config object for a Provider) or any number of Provider descriptions as arguments.  Each
137      * Provider description instructs Ext.Direct how to create client-side stub methods.
138      */
139     addProvider : function(provider){
140         var me = this,
141             args = arguments,
142             i = 0,
143             len;
144             
145         if (args.length > 1) {
146             for (len = args.length; i < len; ++i) {
147                 me.addProvider(args[i]);
148             }
149             return;
150         }
151
152         // if provider has not already been instantiated
153         if (!provider.isProvider) {
154             provider = Ext.create('direct.' + provider.type + 'provider', provider);
155         }
156         me.providers.add(provider);
157         provider.on('data', me.onProviderData, me);
158
159
160         if (!provider.isConnected()) {
161             provider.connect();
162         }
163
164         return provider;
165     },
166     
167     /**
168      * Retrieve a {@link Ext.direct.Provider provider} by the
169      * <b><tt>{@link Ext.direct.Provider#id id}</tt></b> specified when the provider is
170      * {@link #addProvider added}.
171      * @param {String/Ext.data.Provider} id The id of the provider, or the provider instance.
172      */
173     getProvider : function(id){
174         return id.isProvider ? id : this.providers.get(id);
175     },
176     
177     /**
178      * Removes the provider.
179      * @param {String/Ext.direct.Provider} provider The provider instance or the id of the provider.
180      * @return {Ext.direct.Provider} The provider, null if not found.
181      */
182     removeProvider : function(provider){
183         var me = this,
184             providers = me.providers,
185             provider = provider.isProvider ? provider : providers.get(provider);
186             
187         if (provider) {
188             provider.un('data', me.onProviderData, me);
189             providers.remove(provider);
190             return provider;
191         }
192         return null;
193     },
194     
195     /**
196      * Add a transaction to the manager.
197      * @private
198      * @param {Ext.direct.Transaction} transaction The transaction to add
199      * @return {Ext.direct.Transaction} transaction
200      */
201     addTransaction: function(transaction){
202         this.transactions.add(transaction);
203         return transaction;
204     },
205
206     /**
207      * Remove a transaction from the manager.
208      * @private
209      * @param {String/Ext.direct.Transaction} transaction The transaction/id of transaction to remove
210      * @return {Ext.direct.Transaction} transaction
211      */
212     removeTransaction: function(transaction){
213         transaction = this.getTransaction(transaction);
214         this.transactions.remove(transaction);
215         return transaction;
216     },
217
218     /**
219      * Gets a transaction
220      * @private
221      * @param {String/Ext.direct.Transaction} transaction The transaction/id of transaction to get
222      * @return {Ext.direct.Transaction}
223      */
224     getTransaction: function(transaction){
225         return transaction.isTransaction ? transaction : this.transactions.get(transaction);
226     },
227     
228     onProviderData : function(provider, event){
229         var me = this,
230             i = 0,
231             len;
232             
233         if (Ext.isArray(event)) {
234             for (len = event.length; i < len; ++i) {
235                 me.onProviderData(provider, event[i]);
236             }
237             return;
238         }
239         if (event.name && event.name != 'event' && event.name != 'exception') {
240             me.fireEvent(event.name, event);
241         } else if (event.type == 'exception') {
242             me.fireEvent('exception', event);
243         }
244         me.fireEvent('event', event, provider);
245     }
246 }, function(){
247     // Backwards compatibility
248     Ext.Direct = Ext.direct.Manager;
249 });