1//////////////////////////////////////////////////////////////////////////////// 2// 3// ADOBE SYSTEMS INCORPORATED 4// Copyright 2005-2007 Adobe Systems Incorporated 5// All Rights Reserved. 6// 7// NOTICE: Adobe permits you to use, modify, and distribute this file 8// in accordance with the terms of the license agreement accompanying it. 9// 10//////////////////////////////////////////////////////////////////////////////// 11 12package mx.rpc.http 13{ 14 15import mx.core.mx_internal; 16import mx.logging.ILogger; 17import mx.logging.Log; 18import mx.messaging.ChannelSet; 19import mx.messaging.channels.DirectHTTPChannel; 20import mx.messaging.config.LoaderConfig; 21import mx.messaging.messages.HTTPRequestMessage; 22import mx.resources.IResourceManager; 23import mx.resources.ResourceManager; 24import mx.rpc.AbstractService; 25import mx.rpc.events.FaultEvent; 26import mx.rpc.mxml.Concurrency; 27import mx.utils.URLUtil; 28 29use namespace mx_internal; 30 31/** 32 * Dispatched when an HTTPMultiService call returns successfully. 33 * @eventType mx.rpc.events.ResultEvent.RESULT 34 * 35 * @langversion 3.0 36 * @playerversion Flash 9 37 * @playerversion AIR 1.1 38 * @productversion Flex 3 39 */ 40[Event(name="result", type="mx.rpc.events.ResultEvent")] 41 42/** 43 * Dispatched when an HTTPMultiService call fails. 44 * @eventType mx.rpc.events.FaultEvent.FAULT 45 * 46 * @langversion 3.0 47 * @playerversion Flash 9 48 * @playerversion AIR 1.1 49 * @productversion Flex 3 50 */ 51[Event(name="fault", type="mx.rpc.events.FaultEvent")] 52 53/** 54 * The invoke event is fired when an HTTPMultiService call is invoked so long as 55 * an Error is not thrown before the Channel attempts to send the message. 56 * @eventType mx.rpc.events.InvokeEvent.INVOKE 57 * 58 * @langversion 3.0 59 * @playerversion Flash 9 60 * @playerversion AIR 1.1 61 * @productversion Flex 3 62 */ 63[Event(name="invoke", type="mx.rpc.events.InvokeEvent")] 64 65[ResourceBundle("rpc")] 66 67[DefaultProperty("operationList")] 68/** 69 * You use the <code><mx:HTTPMultiService></code> tag to represent a 70 * collection of http operations. Each one has a URL, method, parameters and 71 * return type. 72 * 73 * <p>You can set attributes such as the URL and method on the 74 * HTTPMultiService tag to act as defaults for values set on each individual 75 * operation tag. The URL of the HTTPMultiService serves as the base url (meaning the prefix) 76 * for any relative urls set on the http operation tags. 77 * Each http operation has a <code>send()</code> method, which makes an HTTP request to the 78 * specified URL, and an HTTP response is returned. </p> 79 * 80 * <p>You can pass parameters to the specified URL which are used to put data into the HTTP request. 81 * The contentType property specifies a mime-type which is used to determine the over-the-wire 82 * data format (such as HTTP form encoding or XML). </p> 83 * 84 * <p>You can also use a serialization filter to 85 * implement a custom resultFormat such as JSON. 86 * When you do not go through the server-based 87 * proxy service, you can use only HTTP GET or POST methods. However, when you set 88 * the <code>useProxy </code> property to true and you use the server-based proxy service, you 89 * can also use the HTTP HEAD, OPTIONS, TRACE, and DELETE methods.</p> 90 * 91 * <p><b>Note:</b> Unlike the HTTPService class, the HTTPMultiService class does not 92 * define a <code>request</code> property.</p> 93 * 94 * <p><b>Note:</b> Due to a software limitation, like HTTPService, the HTTPMultiService does 95 * not generate user-friendly error messages when using GET and not using a proxy.</p> 96 * 97 * @langversion 3.0 98 * @playerversion Flash 9 99 * @playerversion AIR 1.1 100 * @productversion Flex 3 101 * 102 * @see mx.rpc.http.HTTPService 103 */ 104public dynamic class HTTPMultiService extends AbstractService 105{ 106 //-------------------------------------------------------------------------- 107 // 108 // Constructor 109 // 110 //-------------------------------------------------------------------------- 111 112 /** 113 * Creates a new HTTPService. If you expect the service to send using relative URLs you may 114 * wish to specify the <code>baseURL</code> that will be the basis for determining the full URL (one example 115 * would be <code>Application.application.url</code>). 116 * 117 * @param baseURL The URL the HTTPService should use when computing relative URLS. 118 * 119 * @langversion 3.0 120 * @playerversion Flash 9 121 * @playerversion AIR 1.1 122 * @productversion Flex 3 123 */ 124 public function HTTPMultiService(baseURL:String = null, destination:String = null) 125 { 126 super(); 127 128 makeObjectsBindable = true; 129 130 if (destination == null) 131 { 132 if (URLUtil.isHttpsURL(LoaderConfig.url)) 133 asyncRequest.destination = HTTPService.DEFAULT_DESTINATION_HTTPS; 134 else 135 asyncRequest.destination = HTTPService.DEFAULT_DESTINATION_HTTP; 136 } 137 else 138 asyncRequest.destination = destination; 139 140 _log = Log.getLogger("mx.rpc.http.HTTPMultiService"); 141 142 this.baseURL = baseURL; 143 144 concurrency = Concurrency.MULTIPLE; 145 } 146 147 //-------------------------------------------------------------------------- 148 // 149 // Variables 150 // 151 //-------------------------------------------------------------------------- 152 153 /** 154 * @private 155 * A shared direct Http channelset used for service instances that do not use the proxy. 156 */ 157 private static var _directChannelSet:ChannelSet; 158 159 /** 160 * @private 161 * Logger 162 */ 163 private var _log:ILogger; 164 165 /** 166 * @private 167 */ 168 private var resourceManager:IResourceManager = ResourceManager.getInstance(); 169 170 /** 171 * @private 172 */ 173 private var _showBusyCursor:Boolean = false; 174 175 /** 176 * @private 177 */ 178 private var _concurrency:String; 179 180 //-------------------------------------------------------------------------- 181 // 182 // Properties 183 // 184 //-------------------------------------------------------------------------- 185 186 //---------------------------------- 187 // contentType 188 //---------------------------------- 189 190 [Inspectable(enumeration="application/x-www-form-urlencoded,application/xml", defaultValue="application/x-www-form-urlencoded", category="General")] 191 /** 192 * Type of content for service requests. 193 * The default is <code>application/x-www-form-urlencoded</code> which sends requests 194 * like a normal HTTP POST with name-value pairs. <code>application/xml</code> send 195 * requests as XML. 196 */ 197 public var contentType:String = AbstractOperation.CONTENT_TYPE_FORM; 198 199 //---------------------------------- 200 // concurrency 201 //---------------------------------- 202 203 [Inspectable(enumeration="multiple,single,last", defaultValue="multiple", category="General")] 204 /** 205 * Value that indicates how to handle multiple calls to the same operation within the service. 206 * The concurrency setting set here will be used for operations that do not specify concurrecny. 207 * Individual operations that have the concurrency setting set directly will ignore the value set here. 208 * The default value is <code>multiple</code>. The following values are permitted: 209 * <ul> 210 * <li><code>multiple</code> Existing requests are not cancelled, and the developer is 211 * responsible for ensuring the consistency of returned data by carefully 212 * managing the event stream. This is the default value.</li> 213 * <li><code>single</code> Only a single request at a time is allowed on the operation; 214 * multiple requests generate a fault.</li> 215 * <li><code>last</code> Making a request cancels any existing request.</li> 216 * </ul> 217 * 218 * @langversion 3.0 219 * @playerversion Flash 9 220 * @playerversion AIR 1.1 221 * @productversion Flex 3 222 */ 223 public function get concurrency():String 224 { 225 return _concurrency; 226 } 227 public function set concurrency(c:String):void 228 { 229 _concurrency = c; 230 } 231 232 //---------------------------------- 233 // showBusyCursor 234 //---------------------------------- 235 236 [Inspectable(defaultValue="false", category="General")] 237 /** 238 * If <code>true</code>, a busy cursor is displayed while a service is executing. The default 239 * value is <code>false</code>. 240 * 241 * @langversion 3.0 242 * @playerversion Flash 9 243 * @playerversion AIR 1.1 244 * @productversion Flex 3 245 */ 246 public function get showBusyCursor():Boolean 247 { 248 return _showBusyCursor; 249 } 250 251 public function set showBusyCursor(sbc:Boolean):void 252 { 253 _showBusyCursor = sbc; 254 } 255 256 //---------------------------------- 257 // headers 258 //---------------------------------- 259 260 [Inspectable(defaultValue="undefined", category="General")] 261 /** 262 * Custom HTTP headers to be sent to the third party endpoint. If multiple headers need to 263 * be sent with the same name the value should be specified as an Array. These headers are sent 264 * to all operations. You can also set headers at the operation level. 265 * 266 * @langversion 3.0 267 * @playerversion Flash 9 268 * @playerversion AIR 1.1 269 * @productversion Flex 3 270 */ 271 public var headers:Object = {}; 272 273 //---------------------------------- 274 // makeObjectsBindable 275 //---------------------------------- 276 277 [Inspectable(defaultValue="true", category="General")] 278 /** 279 * When <code>true</code>, the objects returned support data binding to UI controls. 280 * That means they send PropertyChangeEvents when their property values are being changed. 281 * This is the default value for any operations whose makeObjectsBindable property 282 * is not set explicitly. 283 * 284 * @langversion 3.0 285 * @playerversion Flash 9 286 * @playerversion AIR 1.1 287 * @productversion Flex 3 288 */ 289 public var makeObjectsBindable:Boolean = true; 290 291 //---------------------------------- 292 // method 293 //---------------------------------- 294 295 [Inspectable(enumeration="GET,get,POST,post,HEAD,head,OPTIONS,options,PUT,put,TRACE,trace,DELETE,delete", defaultValue="GET", category="General")] 296 /** 297 * HTTP method for sending the request if a method is not set explicit on the operation. 298 * Permitted values are <code>GET</code>, <code>POST</code>, <code>HEAD</code>, 299 * <code>OPTIONS</code>, <code>PUT</code>, <code>TRACE</code> and <code>DELETE</code>. 300 * Lowercase letters are converted to uppercase letters. The default value is <code>GET</code>. 301 * 302 * @langversion 3.0 303 * @playerversion Flash 9 304 * @playerversion AIR 1.1 305 * @productversion Flex 3 306 */ 307 public var method:String = HTTPRequestMessage.GET_METHOD; 308 309 //---------------------------------- 310 // resultFormat 311 //---------------------------------- 312 313 /** 314 * @private 315 */ 316 private var _resultFormat:String = AbstractOperation.RESULT_FORMAT_OBJECT; 317 318 [Inspectable(enumeration="object,array,xml,flashvars,text,e4x", defaultValue="object", category="General")] 319 /** 320 * Value that indicates how you want to deserialize the result 321 * returned by the HTTP call. The value for this is based on the following: 322 * <ul> 323 * <li>Whether you are returning XML or name/value pairs.</li> 324 * <li>How you want to access the results; you can access results as an object, 325 * text, or XML.</li> 326 * </ul> 327 * 328 * <p>The default value is <code>object</code>. The following values are permitted:</p> 329 * <ul> 330 * <li><code>object</code> The value returned is XML and is parsed as a tree of ActionScript 331 * objects. This is the default.</li> 332 * <li><code>array</code> The value returned is XML and is parsed as a tree of ActionScript 333 * objects however if the top level object is not an Array, a new Array is created and the result 334 * set as the first item. If makeObjectsBindable is true then the Array 335 * will be wrapped in an ArrayCollection.</li> 336 * <li><code>xml</code> The value returned is XML and is returned as literal XML in an 337 * ActionScript XMLnode object.</li> 338 * <li><code>flashvars</code> The value returned is text containing 339 * name=value pairs separated by ampersands, which 340 * is parsed into an ActionScript object.</li> 341 * <li><code>text</code> The value returned is text, and is left raw.</li> 342 * <li><code>e4x</code> The value returned is XML and is returned as literal XML 343 * in an ActionScript XML object, which can be accessed using ECMAScript for 344 * XML (E4X) expressions.</li> 345 * </ul> 346 * 347 * @langversion 3.0 348 * @playerversion Flash 9 349 * @playerversion AIR 1.1 350 * @productversion Flex 3 351 */ 352 public function get resultFormat():String 353 { 354 return _resultFormat; 355 } 356 357 /** 358 * @private 359 */ 360 public function set resultFormat(value:String):void 361 { 362 switch (value) 363 { 364 case AbstractOperation.RESULT_FORMAT_OBJECT: 365 case AbstractOperation.RESULT_FORMAT_ARRAY: 366 case AbstractOperation.RESULT_FORMAT_XML: 367 case AbstractOperation.RESULT_FORMAT_E4X: 368 case AbstractOperation.RESULT_FORMAT_TEXT: 369 case AbstractOperation.RESULT_FORMAT_FLASHVARS: 370 { 371 break; 372 } 373 374 default: 375 { 376 if (value != null && (serializationFilter = SerializationFilter.filterForResultFormatTable[value]) == null) 377 { 378 var message:String = resourceManager.getString( 379 "rpc", "invalidResultFormat", 380 [ value, AbstractOperation.RESULT_FORMAT_OBJECT, AbstractOperation.RESULT_FORMAT_ARRAY, 381 AbstractOperation.RESULT_FORMAT_XML, AbstractOperation.RESULT_FORMAT_E4X, 382 AbstractOperation.RESULT_FORMAT_TEXT, AbstractOperation.RESULT_FORMAT_FLASHVARS ]); 383 throw new ArgumentError(message); 384 } 385 } 386 } 387 _resultFormat = value; 388 } 389 390 /** Default serializationFilter used by all operations which do not set one explicitly */ 391 public var serializationFilter:SerializationFilter; 392 393 //---------------------------------- 394 // rootURL 395 //---------------------------------- 396 397 /** 398 * The URL that the HTTPService object should use when computing relative URLs. 399 * This contains a prefix which is prepended onto any URLs when it is set. 400 * It defaults to null in which case the URL for the SWF is used to compute 401 * relative URLs. 402 * 403 * @langversion 3.0 404 * @playerversion Flash 9 405 * @playerversion AIR 1.1 406 * @productversion Flex 3 407 */ 408 public var baseURL:String; 409 410 /** 411 * @private 412 */ 413 override public function set destination(value:String):void 414 { 415 useProxy = true; 416 super.destination = value; 417 } 418 419 /** 420 * @private 421 */ 422 private var _useProxy:Boolean = false; 423 424 [Inspectable(defaultValue="false", category="General")] 425 /** 426 * Specifies whether to use the Flex proxy service. The default value is <code>false</code>. If you 427 * do not specify <code>true</code> to proxy requests though the Flex server, you must ensure that the player 428 * can reach the target URL. You also cannot use destinations defined in the services-config.xml file if the 429 * <code>useProxy</code> property is set to <code>false</code>. 430 * 431 * @default false 432 * 433 * @langversion 3.0 434 * @playerversion Flash 9 435 * @playerversion AIR 1.1 436 * @productversion Flex 3 437 */ 438 public function get useProxy():Boolean 439 { 440 return _useProxy; 441 } 442 443 /** 444 * @private 445 */ 446 public function set useProxy(value:Boolean):void 447 { 448 if (value != _useProxy) 449 { 450 _useProxy = value; 451 var dcs:ChannelSet = getDirectChannelSet(); 452 if (!useProxy) 453 { 454 if (dcs != asyncRequest.channelSet) 455 asyncRequest.channelSet = dcs; 456 } 457 else 458 { 459 if (asyncRequest.channelSet == dcs) 460 asyncRequest.channelSet = null; 461 } 462 } 463 } 464 465 /** 466 * This serves as the default property for this instance so that we can 467 * define a set of operations as direct children of the HTTPMultiService 468 * tag in MXML. 469 * 470 * @langversion 3.0 471 * @playerversion Flash 9 472 * @playerversion AIR 1.1 473 * @productversion Flex 3 474 */ 475 public function set operationList(ol:Array):void 476 { 477 if (ol == null) 478 operations = null; 479 else 480 { 481 var op:AbstractOperation; 482 var ops:Object = new Object(); 483 for (var i:int = 0; i < ol.length; i++) 484 { 485 op = AbstractOperation(ol[i]); 486 var name:String = op.name; 487 if (!name) 488 throw new ArgumentError("Operations must have a name property value for HTTPMultiService"); 489 ops[name] = op; 490 } 491 operations = ops; 492 } 493 } 494 495 public function get operationList():Array 496 { 497 // Note: does not preserve order of the elements 498 if (operations == null) 499 return null; 500 var ol:Array = new Array(); 501 for (var i:String in operations) 502 { 503 var op:AbstractOperation = operations[i]; 504 ol.push(op); 505 } 506 return ol 507 } 508 509 //-------------------------------------------------------------------------- 510 // 511 // Internal Methods 512 // 513 //-------------------------------------------------------------------------- 514 515 mx_internal function getDirectChannelSet():ChannelSet 516 { 517 if (_directChannelSet == null) 518 { 519 var dcs:ChannelSet = new ChannelSet(); 520 var dhc:DirectHTTPChannel = new DirectHTTPChannel("direct_http_channel"); 521 dhc.requestTimeout = requestTimeout; 522 dcs.addChannel(dhc); 523 _directChannelSet = dcs; 524 } 525 return _directChannelSet; 526 } 527} 528 529} 530