You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by ah...@apache.org on 2019/10/03 21:16:33 UTC
[royale-asjs] 01/10: WebService compiles except for XMLDocument and
getTimer
This is an automated email from the ASF dual-hosted git repository.
aharui pushed a commit to branch webservice
in repository https://gitbox.apache.org/repos/asf/royale-asjs.git
commit b201a96b4493d7701c7f796c090d3ddb3f66a594
Author: Alex Harui <ah...@apache.org>
AuthorDate: Thu Sep 12 21:56:48 2019 -0700
WebService compiles except for XMLDocument and getTimer
---
.../src/main/resources/mx-royale-manifest.xml | 2 +
.../src/main/royale/mx/events/ErrorEvent.as | 2 +
.../royale/mx/messaging/messages/SOAPMessage.as | 126 +
.../src/main/royale/mx/rpc/events/HeaderEvent.as | 157 ++
.../main/royale/mx/rpc/events/SchemaLoadEvent.as | 105 +
.../src/main/royale/mx/rpc/events/WSDLLoadEvent.as | 149 ++
.../src/main/royale/mx/rpc/events/XMLLoadEvent.as | 169 ++
.../main/royale/mx/rpc/soap/AbstractWebService.as | 823 ++++++
.../src/main/royale/mx/rpc/soap/ISOAPDecoder.as | 131 +
.../src/main/royale/mx/rpc/soap/ISOAPEncoder.as | 83 +
.../src/main/royale/mx/rpc/soap/LoadEvent.as | 156 ++
.../src/main/royale/mx/rpc/soap/Operation.as | 1180 +++++++++
.../src/main/royale/mx/rpc/soap/SOAPConstants.as | 351 +++
.../src/main/royale/mx/rpc/soap/SOAPDecoder.as | 1031 ++++++++
.../src/main/royale/mx/rpc/soap/SOAPEncoder.as | 912 +++++++
.../src/main/royale/mx/rpc/soap/SOAPFault.as | 183 ++
.../src/main/royale/mx/rpc/soap/SOAPHeader.as | 120 +
.../src/main/royale/mx/rpc/soap/SOAPResult.as | 81 +
.../src/main/royale/mx/rpc/soap/WebService.as | 84 +-
.../src/main/royale/mx/rpc/soap/mxml/Operation.as | 272 ++
.../src/main/royale/mx/rpc/soap/mxml/WebService.as | 376 +++
.../royale/mx/rpc/soap/types/ApacheDocumentType.as | 55 +
.../main/royale/mx/rpc/soap/types/DataSetType.as | 165 ++
.../royale/mx/rpc/soap/types/ICustomSOAPType.as | 41 +
.../src/main/royale/mx/rpc/soap/types/MapType.as | 168 ++
.../main/royale/mx/rpc/soap/types/QueryBeanType.as | 107 +
.../main/royale/mx/rpc/soap/types/RowSetType.as | 119 +
.../main/royale/mx/rpc/soap/types/SOAPArrayType.as | 614 +++++
.../MXRoyale/src/main/royale/mx/rpc/wsdl/WSDL.as | 1366 ++++++++++
.../src/main/royale/mx/rpc/wsdl/WSDLBinding.as | 171 ++
.../src/main/royale/mx/rpc/wsdl/WSDLConstants.as | 257 ++
.../src/main/royale/mx/rpc/wsdl/WSDLEncoding.as | 278 ++
.../src/main/royale/mx/rpc/wsdl/WSDLLoader.as | 306 +++
.../src/main/royale/mx/rpc/wsdl/WSDLMessage.as | 203 ++
.../src/main/royale/mx/rpc/wsdl/WSDLMessagePart.as | 78 +
.../src/main/royale/mx/rpc/wsdl/WSDLOperation.as | 260 ++
.../src/main/royale/mx/rpc/wsdl/WSDLPort.as | 132 +
.../src/main/royale/mx/rpc/wsdl/WSDLPortType.as | 86 +
.../src/main/royale/mx/rpc/wsdl/WSDLService.as | 118 +
.../src/main/royale/mx/rpc/xml/ComplexString.as | 56 +
.../src/main/royale/mx/rpc/xml/ContentProxy.as | 398 +++
.../src/main/royale/mx/rpc/xml/DecodingContext.as | 45 +
.../src/main/royale/mx/rpc/xml/IXMLDecoder.as | 135 +
.../src/main/royale/mx/rpc/xml/IXMLEncoder.as | 107 +
.../main/royale/mx/rpc/xml/IXMLSchemaInstance.as | 65 +
.../src/main/royale/mx/rpc/xml/NamespaceUtil.as | 81 +
.../royale/mx/rpc/xml/QualifiedResourceManager.as | 164 ++
.../MXRoyale/src/main/royale/mx/rpc/xml/Schema.as | 305 +++
.../src/main/royale/mx/rpc/xml/SchemaConstants.as | 309 +++
.../src/main/royale/mx/rpc/xml/SchemaDatatypes.as | 193 ++
.../src/main/royale/mx/rpc/xml/SchemaLoader.as | 258 ++
.../src/main/royale/mx/rpc/xml/SchemaManager.as | 550 ++++
.../src/main/royale/mx/rpc/xml/SchemaMarshaller.as | 1513 +++++++++++
.../src/main/royale/mx/rpc/xml/SchemaProcessor.as | 235 ++
.../main/royale/mx/rpc/xml/SchemaTypeRegistry.as | 269 ++
.../src/main/royale/mx/rpc/xml/SimpleContent.as | 56 +
.../src/main/royale/mx/rpc/xml/SimpleXMLDecoder.as | 240 ++
.../src/main/royale/mx/rpc/xml/SimpleXMLEncoder.as | 284 ++
.../src/main/royale/mx/rpc/xml/TypeIterator.as | 194 ++
.../src/main/royale/mx/rpc/xml/XMLDecoder.as | 2728 ++++++++++++++++++++
.../src/main/royale/mx/rpc/xml/XMLEncoder.as | 1984 ++++++++++++++
.../src/main/royale/mx/rpc/xml/XMLLoader.as | 151 ++
.../src/main/royale/mx/utils/Base64Decoder.as | 62 +-
.../src/main/royale/mx/utils/Base64Encoder.as | 23 +-
.../src/main/royale/mx/utils/HexDecoder.as | 123 +
.../src/main/royale/mx/utils/HexEncoder.as | 182 ++
.../MXRoyale/src/main/royale/mx/utils/XMLUtil.as | 147 ++
.../src/main/royale/mx/utils/object_proxy.as | 34 +
68 files changed, 21820 insertions(+), 88 deletions(-)
diff --git a/frameworks/projects/MXRoyale/src/main/resources/mx-royale-manifest.xml b/frameworks/projects/MXRoyale/src/main/resources/mx-royale-manifest.xml
index 3f7bf8b..74a8731 100644
--- a/frameworks/projects/MXRoyale/src/main/resources/mx-royale-manifest.xml
+++ b/frameworks/projects/MXRoyale/src/main/resources/mx-royale-manifest.xml
@@ -62,6 +62,8 @@
<component id="RemoteObject" class="mx.rpc.remoting.mxml.RemoteObject" />
<component id="RemoteObjectOperation" class="mx.rpc.remoting.mxml.Operation"/>
<component id="HTTPService" class="mx.rpc.http.mxml.HTTPService" />
+ <component id="WebService" class="mx.rpc.soap.mxml.WebService" />
+ <component id="WebServiceOperation" class="mx.rpc.soap.mxml.Operation" />
<component id="NumberValidator" class="mx.validators.NumberValidator"/>
<component id="PhoneNumberValidator" class="mx.validators.PhoneNumberValidator"/>
<component id="DateValidator" class="mx.validators.DateValidator"/>
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/events/ErrorEvent.as b/frameworks/projects/MXRoyale/src/main/royale/mx/events/ErrorEvent.as
index 3bf3094..d0793b9 100644
--- a/frameworks/projects/MXRoyale/src/main/royale/mx/events/ErrorEvent.as
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/events/ErrorEvent.as
@@ -39,6 +39,8 @@ import org.apache.royale.events.IRoyaleEvent;
COMPILE::SWF
public class ErrorEvent extends flash.events.ErrorEvent
{
+ public static const ERROR:String = "error";
+
public function ErrorEvent(type:String, bubbles:Boolean = false,
cancelable:Boolean = false, text:String = "", id:int = 0
)
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/messaging/messages/SOAPMessage.as b/frameworks/projects/MXRoyale/src/main/royale/mx/messaging/messages/SOAPMessage.as
new file mode 100644
index 0000000..233e889
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/messaging/messages/SOAPMessage.as
@@ -0,0 +1,126 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.messaging.messages
+{
+
+[RemoteClass(alias="flex.messaging.messages.SOAPMessage")]
+
+/**
+ * SOAPMessages are similar to HTTPRequestMessages. However,
+ * they always contain a SOAP XML envelope request body
+ * that will always be sent using HTTP POST.
+ * They also allow a SOAP action to be specified.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion BlazeDS 4
+ * @productversion LCDS 3
+ */
+public class SOAPMessage extends HTTPRequestMessage
+{
+ //--------------------------------------------------------------------------
+ //
+ // Static Constants
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * The HTTP header that stores the SOAP action for the SOAPMessage.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion BlazeDS 4
+ * @productversion LCDS 3
+ */
+ public static const SOAP_ACTION_HEADER:String = "SOAPAction";
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructs an uninitialized SOAPMessage.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion BlazeDS 4
+ * @productversion LCDS 3
+ */
+ public function SOAPMessage()
+ {
+ super();
+ method = "POST";
+ contentType = CONTENT_TYPE_SOAP_XML;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Provides access to the name of the remote method/operation that
+ * will be called.
+ *
+ * @return Returns the name of the remote method/operation that
+ * will be called.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion BlazeDS 4
+ * @productversion LCDS 3
+ */
+ public function getSOAPAction():String
+ {
+ return (httpHeaders != null) ? httpHeaders[SOAP_ACTION_HEADER] : null;
+ }
+
+ /**
+ * @private
+ */
+ public function setSOAPAction(value:String):void
+ {
+ if (value != null)
+ {
+ if (value.indexOf('"') < 0)
+ {
+ var str:String = '"';
+ str += value;
+ str += '"';
+ value = str.toString();
+ }
+
+ if (httpHeaders == null)
+ httpHeaders = {};
+
+ httpHeaders[SOAP_ACTION_HEADER] = value;
+ }
+ }
+
+}
+
+}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/events/HeaderEvent.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/events/HeaderEvent.as
new file mode 100644
index 0000000..ddb196b
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/events/HeaderEvent.as
@@ -0,0 +1,157 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.events
+{
+
+import org.apache.royale.events.IRoyaleEvent;
+import org.apache.royale.events.Event;
+
+import mx.core.mx_internal;
+import mx.messaging.messages.IMessage;
+import mx.rpc.AsyncToken;
+
+use namespace mx_internal;
+
+/**
+ * The event that indicates an RPC operation, such as a WebService SOAP request,
+ * returned a header in the response. A new header event is dispatched for each
+ * service header.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class HeaderEvent extends AbstractEvent
+{
+ /**
+ * The HEADER event type.
+ *
+ * <p>The properties of the event object have the following values:</p>
+ * <table class="innertable">
+ * <tr><th>Property</th><th>Value</th></tr>
+ * <tr><td><code>bubbles</code></td><td>false</td></tr>
+ * <tr><td><code>token</code></td><td>The token that represents the call
+ * to the method. Used in the asynchronous completion token pattern.</td></tr>
+ * <tr><td><code>cancelable</code></td><td>true, but the preventDefault() method has
+ * no effect.</td></tr>
+ * <tr><td><code>currentTarget</code></td><td>The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * <code>myButton.addEventListener()</code> to register an event listener,
+ * myButton is the value of the <code>currentTarget</code>. </td></tr>
+ * <tr><td><code>header</code></td><td>Header that the RPC call returns in the response.
+ * </td></tr>
+ * <tr><td><code>message</code></td><td>The Message associated with this event.</td></tr>
+ * <tr><td><code>target</code></td><td>The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the <code>currentTarget</code> property to always access the
+ * Object listening for the event.</td></tr>
+ * </table>
+ * @eventType header
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const HEADER:String = "header";
+
+ private var _header:Object;
+
+ /**
+ * Creates a new HeaderEvent.
+ *
+ * @param type The event type; indicates the action that caused the event.
+ * @param bubbles Specifies whether the event can bubble up the display list hierarchy.
+ * @param cancelable Specifies whether the behavior associated with the event can be prevented. The dfault is <code>true</code>, but the <code>preventDefault()</code> method has no effect.
+ * @param header Object that holds the header of the call.
+ * @param token AsyncToken that represents the call to the method. Used in the asynchronous completion token pattern.
+ * @param message Source Message of the header.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function HeaderEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = true,
+ header:Object = null, token:AsyncToken = null, message:IMessage = null)
+ {
+ super(type, bubbles, cancelable, token, message);
+
+ _header = header;
+ }
+
+ /**
+ * Header that the RPC call returned in the response.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get header():Object
+ {
+ return _header;
+ }
+
+ /**
+ * Utility method to create a new HeaderEvent that doesn't bubble and is cancelable.
+ *
+ * @param header Object that holds the header of the call.
+ * @param token AsyncToken that represents the call to the method. Used in the asynchronous completion token pattern.
+ * @param message Source Message header.
+ *
+ * @return Returns a new HeaderEvent that doesn't bubble and is cancelable.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function createEvent(header:Object, token:AsyncToken, message:IMessage):HeaderEvent
+ {
+ return new HeaderEvent(HeaderEvent.HEADER, false, true, header, token, message);
+ }
+
+ /**
+ * @private
+ */
+ override public function cloneEvent():IRoyaleEvent
+ {
+ return new HeaderEvent(type, bubbles, cancelable, header, token, message);
+ }
+
+ /**
+ * Returns a string representation of the HeaderEvent.
+ *
+ * @return String representation of the HeaderEvent.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ override public function toString():String
+ {
+ return formatToString("HeaderEvent", "type", "bubbles", "cancelable", "eventPhase");
+ }
+}
+
+}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/events/SchemaLoadEvent.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/events/SchemaLoadEvent.as
new file mode 100644
index 0000000..98940d1
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/events/SchemaLoadEvent.as
@@ -0,0 +1,105 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.events
+{
+
+import org.apache.royale.events.IRoyaleEvent;
+import org.apache.royale.events.Event;
+import mx.rpc.xml.Schema;
+
+[ExcludeClass]
+
+/**
+ * This event is dispatched when an XML Schema has loaded sucessfully.
+ *
+ * @private
+ */
+public class SchemaLoadEvent extends XMLLoadEvent
+{
+ /**
+ * Creates a new SchemaLoadEvent.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function SchemaLoadEvent(type:String, bubbles:Boolean = false,
+ cancelable:Boolean = true, schema:Schema = null, location:String = null)
+ {
+ super(type == null ? LOAD : type,
+ bubbles,
+ cancelable,
+ schema == null ? null : schema.xml,
+ location);
+
+ this.schema = schema;
+ }
+
+ /**
+ * The full Schema document.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var schema:Schema;
+
+ /**
+ * Returns a copy of this SchemaLoadEvent.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ override public function cloneEvent():IRoyaleEvent
+ {
+ return new SchemaLoadEvent(type, bubbles, cancelable, schema, location);
+ }
+
+ /**
+ * Returns a String representation of this SchemaLoadEvent.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ override public function toString():String
+ {
+ return formatToString("SchemaLoadEvent", "location", "type", "bubbles",
+ "cancelable", "eventPhase");
+ }
+
+ /**
+ * A helper method to create a new SchemaLoadEvent.
+ * @private
+ */
+ public static function createEvent(schema:Schema, location:String = null):SchemaLoadEvent
+ {
+ return new SchemaLoadEvent(LOAD, false, true, schema, location);
+ }
+
+ public static const LOAD:String = "schemaLoad";
+}
+
+}
\ No newline at end of file
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/events/WSDLLoadEvent.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/events/WSDLLoadEvent.as
new file mode 100644
index 0000000..84dde55
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/events/WSDLLoadEvent.as
@@ -0,0 +1,149 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.events
+{
+
+import org.apache.royale.events.Event;
+import org.apache.royale.events.IRoyaleEvent;
+import mx.rpc.wsdl.WSDL;
+
+/**
+ * The WSDLLoadEvent class represents the event object for the event dispatched
+ * when a WSDL XML document has loaded successfully.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class WSDLLoadEvent extends XMLLoadEvent
+{
+ /**
+ * Constructor.
+ *
+ * @param type The event type; indicates the action that caused the event.
+ *
+ * @param bubbles Specifies whether the event can bubble up the display list hierarchy.
+ *
+ * @param cancelable Specifies whether the behavior associated with the event can be prevented.
+ *
+ * @param wsdl The full WSDL document.
+ *
+ * @param location The path used to load the document.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function WSDLLoadEvent(type:String, bubbles:Boolean = false,
+ cancelable:Boolean = true, wsdl:WSDL = null, location:String = null)
+ {
+ super(type == null ? LOAD : type,
+ bubbles,
+ cancelable,
+ wsdl == null ? null : wsdl.xml,
+ location);
+
+ this.wsdl = wsdl;
+ }
+
+ /**
+ * The full WSDL document.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var wsdl:WSDL
+
+ /**
+ * Returns a copy of this WSDLLoadEvent object.
+ *
+ * @return A copy of this WSDLLoadEvent object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ override public function cloneEvent():IRoyaleEvent
+ {
+ return new WSDLLoadEvent(type, bubbles, cancelable, wsdl, location);
+ }
+
+ /**
+ * Returns a String representation of this WSDLLoadEvent object.
+ *
+ * @return A String representation of this WSDLLoadEvent object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ override public function toString():String
+ {
+ return formatToString("WSDLLoadEvent", "location", "type", "bubbles",
+ "cancelable", "eventPhase");
+ }
+
+ /**
+ * A helper method to create a new WSDLLoadEvent.
+ * @private
+ */
+ public static function createEvent(wsdl:WSDL, location:String = null):WSDLLoadEvent
+ {
+ return new WSDLLoadEvent(LOAD, false, true, wsdl, location);
+ }
+
+ /**
+ * The LOAD constant defines the value of the <code>type</code> property of the event object
+ * for a <code>wsdlLoad</code> event.
+ *
+ * <p>The properties of the event object have the following values:</p>
+ * <table class="innertable">
+ * <tr><th>Property</th><th>Value</th></tr>
+ * <tr><td><code>bubbles</code></td><td><code>false</code></td></tr>
+ * <tr><td><code>cancelable</code></td><td><code>true</code></td></tr>
+ * <tr><td><code>currentTarget</code></td><td>The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * <code>myButton.addEventListener()</code> to register an event listener,
+ * myButton is the value of the <code>currentTarget</code>. </td></tr>
+ * <tr><td><code>location</code></td><td>The path used to load the document.</td></tr>
+ * <tr><td><code>target</code></td><td>The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the <code>currentTarget</code> property to always access the
+ * Object listening for the event.</td></tr>
+ * <tr><td><code>wsdl</code></td><td>The full WSDL document.</td></tr>
+ * </table>
+ *
+ * @eventType result
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const LOAD:String = "wsdlLoad";
+}
+
+}
\ No newline at end of file
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/events/XMLLoadEvent.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/events/XMLLoadEvent.as
new file mode 100644
index 0000000..323bfcd
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/events/XMLLoadEvent.as
@@ -0,0 +1,169 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.events
+{
+
+import org.apache.royale.events.Event;
+import org.apache.royale.events.IRoyaleEvent;
+
+/**
+ * The XMLLoadEvent class is a base class for events that are dispatched when an RPC service
+ * successfully loaded an XML document.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class XMLLoadEvent extends Event
+{
+ /**
+ * Constructor.
+ *
+ * @param type The event type; indicates the action that triggered the event.
+ *
+ * @param bubbles Specifies whether the event can bubble up the display list hierarchy.
+ *
+ * @param cancelable Specifies whether the behavior associated with the event can be prevented.
+ *
+ * @param xml The XML document loaded.
+ *
+ * @param location The path used to load the document.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function XMLLoadEvent(type:String, bubbles:Boolean = false,
+ cancelable:Boolean = true, xml:XML = null, location:String = null)
+ {
+ super(type == null ? LOAD : type,
+ bubbles,
+ cancelable);
+
+ this.xml = xml;
+ this.location = location;
+ }
+
+ /**
+ * The raw XML document.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var xml:XML;
+
+ /**
+ * The location from which the document was loaded.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var location:String;
+
+ /**
+ * Returns a copy of this XMLLoadEvent object.
+ *
+ * @return A copy of this XMLLoadEvent object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ override public function cloneEvent():IRoyaleEvent
+ {
+ return new XMLLoadEvent(type, bubbles, cancelable, xml, location);
+ }
+
+ /**
+ * Returns a String representation of this XMLLoadEvent object.
+ *
+ * @return A String representation of this XMLLoadEvent object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ COMPILE::SWF {override}
+ public function toString():String
+ {
+ return formatToString("XMLLoadEvent", "location", "type", "bubbles",
+ "cancelable", "eventPhase");
+ }
+
+ COMPILE::JS
+ public function formatToString(className:String, ... rest):String
+ {
+ if (rest)
+ {
+ for (var s:String in rest)
+ className += " " + s;
+ }
+ return className;
+ }
+
+ /**
+ * A helper method to create a new XMLLoadEvent.
+ * @private
+ */
+ public static function createEvent(xml:XML = null, location:String = null):XMLLoadEvent
+ {
+ return new XMLLoadEvent(LOAD, false, true, xml, location);
+ }
+
+ /**
+ * The LOAD constant defines the value of the <code>type</code> property of the event object
+ * for a <code>xmlLoad</code> event.
+ *
+ * <p>The properties of the event object have the following values:</p>
+ * <table class="innertable">
+ * <tr><th>Property</th><th>Value</th></tr>
+ * <tr><td><code>bubbles</code></td><td><code>false</code></td></tr>
+ * <tr><td><code>cancelable</code></td><td><code>true</code></td></tr>
+ * <tr><td><code>currentTarget</code></td><td>The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * <code>myButton.addEventListener()</code> to register an event listener,
+ * myButton is the value of the <code>currentTarget</code>. </td></tr>
+ * <tr><td><code>location</code></td><td>The location from which the document was loaded.</td></tr>
+ * <tr><td><code>target</code></td><td>The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the <code>currentTarget</code> property to always access the
+ * Object listening for the event.</td></tr>
+ * <tr><td><code>xml</code></td><td>The raw XML document.</td></tr>
+ * </table>
+ *
+ * @eventType result
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const LOAD:String = "xmlLoad";
+}
+
+}
\ No newline at end of file
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/AbstractWebService.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/AbstractWebService.as
new file mode 100644
index 0000000..a94c3fa
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/AbstractWebService.as
@@ -0,0 +1,823 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap
+{
+
+import org.apache.royale.events.Event;
+
+import mx.core.mx_internal;
+import mx.logging.ILogger;
+import mx.logging.Log;
+import mx.messaging.ChannelSet;
+import mx.messaging.channels.DirectHTTPChannel;
+import mx.messaging.config.LoaderConfig;
+import mx.rpc.AbstractOperation;
+import mx.rpc.AbstractService;
+import mx.rpc.AsyncRequest;
+import mx.rpc.Fault;
+import mx.rpc.events.FaultEvent;
+import mx.rpc.http.HTTPService;
+import mx.utils.URLUtil;
+import mx.utils.XMLUtil;
+
+use namespace mx_internal;
+
+/**
+ * AbstractWebService is an abstract base class for implementations
+ * that provide RPC access to SOAP-based web services. This class does not
+ * load WSDL descriptions at runtime.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class AbstractWebService extends AbstractService
+{
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Creates a new WebService. The destination, if specified, should match an
+ * entry in services-config.xml. If unspecified, the WebService uses the
+ * DefaultHTTP destination. The <code>rootURL</code> is required if you
+ * intend to use a relative URL find the WSDL document for this WebService.
+ *
+ * @param destination The destination. It should match a destination name
+ * in the services-config.xml file.
+ *
+ * @param rootURL The URL that the WebService should use when computing relative URLs.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function AbstractWebService(destination:String = null, rootURL:String = null)
+ {
+ super(destination);
+
+ _useProxy = false;
+ _headers = [];
+ _log = Log.getLogger("mx.rpc.soap.AbstractWebService");
+
+ if (destination == null)
+ {
+ // If the SWF was loaded via HTTPS, we'll use the DefaultHTTPS
+ // destination by default
+ if (URLUtil.isHttpsURL(LoaderConfig.url))
+ super.destination = DEFAULT_DESTINATION_HTTPS;
+ else
+ super.destination = DEFAULT_DESTINATION_HTTP;
+
+ destinationSet = false;
+ }
+ else
+ {
+ destinationSet = true;
+ }
+
+ makeObjectsBindable = true;
+
+ _ready = true;
+ }
+
+ //-------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //-------------------------------------------------------------------------
+
+ //----------------------------------
+ // description
+ //----------------------------------
+
+ /**
+ * The description of the service for the currently active port.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get description():String
+ {
+ return _description;
+ }
+
+ public function set description(value:String):void
+ {
+ _description = value;
+ }
+
+
+ //----------------------------------
+ // destination
+ //----------------------------------
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ override public function get destination():String
+ {
+ return super.destination;
+ }
+
+ override public function set destination(value:String):void
+ {
+ super.destination = value;
+ useProxy = true;
+ destinationSet = true;
+ }
+
+
+ //----------------------------------
+ // endpointURI
+ //----------------------------------
+
+ /**
+ * The location of the WebService. Normally, the WSDL document specifies
+ * the location of the services, but you can set this property to override
+ * that location.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get endpointURI():String
+ {
+ return (endpointOverride) ? endpointOverride : _endpointURI;
+ }
+
+ public function set endpointURI(value:String):void
+ {
+ endpointOverride = value;
+ }
+
+
+ //----------------------------------
+ // headers
+ //----------------------------------
+
+ /**
+ * Returns the array of SOAPHeaders registered for the WebService.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get headers():Array
+ {
+ return _headers;
+ }
+
+
+ //----------------------------------
+ // httpHeaders
+ //----------------------------------
+
+ private var _httpHeaders:Object;
+
+ [Inspectable(defaultValue="undefined", category="General")]
+ /**
+ * Custom HTTP headers to be sent to the SOAP endpoint. If multiple
+ * headers need to be sent with the same name the value should be specified
+ * as an Array.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get httpHeaders():Object
+ {
+ return _httpHeaders;
+ }
+
+ public function set httpHeaders(value:Object):void
+ {
+ _httpHeaders = value;
+ }
+
+
+ //----------------------------------
+ // makeObjectsBindable
+ //----------------------------------
+
+ [Inspectable(defaultValue="true", category="General")]
+ /**
+ * When this value is true, anonymous objects returned are forced to
+ * bindable objects.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get makeObjectsBindable():Boolean
+ {
+ return _makeObjectsBindable;
+ }
+
+ public function set makeObjectsBindable(value:Boolean):void
+ {
+ _makeObjectsBindable = value;
+ }
+
+
+ //----------------------------------
+ // port
+ //----------------------------------
+
+ /**
+ * Specifies the port within the WSDL document that this WebService should
+ * use.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get port():String
+ {
+ return _port;
+ }
+
+ public function set port(value:String):void
+ {
+ _port = value;
+ }
+
+
+ //----------------------------------
+ // ready
+ //----------------------------------
+
+ /**
+ * Specifies whether the WebService is ready to make requests.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get ready():Boolean
+ {
+ return _ready;
+ }
+
+
+ //----------------------------------
+ // rootURL
+ //----------------------------------
+
+ /**
+ * The URL that the WebService should use when computing relative URLs. This
+ * property is only used when going through the proxy. When the
+ * <code>useProxy</code> property is set <code>to false</code> the relative
+ * URL is computed automatically based on the location of the SWF running
+ * this application. If not set explicitly <code>rootURL</code> is
+ * automatically set to the URL of mx.messaging.config.LoaderConfig.url.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get rootURL():String
+ {
+ if (_rootURL == null)
+ {
+ _rootURL = LoaderConfig.url;
+ }
+ return _rootURL;
+ }
+
+ public function set rootURL(value:String):void
+ {
+ _rootURL = value;
+ }
+
+
+ //----------------------------------
+ // service
+ //----------------------------------
+
+ /**
+ * Specifies the service within the WSDL document that this WebService
+ * should use.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get service():String
+ {
+ return _service;
+ }
+
+ public function set service(value:String):void
+ {
+ _service = value;
+ }
+
+
+ //----------------------------------
+ // useProxy
+ //----------------------------------
+
+ [Inspectable(defaultValue="false", category="General")]
+ /**
+ * Specifies whether to use the Flex proxy service. The default value is
+ * <code>false</code>. If you do not specify <code>true</code> to proxy
+ * requests though the Flex server, you must ensure that Flash Player can
+ * reach the target URL. You also cannot use destinations defined in the
+ * services-config.xml file if the <code>useProxy</code> property is set
+ * to <code>false</code>.
+ *
+ * @default false
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get useProxy():Boolean
+ {
+ return _useProxy;
+ }
+
+ public function set useProxy(value:Boolean):void
+ {
+ if (value != _useProxy)
+ {
+ _useProxy = value;
+
+ var dcs:ChannelSet = getDirectChannelSet();
+ if (!useProxy)
+ {
+ if (dcs != asyncRequest.channelSet)
+ asyncRequest.channelSet = dcs;
+ }
+ else
+ {
+ if (asyncRequest.channelSet == dcs)
+ asyncRequest.channelSet = null;
+ }
+ }
+ }
+
+
+ //----------------------------------
+ // xmlSpecialCharsFilter
+ //----------------------------------
+
+ private var _xmlSpecialCharsFilter:Function;
+
+ [Inspectable(defaultValue="undefined", category="General")]
+ /**
+ * Custom function to be used to escape XML special characters before
+ * encoding any simple content. Valid for all operations on the web
+ * service unless specifically overwritten on the operation level.
+ * If none is provided, the default function is whatever is set by the particular
+ * implementation of IXMLEncoder.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get xmlSpecialCharsFilter():Function
+ {
+ return _xmlSpecialCharsFilter;
+ }
+
+ public function set xmlSpecialCharsFilter(func:Function):void
+ {
+ _xmlSpecialCharsFilter = func;
+ }
+
+ //----------------------------------
+ // convertParametersHandler
+ //----------------------------------
+
+ /**
+ * An optional function, primarily intended for framework developers who need to install
+ * a function to get called with the parameters passed to each webservice operation invocation.
+ * The function takes an array of parameters and returns the potentially altered array.
+ *
+ * The function definition should look like:
+ * <code>
+ * function myParametersFunction(parameters:Array):Array
+ * </code>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var convertParametersHandler:Function;
+
+ //----------------------------------
+ // convertResultHandler
+ //----------------------------------
+
+ /**
+ * An optional function, primarily intended for framework developers who need to install
+ * a hook to process the results of an operation before notifying the result handlers.
+ *
+ * The function definition should look like:
+ * <code>
+ * function myConvertResultsFunction(result:*, operation:AbstractOperation):*
+ * </code>
+ *
+ * It is passed the result just after the makeObjectsBindable conversion has been done
+ * but before the result event is created.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var convertResultHandler:Function;
+
+ //-------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //-------------------------------------------------------------------------
+
+ /**
+ * Adds a header that will be applied to all operations of this web service.
+ * The header can be provided in a pre-encoded form as an XML instance, or
+ * as a SOAPHeader instance which leaves the encoding up to the internal
+ * SOAP encoder.
+ *
+ * @param header The SOAP header to add to all operations.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function addHeader(header:Object):void
+ {
+ _headers.push(header);
+ }
+
+ /**
+ * Add a header that will be applied to all operations of this WebService.
+ *
+ * @param qnameLocal The localname for the header QName.
+ * @param qnameNamespace The namespace for the header QName.
+ * @param headerName The name of the header.
+ * @param headerValue The value of the header.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function addSimpleHeader(qnameLocal:String, qnameNamespace:String, headerName:String, headerValue:String):void
+ {
+ var obj:Object = {};
+ obj[headerName] = headerValue;
+ addHeader(new SOAPHeader(new QName(qnameNamespace, qnameLocal), obj));
+ }
+
+ /**
+ * Clears the headers that applied to all operations.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function clearHeaders():void
+ {
+ _headers.length = 0;
+ }
+
+ /**
+ * Returns a header if a match is found based on QName, localName, and URI.
+ *
+ * @param qname QName of the SOAPHeader.
+ * @param headerName (Optional) Name of a header in the SOAPHeader content.
+ *
+ * @return Returns a header if a match is found based on QName, localName, and URI.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function getHeader(qname:QName, headerName:String = null):SOAPHeader
+ {
+ var length:uint = _headers.length;
+ for (var i:uint = 0; i < length; i++)
+ {
+ var header:SOAPHeader = SOAPHeader(_headers[i]);
+ if (XMLUtil.qnamesEqual(header.qname, qname))
+ {
+ if (headerName)
+ {
+ if (header.content && header.content[headerName])
+ {
+ return header;
+ }
+ }
+ else
+ {
+ return header;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Removes the header with the given QName from all operations.
+ *
+ * @param qname QName of the SOAPHeader.
+ * @param headerName (Optional) Name of a header in the SOAPHeader content.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function removeHeader(qname:QName, headerName:String = null):void
+ {
+ var length:uint = _headers.length;
+ for (var i:uint = 0; i < length; i++)
+ {
+ var header:SOAPHeader = SOAPHeader(_headers[i]);
+ if (XMLUtil.qnamesEqual(header.qname, qname))
+ {
+ if (headerName)
+ {
+ if (header.content && header.content[headerName])
+ {
+ _headers.splice(i, 1);
+ return; // Got it
+ }
+ }
+ else
+ {
+ _headers.splice(i, 1);
+ return; // Got it
+ }
+ }
+ }
+ }
+
+ /**
+ * The username and password to authenticate a user when accessing
+ * the webservice. These will be passed as part of the HTTP Authorization
+ * header from the proxy to the endpoint. If useProxy is false this property
+ * will be ignored.
+ *
+ * @param remoteUsername The username to pass to the remote endpoint.
+ * @param remotePassword The password to pass to the remote endpoint.
+ * @param charset The character set encoding to use while encoding the
+ * remote credentials. The default is null, which implies the legacy charset
+ * of ISO-Latin-1. The only other supported charset is "UTF-8".
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ override public function setRemoteCredentials(remoteUsername:String, remotePassword:String, charset:String=null):void
+ {
+ super.setRemoteCredentials(remoteUsername, remotePassword, charset);
+ }
+
+ //---------------------------------
+ // Helper methods
+ //---------------------------------
+
+ /**
+ * Returns a JSESSIOND found in the URL. This should be attached
+ * to any communication back with the server where session state needs to
+ * be preserved
+ * @private
+ */
+ mx_internal static function findJSessionID():String
+ {
+ var jsessionid:String = null;
+ var args:Object = LoaderConfig.parameters;
+ if (args)
+ {
+ var js:Object = args.jsessionid;
+ if (!js)
+ {
+ js = args.JSESSIONID;
+
+ if (!js)
+ {
+ var u:String = LoaderConfig.url;
+ if (u)
+ {
+ var ind:Number = u.lastIndexOf(";")
+ if (ind != -1)
+ {
+ var arr:Array = u.substring(ind + 1).split("=");
+
+ if (arr[0] == "jsessionid" || arr[0] == "JSESSIONID")
+ {
+ jsessionid = arr[1];
+ }
+ }
+ }
+ }
+ else
+ {
+ jsessionid = String(js);
+ }
+ }
+ else
+ {
+ jsessionid = String(js);
+ }
+ }
+ return jsessionid;
+ }
+
+ /**
+ * @private
+ */
+ mx_internal function getDirectChannelSet():ChannelSet
+ {
+ if (_directChannelSet == null)
+ {
+ var dcs:ChannelSet = new ChannelSet();
+ var dhc:DirectHTTPChannel = new DirectHTTPChannel("direct_http_channel");
+ dhc.requestTimeout = requestTimeout;
+ dcs.addChannel(dhc);
+ _directChannelSet = dcs;
+ }
+ return _directChannelSet;
+ }
+
+ // Deals with the queued calls - if a fault is passed, we'll simply dispatch
+ // a FaultEvent for each call. Otherwise we invoke each one.
+ /**
+ * @private
+ */
+ protected function unEnqueueCalls(fault:Fault = null):void
+ {
+ var op:Operation;
+ for (var opName:String in _operations)
+ {
+ op = _operations[opName];
+ if (op.hasPendingInvocations())
+ {
+ if (fault != null)
+ {
+ _log.info("Faulting previously queued operation calls {0}", op.name);
+ while (op.hasPendingInvocations())
+ {
+ op.cancel();
+ op.dispatchEvent(FaultEvent.createEvent(fault));
+ }
+ }
+ else
+ {
+ _log.info("Invoking previously queued calls {0}", op.name);
+ op.invokeAllPending();
+ }
+ }
+ }
+ }
+
+ //-------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //-------------------------------------------------------------------------
+
+ //--------------------------------------------
+ // Backing variables for public getter/setters
+ //--------------------------------------------
+
+ /**
+ * @private
+ */
+ protected var _endpointURI:String;
+
+ private var _description:String;
+
+ private var endpointOverride:String;
+
+ private var _headers:Array;
+
+ private var _makeObjectsBindable:Boolean;
+
+ /**
+ * @private
+ */
+ protected var _port:String;
+
+ private var _rootURL:String;
+
+ /**
+ * @private
+ */
+ protected var _service:String;
+
+ private var _useProxy:Boolean;
+
+ //---------------------------------
+ // Internal properties
+ //---------------------------------
+
+ //private var _activePort:Object;
+
+ /**
+ * @private
+ */
+ protected var destinationSet:Boolean;
+
+ /**
+ * @private
+ */
+ protected var _ready:Boolean;
+
+ private var _log:ILogger;
+
+ /**
+ * @private
+ */
+ private static var _directChannelSet:ChannelSet = null;
+
+ //--------------------------------------------------------------------------
+ //
+ // Static Constants
+ //
+ //--------------------------------------------------------------------------
+
+
+ /**
+ * The default destination to use for HTTP connections when invoking a webservice through a proxy.
+ * If you don't provide a destination and you set the <code>useProxy</code> property to <code>true</code>,
+ * the default destinations will be used to route the requests to the webservice endpoint.
+ *
+ * <p>Note that if the default destinations are used, you must specify the WSDL and endpointURI on the client.
+ * If you use a non-default proxy destination, you can have the WSDL and endpointURI specified in the
+ * destination configuration.</p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const DEFAULT_DESTINATION_HTTP:String = "DefaultHTTP";
+
+ /**
+ * The default destination to use for HTTPS connections when invoking a webservice through a proxy.
+ * If you don't provide a destination and you set the <code>useProxy</code> property to <code>true</code>,
+ * the default destinations will be used to route the requests to the webservice endpoint.
+ *
+ * <p>Note that if the default destinations are used, you must specify the WSDL and endpointURI on the client.
+ * If you use a non-default proxy destination, you can have the WSDL and endpointURI specified in the
+ * destination configuration.</p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const DEFAULT_DESTINATION_HTTPS:String = "DefaultHTTPS";
+}
+
+}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/ISOAPDecoder.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/ISOAPDecoder.as
new file mode 100644
index 0000000..8770a02
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/ISOAPDecoder.as
@@ -0,0 +1,131 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap
+{
+
+import mx.rpc.wsdl.WSDLOperation;
+import mx.rpc.xml.IXMLDecoder;
+import mx.rpc.xml.SchemaConstants;
+
+[ExcludeClass]
+
+/**
+ * Decodes the SOAP response for a particular operation.
+ *
+ */
+public interface ISOAPDecoder extends IXMLDecoder
+{
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Determines whether or not a single or empty return value for an output
+ * message part that is defined as an array should be returned as an array
+ * containing one (or zero, respectively) elements. This is applicable for
+ * document/literal "wrapped" web services, where one or more of the elements
+ * that represent individual message parts in the "wrapper" sequence could
+ * have the maxOccurs attribute set with a value greater than 1. This is a
+ * hint that the corresponding part should be treated as an array even if
+ * the response contains zero or one values for that part. Setting
+ * forcePartArrays to true will always create an array for parts defined in
+ * this manner, regardless of the number of values returned. Leaving
+ * forcePartArrays as false will only create arrays if two or more elements
+ * are returned.
+ */
+ function get forcePartArrays():Boolean;
+ function set forcePartArrays(value:Boolean):void;
+
+ /**
+ * Determines whether the decoder should ignore whitespace when processing
+ * the XML of a SOAP-encoded response. The default should be
+ * <code>true</code> and thus whitespace not preserved. If an XML Schema
+ * type definition specifies a <code>whiteSpace</code> restriction set to
+ * <code>preserve</code> then ignoreWhitespace must first be set to <code>false</code>.
+ * Conversely, if a type <code>whiteSpace</code> restriction is set to
+ * <code>replace</code> or <code>collapse</code> then that setting is
+ * be honored even if ignoreWhitespace is set to <code>false</code>.
+ */
+ function get ignoreWhitespace():Boolean;
+ function set ignoreWhitespace(value:Boolean):void;
+
+ /**
+ * Determines how the SOAP-encoded XML result is decoded. A value of
+ * <code>object</code> specifies that the XML is decoded into an
+ * object structure as specified in the WSDL document. A value of
+ * <code>xml</code> specifies that the XML is left as XMLNodes. A
+ * value of <code>e4x</code> specifies that the XML will be accessible
+ * using ECMAScript for XML (E4X) expressions.
+ */
+ function get resultFormat():String;
+ function set resultFormat(value:String):void;
+
+ /**
+ * Determines how the SOAP-encoded headers are decoded. A value of
+ * <code>object</code> specifies that each header XML node is decoded
+ * into a SOAPHeader object, and its <code>content</code> property is
+ * an object structure as specified in the WSDL document. A value of
+ * <code>xml</code> specifies that the XML is left as XMLNodes. A
+ * value of <code>e4x</code> specifies that the XML should be accessible
+ * using ECMAScript for XML (E4X) expressions.
+ */
+ function get headerFormat():String;
+ function set headerFormat(value:String):void;
+
+ /**
+ * Determines the type of the default result object for calls to web services
+ * that define multiple parts in the output message. A value of "object"
+ * specifies that the lastResult object will be an Object with named properties
+ * corresponding to the individual output parts. A value of "array" would
+ * make the lastResult an array, where part values are pushed in the order
+ * they occur in the body of the SOAP message. The default value for document-
+ * literal web services is "object". The default for rpc services is "array".
+ * The multiplePartsFormat property is applicable only when
+ * resultFormat="object" and ignored otherwise.
+ */
+ function get multiplePartsFormat():String;
+ function set multiplePartsFormat(value:String):void;
+
+ /**
+ * A WSDLOperation defines the SOAP binding styles and specifies how to
+ * decode a SOAP result.
+ */
+ function get wsdlOperation():WSDLOperation;
+ function set wsdlOperation(value:WSDLOperation):void;
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Decodes a SOAP response into a result and headers.
+ *
+ * @param response The SOAP response object.
+ *
+ * @return A SOAPResult object containing the response.
+ */
+ function decodeResponse(response:*):SOAPResult;
+}
+
+}
\ No newline at end of file
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/ISOAPEncoder.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/ISOAPEncoder.as
new file mode 100644
index 0000000..154d2f7
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/ISOAPEncoder.as
@@ -0,0 +1,83 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap
+{
+
+import mx.rpc.wsdl.WSDLOperation;
+import mx.rpc.xml.SchemaConstants;
+import mx.rpc.xml.IXMLEncoder;
+
+[ExcludeClass]
+
+/**
+ * An ISOAPEncoder is used to create SOAP 1.1 formatted requests for a web
+ * service operation. A WSDLOperation provides the definition of how a SOAP
+ * request should be formatted and therefore must be set before a call is made to
+ * encode().
+ *
+ */
+public interface ISOAPEncoder extends IXMLEncoder
+{
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Determines whether the encoder should ignore whitespace when
+ * constructing an XML representation of a SOAP request.
+ * The default should be <code>true</code> and thus whitespace not preserved.
+ * If an XML Schema type definition specifies a <code>whiteSpace</code>
+ * restriction set to <code>preserve</code> then ignoreWhitespace must
+ * first be set to false. Conversely, if a type <code>whiteSpace</code>
+ * restriction is set to <code>replace</code> or <code>collapse</code> then
+ * that setting will be honored even if ignoreWhitespace is set to <code>false</code>.
+ */
+ function get ignoreWhitespace():Boolean;
+ function set ignoreWhitespace(value:Boolean):void;
+
+ /**
+ * A WSDLOperation defines the SOAP binding styles and specifies how to
+ * encode a SOAP request.
+ */
+ function get wsdlOperation():WSDLOperation;
+ function set wsdlOperation(value:WSDLOperation):void;
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Creates a SOAP-encoded request to an operation from the given input
+ * parameters and headers.
+ *
+ * @param args values to be encoded in the body of the SOAP request.
+ *
+ * @param headers header values to be encoded in the SOAP envelope.
+ *
+ * @return SOAP-encoded XML representation of the passed in arguments and headers.
+ */
+ function encodeRequest(args:* = null, headers:Array = null):XML;
+}
+
+}
\ No newline at end of file
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/LoadEvent.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/LoadEvent.as
new file mode 100644
index 0000000..8f6a857
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/LoadEvent.as
@@ -0,0 +1,156 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap
+{
+
+import org.apache.royale.events.Event;
+import org.apache.royale.events.IRoyaleEvent;
+import flash.xml.XMLDocument;
+import mx.rpc.events.WSDLLoadEvent;
+import mx.rpc.wsdl.WSDL;
+
+// Note that this event is retained in the mx.rpc.soap package
+// for backwards compatibility.
+
+/**
+ * This event is dispatched when a WSDL XML document has loaded successfully.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class LoadEvent extends WSDLLoadEvent
+{
+ /**
+ * Creates a new WSDLLoadEvent.
+ * @param type The event type; indicates the action that triggered the event.
+ * @param bubbles Specifies whether the event can bubble up the display list hierarchy.
+ * @param cancelable Specifies whether the behavior associated with the event can be prevented.
+ * @param wsdl Object that contains the WSDL document.
+ * @param location URL of the WSDL document.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function LoadEvent(type:String, bubbles:Boolean = false,
+ cancelable:Boolean = true, wsdl:WSDL = null, location:String = null)
+ {
+ super(type == null ? LOAD : type,
+ bubbles,
+ cancelable,
+ wsdl,
+ location);
+ }
+
+ [Deprecated(replacement="xml")]
+ /**
+ * This getter is retained to provide legacy access to the loaded document
+ * as an instance of flash.xml.XMLDocument.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get document():XMLDocument
+ {
+ if (_document == null && xml != null)
+ {
+ try
+ {
+ _document = new XMLDocument(xml.toXMLString());
+ }
+ catch(e:Error)
+ {
+ }
+ }
+ return _document;
+ }
+
+ /**
+ * Returns a copy of this LoadEvent.
+ *
+ * @return Returns a copy of this LoadEvent.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ override public function cloneEvent():IRoyaleEvent
+ {
+ return new LoadEvent(type, bubbles, cancelable, wsdl, location);
+ }
+
+ /**
+ * Returns a String representation of this LoadEvent.
+ *
+ * @return Returns a String representation of this LoadEvent.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ override public function toString():String
+ {
+ return formatToString("LoadEvent", "location", "type", "bubbles",
+ "cancelable", "eventPhase");
+ }
+
+ /**
+ * A helper method to create a new LoadEvent.
+ * @private
+ */
+ public static function createEvent(wsdl:WSDL, location:String = null):LoadEvent
+ {
+ return new LoadEvent(LOAD, false, true, wsdl, location);
+ }
+
+
+ /**
+ * The <code>LOAD</code> constant defines the value of the <code>type</code> property
+ * of the event object for a <code>load</code> event.
+ *
+ * <p>The properties of the event object have the following values:</p>
+ * <table class="innertable">
+ * <tr><th>Property</th><th>Value</th></tr>
+ * <tr><td><code>bubbles</code></td><td>false</td></tr>
+ * <tr><td><code>cancelable</code></td><td>true</td></tr>
+ * <tr><td><code>wsdl</code></td><td>WSDL object.</td></tr>
+ * <tr><td><code>location</code></td><td>URI of the WSDL document</td></tr>
+ * </table>
+ *
+ * @eventType load
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const LOAD:String = "load";
+
+ private var _document:XMLDocument;
+}
+
+}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/Operation.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/Operation.as
new file mode 100644
index 0000000..6243d69
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/Operation.as
@@ -0,0 +1,1180 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap
+{
+
+import org.apache.royale.events.Event;
+import flash.xml.XMLNode;
+
+import mx.core.mx_internal;
+import mx.logging.Log;
+import mx.logging.ILogger;
+import mx.messaging.ChannelSet;
+import mx.messaging.events.MessageEvent;
+import mx.messaging.events.MessageFaultEvent;
+import mx.messaging.messages.IMessage;
+import mx.messaging.messages.SOAPMessage;
+import mx.netmon.NetworkMonitor;
+import mx.resources.IResourceManager;
+import mx.resources.ResourceManager;
+import mx.rpc.AbstractOperation;
+import mx.rpc.AbstractService;
+import mx.rpc.AsyncToken;
+import mx.rpc.Fault;
+import mx.rpc.events.FaultEvent;
+import mx.rpc.events.HeaderEvent;
+import mx.rpc.events.ResultEvent;
+import mx.rpc.soap.AbstractWebService;
+import mx.rpc.wsdl.WSDLOperation;
+import mx.rpc.xml.SchemaConstants;
+import mx.utils.ObjectProxy;
+import mx.utils.XMLUtil;
+
+use namespace mx_internal;
+
+/**
+ * Dispatched when an Operation invocation returns with SOAP headers in the
+ * response. A HeaderEvent is dispatched for each SOAP header.
+ * @eventType mx.rpc.events.HeaderEvent.HEADER
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+[Event(name="header", type="mx.rpc.events.HeaderEvent")]
+
+[ResourceBundle("rpc")]
+
+/**
+ * An Operation used specifically by WebServices. An Operation is an individual
+ * method on a service. An Operation can be called either by invoking the
+ * function of the same name on the service or by accessing the Operation as a
+ * property on the service and calling the <code>send()</code> method.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class Operation extends AbstractOperation
+{
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Creates a new Operation. This is usually done directly by the MXML
+ * compiler or automatically by the WebService when an unknown operation
+ * has been accessed. It is not recommended that a developer use this
+ * constructor directly.
+ *
+ * @param webService The web service upon which this Operation is invoked.
+ *
+ * @param name The name of this Operation.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function Operation(webService:AbstractService = null, name:String = null)
+ {
+ super(webService, name);
+
+ _resultFormat = "object";
+ _headerFormat = "e4x";
+ _headers = [];
+ log = Log.getLogger("mx.rpc.soap.Operation");
+
+ if (webService)
+ {
+ this.webService = AbstractWebService(webService);
+ log.info("Creating SOAP Operation for {0}", name);
+ }
+
+ // No explicit timeout value by default. The user can set this, and
+ // thus engage a timer for this # of milliseconds on each call. If the
+ // timer fires before the call returns, a fault will be generated.
+ timeout = -1;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ private var resourceManager:IResourceManager =
+ ResourceManager.getInstance();
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // decoder
+ //----------------------------------
+
+ /**
+ * The ISOAPDecoder implementation used by this Operation to decode a SOAP
+ * encoded response into ActionScript.
+ *
+ * @private
+ */
+ public function get decoder():ISOAPDecoder
+ {
+ if (_decoder == null)
+ {
+ _decoder = new SOAPDecoder();
+ _decoder.makeObjectsBindable = makeObjectsBindable;
+ _decoder.ignoreWhitespace = ignoreWhitespace;
+ }
+
+ if (_decoder.wsdlOperation == null)
+ _decoder.wsdlOperation = wsdlOperation;
+
+ return _decoder;
+ }
+
+ /**
+ * @private
+ */
+ public function set decoder(value:ISOAPDecoder):void
+ {
+ _decoder = value;
+ }
+
+
+ //----------------------------------
+ // encoder
+ //----------------------------------
+
+ /**
+ * The ISOAPEncoder implementation used by this Operation to encode
+ * ActionScript input arguments as a SOAP encoded request.
+ *
+ * @private
+ */
+ public function get encoder():ISOAPEncoder
+ {
+ if (_encoder == null)
+ {
+ _encoder = new SOAPEncoder();
+ _encoder.ignoreWhitespace = ignoreWhitespace;
+ }
+
+ if (_encoder.wsdlOperation == null)
+ _encoder.wsdlOperation = wsdlOperation;
+
+ // Tell the encoder to use the xmlSpecialCharsFilter function specified
+ // on the Operation (or Service). If null, encoder will default to its
+ // own implementation.
+ _encoder.xmlSpecialCharsFilter = xmlSpecialCharsFilter;
+
+ return _encoder;
+ }
+
+ /**
+ * @private
+ */
+ public function set encoder(value:ISOAPEncoder):void
+ {
+ _encoder = value;
+ }
+
+
+ //----------------------------------
+ // endpointURI
+ //----------------------------------
+
+ /**
+ * The location of the WebService for this Operation. Normally, the WSDL
+ * specifies the location of the services, but you can set this property to
+ * override that location for the individual Operation.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get endpointURI():String
+ {
+ return _endpointURI ? _endpointURI : webService.endpointURI;
+ }
+
+ public function set endpointURI(uri:String):void
+ {
+ _endpointURI = uri;
+ }
+
+ //----------------------------------
+ // forcePartArrays
+ //----------------------------------
+
+ [Inspectable(defaultValue="false", category="General")]
+ /**
+ * Determines whether or not a single or empty return value for an output
+ * message part that is defined as an array should be returned as an array
+ * containing one (or zero, respectively) elements. This is applicable for
+ * document/literal "wrapped" web services, where one or more of the elements
+ * that represent individual message parts in the "wrapper" sequence could
+ * have the maxOccurs attribute set with a value greater than 1. This is a
+ * hint that the corresponding part should be treated as an array even if
+ * the response contains zero or one values for that part. Setting
+ * forcePartArrays to true will always create an array for parts defined in
+ * this manner, regardless of the number of values returned. Leaving
+ * forcePartArrays as false will only create arrays if two or more elements
+ * are returned.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get forcePartArrays():Boolean
+ {
+ return _forcePartArrays;
+ }
+
+ public function set forcePartArrays(value:Boolean):void
+ {
+ _forcePartArrays = value;
+ }
+
+ //----------------------------------
+ // headerFormat
+ //----------------------------------
+
+ [Inspectable(enumeration="object,e4x,xml,E4X,XML", defaultValue="e4x", category="General")]
+ /**
+ * Determines how the SOAP encoded headers are decoded. A value of
+ * <code>object</code> specifies that each header XML node will be decoded
+ * into a SOAPHeader object, and its <code>content</code> property will be
+ * an object structure as specified in the WSDL document. A value of
+ * <code>xml</code> specifies that the XML will be left as XMLNodes. A
+ * value of <code>e4x</code> specifies that the XML will be accessible
+ * using ECMAScript for XML (E4X) expressions.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get headerFormat():String
+ {
+ if (_headerFormat == null)
+ _headerFormat = "e4x";
+
+ return _headerFormat;
+ }
+
+ public function set headerFormat(hf:String):void
+ {
+ if (hf != null)
+ hf = hf.toLowerCase();
+
+ _headerFormat = hf;
+ }
+
+ //----------------------------------
+ // headers
+ //----------------------------------
+
+ /**
+ * Accessor to an Array of SOAPHeaders that are to be sent on
+ * each invocation of the operation.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get headers():Array
+ {
+ return _headers;
+ }
+
+
+ //----------------------------------
+ // httpHeaders
+ //----------------------------------
+
+ private var _httpHeaders:Object;
+
+ [Inspectable(defaultValue="undefined", category="General")]
+ /**
+ * Custom HTTP headers to be sent to the SOAP endpoint. If multiple
+ * headers need to be sent with the same name the value should be specified
+ * as an Array.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get httpHeaders():Object
+ {
+ if (_httpHeaders != null)
+ return _httpHeaders;
+
+ return AbstractWebService(service).httpHeaders;
+ }
+
+ public function set httpHeaders(value:Object):void
+ {
+ _httpHeaders = value;
+ }
+
+
+ //----------------------------------
+ // ignoreWhitespace
+ //----------------------------------
+
+ [Inspectable(defaultValue="true", category="General")]
+ /**
+ * Determines whether whitespace is ignored when processing XML for a SOAP
+ * encoded request or response. The default is <code>true</code>
+ * and thus whitespace is not preserved. If an XML Schema type definition
+ * specifies a <code>whiteSpace</code> restriction set to
+ * <code>preserve</code> then ignoreWhitespace must first be set to false.
+ * Conversely, if a type <code>whiteSpace</code> restriction is set to
+ * <code>replace</code> or <code>collapse</code> then that setting will
+ * be honored even if ignoreWhitespace is set to false.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get ignoreWhitespace():Boolean
+ {
+ return _ignoreWhitespace;
+ }
+
+ public function set ignoreWhitespace(value:Boolean):void
+ {
+ _ignoreWhitespace = value;
+
+ if (_decoder != null)
+ _decoder.ignoreWhitespace = _ignoreWhitespace;
+
+ if (_encoder != null)
+ _encoder.ignoreWhitespace = _ignoreWhitespace;
+ }
+
+
+ //----------------------------------
+ // makeObjectsBindable
+ //----------------------------------
+
+ [Inspectable(defaultValue="true", category="General")]
+ /**
+ * When this value is true, anonymous objects returned are forced to
+ * bindable objects.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ override public function get makeObjectsBindable():Boolean
+ {
+ if (_makeObjectsBindableSet)
+ {
+ return _makeObjectsBindable;
+ }
+ return AbstractWebService(service).makeObjectsBindable;
+ }
+
+ override public function set makeObjectsBindable(value:Boolean):void
+ {
+ _makeObjectsBindable = value;
+ _makeObjectsBindableSet = true;
+
+ if (_decoder != null)
+ _decoder.makeObjectsBindable = value;
+ }
+
+
+ //----------------------------------
+ // multiplePartsFormat
+ //----------------------------------
+
+ [Inspectable(enumeration="object,array", defaultValue="object", category="General")]
+ /**
+ * Determines the type of the default result object for calls to web services
+ * that define multiple parts in the output message. A value of "object"
+ * specifies that the lastResult object will be an Object with named properties
+ * corresponding to the individual output parts. A value of "array" would
+ * make the lastResult an array, where part values are pushed in the order
+ * they occur in the body of the SOAP message. The default value for document-
+ * literal operations is "object". The default for rpc operations is "array".
+ * The multiplePartsFormat property is applicable only when
+ * resultFormat is "object" and ignored otherwise.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get multiplePartsFormat():String
+ {
+ if (_multiplePartsFormat == null)
+ {
+ // To keep Flex 2.0.1 HF 2+ behavior, we need to determine the
+ // default value based on the style of the operation.
+ if (_wsdlOperation != null && _wsdlOperation.style == "rpc")
+ _multiplePartsFormat = "array";
+ else
+ _multiplePartsFormat = "object";
+ }
+
+ return _multiplePartsFormat;
+ }
+
+ public function set multiplePartsFormat(value:String):void
+ {
+ if (value != null)
+ value = value.toLowerCase();
+
+ _multiplePartsFormat = value;
+ }
+
+ //----------------------------------
+ // request
+ //----------------------------------
+
+ /**
+ * The request of the Operation is an object structure or an XML structure.
+ * If you specify XML, the XML is sent as is. If you pass an object, it is
+ * encoded into a SOAP XML structure.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get request():Object
+ {
+ return this.arguments;
+ }
+
+ public function set request(r:Object):void
+ {
+ this.arguments = r;
+ }
+
+
+ //----------------------------------
+ // resultFormat
+ //----------------------------------
+
+ [Inspectable(enumeration="object,e4x,xml,E4X,XML", defaultValue="object", category="General")]
+ /**
+ * Determines how the Operation result is decoded. A value of
+ * <code>object</code> specifies that the XML will be decoded into an
+ * object structure as specified in the WSDL document. A value of
+ * <code>xml</code> specifies that the XML will be left as XMLNodes. A
+ * value of <code>e4x</code> specifies that the XML will be accessible
+ * using ECMAScript for XML (E4X) expressions.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get resultFormat():String
+ {
+ if (_resultFormat == null)
+ _resultFormat = "object";
+
+ return _resultFormat;
+ }
+
+ public function set resultFormat(rf:String):void
+ {
+ if (rf != null)
+ rf = rf.toLowerCase();
+
+ _resultFormat = rf;
+ }
+
+
+ //----------------------------------
+ // resultHeaders
+ //----------------------------------
+
+ [Bindable("resultForBinding")]
+ /**
+ * The headers that were returned as part of the last execution of this
+ * operation. They match up with the <code>lastResult</code> property and
+ * are the same as the collection of headers that are dispatched
+ * individually as HeaderEvents.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get resultHeaders():Array
+ {
+ return _responseHeaders;
+ }
+
+
+ //----------------------------------
+ // xmlSpecialCharsFilter
+ //----------------------------------
+
+ private var _xmlSpecialCharsFilter:Function;
+
+ /**
+ * Specifies a custom function used to escape XML special characters before
+ * encoding any simple content.
+ * Valid for all operations on the web service unless specifically overwritten
+ * on the operation level.
+ * If no function is provided, the defaults is whatever is set by the
+ * particular implementation of IXMLEncoder.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get xmlSpecialCharsFilter():Function
+ {
+ if (_xmlSpecialCharsFilter != null)
+ return _xmlSpecialCharsFilter;
+
+ return AbstractWebService(service).xmlSpecialCharsFilter;
+ }
+
+ /**
+ * @private
+ */
+ public function set xmlSpecialCharsFilter(func:Function):void
+ {
+ _xmlSpecialCharsFilter = func;
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Internal Properties
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ mx_internal var handleAxisSession:Boolean;
+
+ /**
+ * @private
+ */
+ mx_internal function get wsdlOperation():WSDLOperation
+ {
+ return _wsdlOperation;
+ }
+
+ /**
+ * @private
+ */
+ mx_internal function set wsdlOperation(value:WSDLOperation):void
+ {
+ _wsdlOperation = value;
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Adds a header that is applied only to this Operation. The header can be
+ * provided in a pre-encoded form as an XML instance, or as a SOAPHeader
+ * instance which leaves the encoding up to the internal SOAP encoder.
+ * @param header The SOAP header to add to this Operation.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function addHeader(header:Object):void
+ {
+ _headers.push(header);
+ }
+
+ /**
+ * Adds a header that is applied only to this Operation.
+ * @param qnameLocal the localname for the header QName
+ * @param qnameNamespace the namespace for header QName
+ * @param headerName Name of the header.
+ * @param headerValue Value of the header.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function addSimpleHeader(qnameLocal:String, qnameNamespace:String,
+ headerName:String, headerValue:String):void
+ {
+ var obj:Object = {};
+ obj[headerName] = headerValue;
+ addHeader(new SOAPHeader(new QName(qnameNamespace, qnameLocal), obj));
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ override public function cancel(id:String = null):AsyncToken
+ {
+
+ if (hasPendingInvocations())
+ {
+ if (null == id)
+ {
+ // remove the last pending call
+ return pendingInvocations.pop().token;
+ }
+ // check if id is one of the pending calls
+ for (var i:int = pendingInvocations.length-1; i >= 0; i--)
+ {
+ if (pendingInvocations[i].token.message != null &&
+ pendingInvocations[i].token.message.messageId == id)
+ {
+ var pc:OperationPendingCall = pendingInvocations.splice(i,1)[0];
+ return pc.token;
+ }
+ }
+ }
+ //if the call is not pending, use super
+ return super.cancel(id);
+ }
+
+ /**
+ * Clears the headers for this individual Operation.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function clearHeaders():void
+ {
+ _headers.length = 0;
+ }
+
+ /**
+ * Returns a header if a match is found based on QName localName and URI.
+ * @param qname QName of the SOAPHeader.
+ * @param headerName Name of a header in the SOAPHeader content (Optional)
+ * @return Returns the SOAPHeader.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function getHeader(qname:QName, headerName:String = null):SOAPHeader
+ {
+ var length:uint = _headers.length;
+ for (var i:uint = 0; i < length; i++)
+ {
+ var header:SOAPHeader = SOAPHeader(_headers[i]);
+ if (XMLUtil.qnamesEqual(header.qname, qname))
+ {
+ if (headerName)
+ {
+ if (header.content && header.content[headerName])
+ {
+ return header;
+ }
+ }
+ else
+ {
+ return header;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Removes the header with the given QName from all operations.
+ * @param qname QName of the SOAPHeader.
+ * @param headerName Name of a header in the SOAPHeader content (Optional)
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function removeHeader(qname:QName, headerName:String = null):void
+ {
+ var length:uint = _headers.length;
+ for (var i:uint = 0; i < length; i++)
+ {
+ var header:SOAPHeader = SOAPHeader(_headers[i]);
+ if (XMLUtil.qnamesEqual(header.qname, qname))
+ {
+ if (headerName)
+ {
+ if (header.content && header.content[headerName])
+ {
+ _headers.splice(i, 1);
+ return; // Got it
+ }
+ }
+ else
+ {
+ _headers.splice(i, 1);
+ return; // Got it
+ }
+ }
+ }
+ }
+
+ /**
+ * @private
+ */
+ override public function send(...args:Array):AsyncToken
+ {
+ if (service != null)
+ service.initialize();
+
+ if (webService.convertParametersHandler != null)
+ args = webService.convertParametersHandler(args);
+
+ if (operationManager != null)
+ return operationManager(args);
+
+ var argsToPass:Object = null;
+ if (args && args.length > 0)
+ {
+ if ((args.length == 1) && (args[0] is XMLNode || args[0] is XML))
+ {
+ // special case: handle xml node as single argument and drop
+ // into literal mode.
+ argsToPass = args[0];
+ }
+ else
+ {
+ argsToPass = args;
+ }
+ }
+ //Syntactically pre-registered
+ else if (this.arguments)
+ {
+ argsToPass = this.arguments;
+ }
+
+ var combinedHeaders:Array = [];
+
+ if (_headers)
+ {
+ combinedHeaders = combinedHeaders.concat(_headers);
+ }
+
+ if (webService.headers)
+ {
+ combinedHeaders = combinedHeaders.concat(webService.headers);
+ }
+
+ //create an empty message and a token to hold it
+ var message:SOAPMessage = new SOAPMessage();
+ var token:AsyncToken = new AsyncToken(message);
+
+ var pc:OperationPendingCall = new OperationPendingCall(argsToPass, combinedHeaders, token);
+
+ if (webService.ready)
+ {
+ invokePendingCall(pc);
+ }
+ else // if (!webService.wsdlFault)
+ {
+ log.debug("Queueing SOAP operation {0}", name);
+ if (!pendingInvocations)
+ {
+ pendingInvocations = [];
+ }
+ pendingInvocations.push(pc);
+ }
+ // FIXME: Handle WSDL error case
+ /*
+ else
+ {
+ var errMsg:String = "Cannot invoke method " + name + " as WSDL did not load successfully";
+ dispatchRpcEvent(createFaultEvent("Client.InvalidWSDL", errMsg));
+ }
+ */
+
+ return pc.token;
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Internal Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ mx_internal function hasPendingInvocations():Boolean
+ {
+ return pendingInvocations != null && pendingInvocations.length > 0;
+ }
+
+ /**
+ * @private
+ */
+ mx_internal function invokeAllPending():void
+ {
+ if (hasPendingInvocations())
+ {
+ for (var i:int = 0; i < pendingInvocations.length; ++i)
+ {
+ invokePendingCall(pendingInvocations[i]);
+ }
+ pendingInvocations = null;
+ }
+ }
+
+ /**
+ * We now SOAP encode the pending call and send the request.
+ *
+ * @private
+ */
+ mx_internal function invokePendingCall(pc:OperationPendingCall):void
+ {
+ log.debug("Invoking SOAP operation {0}", name);
+
+ startTime = new Date();
+
+ var message:SOAPMessage = SOAPMessage(pc.token.message);
+ var soap:XML;
+
+ if (wsdlOperation == null)
+ {
+ log.debug("No operation found {0}", name);
+ dispatchRpcEvent(createFaultEvent("Client.NoSuchMethod", "Couldn't find method '" + name + "' in service."));
+ return;
+ }
+
+ try
+ {
+ soap = encoder.encodeRequest(pc.args, pc.headers);
+ }
+ catch(fault:Fault)
+ {
+ dispatchRpcEvent(FaultEvent.createEvent(fault));
+ return;
+ }
+ catch(error:Error)
+ {
+ var errorMsg:String = error.message ? error.message : "";
+ var fault2:Fault = new Fault("EncodingError", errorMsg);
+ var faultEvent:FaultEvent = FaultEvent.createEvent(fault2);
+ dispatchRpcEvent(faultEvent);
+ return;
+ }
+
+ message.httpHeaders = httpHeaders;
+ if (message.getSOAPAction() == null)
+ message.setSOAPAction(wsdlOperation.soapAction);
+ message.body = soap.toXMLString();
+ message.url = endpointURI;
+ if (NetworkMonitor.isMonitoring())
+ {
+ message.recordHeaders = true;
+ }
+
+ invoke(message, pc.token);
+ }
+
+ /**
+ * We intercept faults as the SOAP response content may still been present
+ * in the message body.
+ *
+ * @private
+ */
+ override mx_internal function processFault(message:IMessage, token:AsyncToken):Boolean
+ {
+ var dispatchFaultEvent:Boolean = true;
+
+ if (message != null && message.body != null)
+ {
+ dispatchFaultEvent = processSOAP(message, token);
+ }
+
+ return dispatchFaultEvent;
+ }
+
+ /**
+ * We decode the SOAP encoded response and update the result and response
+ * headers (if any).
+ *
+ * @private
+ */
+ override mx_internal function processResult(message:IMessage, token:AsyncToken):Boolean
+ {
+ if (processSOAP(message, token))
+ {
+ if (webService.convertResultHandler != null)
+ _result = webService.convertResultHandler(_result, this);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @private
+ */
+ mx_internal function processSOAP(message:IMessage, token:AsyncToken):Boolean
+ {
+ var body:Object = message.body;
+ var eventDispatchRequired:Boolean = true;
+
+ try
+ {
+ var stringResult:String = String(body);
+ decoder.resultFormat = resultFormat;
+ decoder.headerFormat = headerFormat;
+ decoder.multiplePartsFormat = multiplePartsFormat;
+ decoder.forcePartArrays = forcePartArrays;
+
+ var soapResult:SOAPResult = decoder.decodeResponse(stringResult);
+
+ // Reset result
+ _result = null;
+
+ // Expose headers for the bindable property "resultHeaders" as
+ // well as RPC fault and result events...
+ _responseHeaders = soapResult.headers;
+
+ // Process headers for both result and fault
+ eventDispatchRequired = processHeaders(_responseHeaders, token, message);
+
+ // Handle faults
+ if (soapResult.isFault)
+ {
+ var faults:Array = soapResult.result as Array;
+ for each (var soapFault:Fault in faults)
+ {
+ soapFault.content = body;
+ dispatchRpcEvent(FaultEvent.createEvent(soapFault, token, message));
+ }
+ eventDispatchRequired = false;
+ }
+
+ if (eventDispatchRequired)
+ _result = soapResult.result;
+ }
+ catch (fault:Fault)
+ {
+ fault.content = body;
+ dispatchRpcEvent(FaultEvent.createEvent(fault, token, message));
+ eventDispatchRequired = false;
+ }
+ catch (error:Error)
+ {
+ var errorMsg:String = error.message != null ? error.message : "";
+ var fault2:Fault = new Fault("DecodingError", errorMsg);
+ fault2.content = body;
+ var faultEvent:FaultEvent = FaultEvent.createEvent(fault2, token, message);
+ dispatchRpcEvent(faultEvent);
+ eventDispatchRequired = false;
+ }
+
+ return eventDispatchRequired;
+ }
+
+ /**
+ * Checks SOAP response headers and enforces any mustUnderstand attributes
+ * by checking that a listener exists for the "header" event. If we're
+ * honoring Axis sessions then we also look out for for the sessionID
+ * header and add it to the Operation's corresponding service for
+ * subsequent invocations. Finally, the header is dispatched as a
+ * HeaderEvent. If no problems are encountered the method simply returns
+ * true.
+ *
+ * @private
+ */
+ protected function processHeaders(responseHeaders:Array, token:AsyncToken, message:IMessage):Boolean
+ {
+ if (responseHeaders != null)
+ {
+ for (var i:uint = 0; i < responseHeaders.length; i++)
+ {
+ var header:Object = responseHeaders[i];
+ var mustUnderstand:Boolean;
+ var headerQName:QName;
+ var headerContent:Object;
+
+ if (header is XML)
+ {
+ var headerXML:XML = header as XML;
+
+ mustUnderstand = headerXML.@mustUnderstand == "1" ? true : false;
+ headerQName = headerXML.name() as QName;
+
+ if (headerXML.hasComplexContent())
+ headerContent = headerXML.elements();
+ else
+ headerContent = headerXML.text();
+
+ }
+ else if (header is SOAPHeader)
+ {
+ mustUnderstand = header.mustUnderstand;
+ headerQName = header.qname;
+ headerContent = header.content;
+ }
+
+ // If header was either XML or SOAPHeader, headerQName would
+ // be set by now.
+ if (headerQName != null)
+ {
+ if (mustUnderstand == true)
+ {
+ if (!hasEventListener(HeaderEvent.HEADER) && !service.hasEventListener(HeaderEvent.HEADER))
+ {
+ var msg:String = resourceManager.getString(
+ "rpc", "noListenerForHeader",
+ [ headerQName ]);
+ var fault:Fault = new Fault("Client.MustUnderstand", msg);
+ var faultEvent:FaultEvent = FaultEvent.createEvent(fault, token, message);
+ dispatchRpcEvent(faultEvent);
+ return false;
+ }
+ }
+
+ if (handleAxisSession)
+ {
+ // pass the session id on to any request made on this proxy
+ if (headerQName != null && headerQName.localName == "sessionID" &&
+ headerQName.uri == "http://xml.apache.org/axis/session")
+ {
+ var newHeader:SOAPHeader = new SOAPHeader(headerQName, headerContent);
+ webService.addHeader(newHeader);
+ }
+ }
+
+ var headerEvent:HeaderEvent = HeaderEvent.createEvent(header, token, message);
+ dispatchRpcEvent(headerEvent);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @private
+ */
+ override mx_internal function setService(value:AbstractService):void
+ {
+ super.setService(value);
+ webService = AbstractWebService(value);
+ }
+
+ /**
+ * @private
+ */
+ protected function createFaultEvent(faultCode:String = null, faultString:String = null, faultDetail:String = null):FaultEvent
+ {
+ var fault:Fault = new Fault(faultCode, faultString, faultDetail);
+ var faultEvent:FaultEvent = FaultEvent.createEvent(fault);
+ return faultEvent;
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ // Backing variables for public getter/setters
+ private var _endpointURI:String;
+ private var _forcePartArrays:Boolean = false; // Flex 2.0.1 HF2+ behavior is false
+ private var _headerFormat:String;
+ private var _headers:Array;
+ private var _resultFormat:String;
+ private var _makeObjectsBindableSet:Boolean;
+ private var _multiplePartsFormat:String;
+
+ // Internal properties
+ //any vars here with underscores minimally have a getter or setter
+ private var _decoder:ISOAPDecoder;
+ private var _encoder:ISOAPEncoder;
+ private var _ignoreWhitespace:Boolean = true;
+ private var log:ILogger;
+ private var pendingInvocations:Array;
+ private var startTime:Date;
+ private var timeout:int;
+ private var webService:AbstractWebService;
+
+ /**
+ * @private
+ */
+ protected var _wsdlOperation:mx.rpc.wsdl.WSDLOperation;
+}
+}
+
+import mx.rpc.AsyncToken;
+
+/**
+ * @private
+ */
+class OperationPendingCall
+{
+ public var args:*;
+ public var headers:Array;
+ public var token:AsyncToken;
+
+ public function OperationPendingCall(args:*, headers:Array, token:AsyncToken)
+ {
+ super();
+ this.args = args;
+ this.headers = headers;
+ this.token = token;
+ }
+}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/SOAPConstants.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/SOAPConstants.as
new file mode 100644
index 0000000..b509e71
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/SOAPConstants.as
@@ -0,0 +1,351 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap
+{
+
+import org.apache.royale.reflection.getDefinitionByName;
+import org.apache.royale.reflection.getQualifiedClassName;
+
+import mx.rpc.soap.types.ICustomSOAPType;
+import mx.rpc.soap.types.MapType;
+import mx.rpc.soap.types.QueryBeanType;
+import mx.rpc.soap.types.RowSetType;
+import mx.rpc.soap.types.SOAPArrayType;
+import mx.rpc.soap.types.ApacheDocumentType;
+import mx.rpc.soap.types.DataSetType;
+import mx.utils.StringUtil;
+import mx.utils.URLUtil;
+
+[ExcludeClass]
+
+/**
+ * A helper class listing all of the constants required to encode and decode
+ * SOAP messages.
+ *
+ * @private
+ */
+public class SOAPConstants
+{
+ public function SOAPConstants(envelopeNS:Namespace = null, encodingNS:Namespace = null)
+ {
+ super();
+
+ // Default to SOAP 1.1
+ if (envelopeNS == null)
+ envelopeNS = new Namespace(SOAP_ENV_PREFIX, SOAP_ENVELOPE_URI);
+
+ if (encodingNS == null)
+ encodingNS = new Namespace(SOAP_ENC_PREFIX, SOAP_ENCODING_URI);
+
+ _envelopeNS = envelopeNS;
+ _encodingNS = encodingNS;
+
+ envelopeQName = new QName(envelopeURI, "Envelope");
+ headerQName = new QName(envelopeURI, "Header");
+ bodyQName = new QName(envelopeURI, "Body");
+ faultQName = new QName(envelopeURI, "Fault");
+ actorQName = new QName(envelopeURI, "actor");
+ mustUnderstandQName = new QName(envelopeURI, "mustUnderstand");
+
+ soapencArrayQName = new QName(encodingURI, "Array");
+ soapencArrayTypeQName = new QName(encodingURI, "arrayType");
+ soapencRefQName = new QName(encodingURI, "multiRef");
+ soapoffsetQName = new QName(encodingURI, "offset");
+ soapBase64QName = new QName(encodingURI, "base64");
+
+ // Initialize custom SOAP type handlers
+ if (!customTypesInitialized)
+ initCustomSOAPTypes();
+
+ // Register Types with version-specific QNames
+ registerCustomSOAPType(soapencArrayQName, SOAPArrayType);
+ registerCustomSOAPType(soapencArrayTypeQName, SOAPArrayType);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ public function get contentType():String
+ {
+ return _contentType;
+ }
+
+ public function get encodingURI():String
+ {
+ return encodingNamespace.uri;
+ }
+
+ public function get encodingNamespace():Namespace
+ {
+ return _encodingNS;
+ }
+
+ public function get envelopeURI():String
+ {
+ return envelopeNamespace.uri;
+ }
+
+ public function get envelopeNamespace():Namespace
+ {
+ return _envelopeNS;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ public function getSOAPEncodingToken(type:QName):String
+ {
+ return encodingNamespace.prefix + ":" + type.localName;
+ }
+
+ public static function getConstants(xml:XML = null):SOAPConstants
+ {
+ var envelopeNS:Namespace;
+ var encodingNS:Namespace;
+
+ if (xml != null)
+ {
+ var nsArray:Array = xml.namespaceDeclarations();
+ for each (var ns:Namespace in nsArray)
+ {
+ if (URLUtil.urisEqual(ns.uri, SOAP_ENVELOPE_URI)
+ || URLUtil.urisEqual(ns.uri, SOAP12_ENVELOPE_URI))
+ {
+ envelopeNS = ns;
+ }
+ else if (URLUtil.urisEqual(ns.uri, SOAP_ENCODING_URI)
+ || URLUtil.urisEqual(ns.uri, SOAP12_ENCODING_URI))
+ {
+ encodingNS = ns;
+ }
+ }
+ }
+
+ // Default to SOAP 1.1
+ if (envelopeNS == null)
+ envelopeNS = new Namespace(SOAP_ENV_PREFIX, SOAP_ENVELOPE_URI);
+
+ if (encodingNS == null)
+ encodingNS = new Namespace(SOAP_ENC_PREFIX, SOAP_ENCODING_URI);
+
+ if (constantsCache == null)
+ constantsCache = {};
+
+ var constants:SOAPConstants = constantsCache[envelopeNS.uri];
+ if (constants == null)
+ {
+ constants = new SOAPConstants(envelopeNS, encodingNS);
+ constantsCache[envelopeNS.uri] = constants;
+ }
+
+ return constants;
+ }
+
+ public static function isSOAPEncodedType(type:QName):Boolean
+ {
+ var uri:String = (type != null) ? type.uri : null;
+ if (uri != null)
+ {
+ if (URLUtil.urisEqual(uri, SOAPConstants.SOAP_ENCODING_URI) ||
+ URLUtil.urisEqual(uri, SOAPConstants.SOAP12_ENCODING_URI))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Looks for an ICustomSOAPType implementation for the given type.
+ *
+ * @return A new instance of the ICustomSOAPType, if registered, otherwise
+ * null.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function getCustomSOAPType(type:QName):ICustomSOAPType
+ {
+ var soapType:ICustomSOAPType;
+ if (type != null)
+ {
+ var key:String = getKey(type);
+ var definitionName:String = typeMap[key] as String;
+
+ if (definitionName != null)
+ {
+ try
+ {
+ var c:Class = getDefinitionByName(definitionName) as Class;
+ soapType = new c() as ICustomSOAPType;
+ }
+ catch(e:Error)
+ {
+ }
+ }
+ }
+ return soapType;
+ }
+
+ /**
+ * Maps a type QName to a definition of an ISOAPType implementation.
+ * The definition can be a String representation of the fully qualified
+ * class name, an Object instance or the Class instance itself.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function registerCustomSOAPType(type:QName, definition:*):void
+ {
+ var key:String = getKey(type);
+
+ var definitionName:String;
+
+ if (definition is String)
+ definitionName = definition as String;
+ else
+ definitionName = getQualifiedClassName(definition);
+
+ typeMap[key] = definitionName;
+ }
+
+ /**
+ * Removes the ICustomSOAPType from the registry for the given type.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function unregisterCustomSOAPType(type:QName):void
+ {
+ if (type != null)
+ {
+ var key:String = getKey(type);
+ delete typeMap[key];
+ }
+ }
+
+ private static function getKey(type:QName):String
+ {
+ var key:String;
+ if (type.uri == null || type.uri == "")
+ key = type.localName;
+ else
+ key = type.toString();
+ return key;
+ }
+
+ private static function initCustomSOAPTypes():void
+ {
+ registerCustomSOAPType(queryBeanQName, QueryBeanType);
+ registerCustomSOAPType(mapQName, MapType);
+ registerCustomSOAPType(rowSetQName, RowSetType);
+ registerCustomSOAPType(documentQName, ApacheDocumentType);
+ registerCustomSOAPType(diffgramQName, DataSetType);
+ customTypesInitialized = true;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ // SOAP Envelope QNames
+ public var envelopeQName:QName;
+ public var headerQName:QName;
+ public var bodyQName:QName;
+ public var faultQName:QName;
+ public var actorQName:QName;
+ public var mustUnderstandQName:QName;
+
+ // SOAP Encoding QNames
+ public var soapencArrayQName:QName;
+ public var soapencArrayTypeQName:QName;
+ public var soapencRefQName:QName;
+ public var soapoffsetQName:QName;
+ public var soapBase64QName:QName;
+
+ private var _contentType:String;
+ private var _envelopeNS:Namespace;
+ private var _encodingNS:Namespace;
+
+ private static var constantsCache:Object;
+ private static var customTypesInitialized:Boolean;
+ private static var typeMap:Object = {};
+
+ //--------------------------------------------------------------------------
+ //
+ // Constants
+ //
+ //--------------------------------------------------------------------------
+
+ // ColdFusion SOAP Type QNames
+ public static const queryBeanQName:QName = new QName(COLD_FUSION_URI, "QueryBean");
+
+ // Apache SOAP Type QNames
+ public static const rowSetQName:QName = new QName(APACHE_SOAP_URI, "RowSet");
+ public static const mapQName:QName = new QName(APACHE_SOAP_URI, "Map");
+ public static const documentQName:QName = new QName(APACHE_SOAP_URI, "Document");
+
+ // MS .NET DataSet Constants
+ public static const msdataURI:String = "urn:schemas-microsoft-com:xml-msdata";
+ public static const diffgramQName:QName = new QName("urn:schemas-microsoft-com:xml-diffgram-v1", "diffgram");
+
+ // SOAP Envelope Constants
+ public static const SOAP_ENVELOPE_URI:String = "http://schemas.xmlsoap.org/soap/envelope/";
+ public static const SOAP12_ENVELOPE_URI:String = "http://www.w3.org/2002/12/soap-envelope";
+ public static const XML_DECLARATION:String = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
+
+ // SOAP Encoding Constants
+ public static const SOAP_ENCODING_URI:String = "http://schemas.xmlsoap.org/soap/encoding/";
+ public static const SOAP12_ENCODING_URI:String = "http://www.w3.org/2002/12/soap-encoding";
+ public static const SOAP_CONTENT_TYPE:String = "text/xml; charset=utf-8";
+ public static const SOAP12_CONTENT_TYPE:String = "application/soap+xml; charset=utf-8";
+
+ public static const RPC_STYLE:String = "rpc";
+ public static const DOC_STYLE:String = "document";
+ public static const WRAPPED_STYLE:String = "wrapped";
+ public static const USE_ENCODED:String = "encoded";
+ public static const USE_LITERAL:String = "literal";
+ public static const DEFAULT_OPERATION_STYLE:String = "document";
+ public static const DEFAULT_USE:String = "literal";
+
+ // Default namespace prefixes
+ public static const SOAP_ENV_PREFIX:String = "SOAP-ENV";
+ public static const SOAP_ENC_PREFIX:String = "SOAP-ENC";
+
+ // Custom SOAP Type Constants
+ public static const COLD_FUSION_URI:String = "http://rpc.xml.coldfusion";
+ public static const APACHE_SOAP_URI:String = "http://xml.apache.org/xml-soap";
+}
+
+}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/SOAPDecoder.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/SOAPDecoder.as
new file mode 100644
index 0000000..77aa7f6
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/SOAPDecoder.as
@@ -0,0 +1,1031 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap
+{
+
+import flash.utils.getTimer;
+import flash.xml.XMLDocument;
+import flash.xml.XMLNode;
+
+import mx.logging.ILogger;
+import mx.logging.Log;
+import mx.rpc.soap.types.ICustomSOAPType;
+import mx.rpc.wsdl.WSDLEncoding;
+import mx.rpc.wsdl.WSDLMessagePart;
+import mx.rpc.wsdl.WSDLOperation;
+import mx.rpc.xml.ContentProxy;
+import mx.rpc.xml.DecodingContext;
+import mx.rpc.xml.SchemaConstants;
+import mx.rpc.xml.SchemaDatatypes;
+import mx.rpc.xml.TypeIterator;
+import mx.rpc.xml.XMLDecoder;
+import mx.utils.StringUtil;
+import mx.utils.URLUtil;
+import mx.utils.XMLUtil;
+import mx.utils.object_proxy;
+
+use namespace object_proxy;
+
+[ExcludeClass]
+
+/**
+ * Decodes the SOAP response for a particular operation
+ *
+ * @private
+ */
+public class SOAPDecoder extends XMLDecoder implements ISOAPDecoder
+{
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ public function SOAPDecoder()
+ {
+ super();
+ log = Log.getLogger("mx.rpc.soap.SOAPDecoder");
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Controls whether the decoder supports the legacy literal style encoding
+ * for generic compound type (such as arrays). Older document-literal SOAP
+ * implementations sometimes encoded unbounded element sequences with
+ * generic child <code>item</code> elements instead of repeating the
+ * value element itself. The default is true.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var supportGenericCompoundTypes:Boolean = false;
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ public function get forcePartArrays():Boolean
+ {
+ return _forcePartArrays;
+ }
+
+ public function set forcePartArrays(value:Boolean):void
+ {
+ _forcePartArrays = value;
+ }
+
+ public function get headerFormat():String
+ {
+ return _headerFormat;
+ }
+
+ public function set headerFormat(value:String):void
+ {
+ _headerFormat = value;
+ }
+
+ /**
+ * Determines whether the decoder should ignore whitespace when processing
+ * the XML of a SOAP encoded response. The default is <code>true</code>
+ * and thus whitespace is not preserved. If an XML Schema type definition
+ * specifies a <code>whiteSpace</code> restriction set to
+ * <code>preserve</code> then ignoreWhitespace must first be set to false.
+ * Conversely, if a type <code>whiteSpace</code> restriction is set to
+ * <code>replace</code> or <code>collapse</code> then that setting will
+ * be honored even if ignoreWhitespace is set to false.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get ignoreWhitespace():Boolean
+ {
+ return _ignoreWhitespace;
+ }
+
+ public function set ignoreWhitespace(value:Boolean):void
+ {
+ _ignoreWhitespace = value;
+ }
+
+ public function get multiplePartsFormat():String
+ {
+ return _multiplePartsFormat;
+ }
+
+ public function set multiplePartsFormat(value:String):void
+ {
+ _multiplePartsFormat = value;
+ }
+
+ public function get resultFormat():String
+ {
+ return _resultFormat;
+ }
+
+ public function set resultFormat(value:String):void
+ {
+ _resultFormat = value;
+ }
+
+ public function get schemaConstants():SchemaConstants
+ {
+ return schemaManager.schemaConstants;
+ }
+
+ public function get soapConstants():SOAPConstants
+ {
+ return wsdlOperation.soapConstants;
+ }
+
+ public function get wsdlOperation():WSDLOperation
+ {
+ return _wsdlOperation;
+ }
+
+ public function set wsdlOperation(value:WSDLOperation):void
+ {
+ _wsdlOperation = value;
+ schemaManager = _wsdlOperation.schemaManager;
+ }
+
+ /**
+ * @private
+ */
+ protected function get inputEncoding():WSDLEncoding
+ {
+ var encoding:WSDLEncoding;
+ if (_wsdlOperation.inputMessage != null)
+ encoding = _wsdlOperation.inputMessage.encoding;
+ else
+ encoding = new WSDLEncoding();
+ return encoding;
+ }
+
+ /**
+ * @private
+ */
+ protected function get outputEncoding():WSDLEncoding
+ {
+ var encoding:WSDLEncoding;
+ if (_wsdlOperation.outputMessage != null)
+ encoding = _wsdlOperation.outputMessage.encoding;
+ else
+ encoding = new WSDLEncoding();
+ return encoding;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods - SOAP Decoding
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Decodes a SOAP response into a result and headers.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function decodeResponse(response:*):SOAPResult
+ {
+ var soapResult:SOAPResult;
+ var responseString:String;
+
+ if (response is XML)
+ responseString = XML(response).toXMLString();
+ else
+ responseString = String(response);
+
+ var startTime:int = getTimer();
+
+ log.info("Decoding SOAP response");
+
+ // Reset the decoder state to clear contexts for schema types, etc.
+ reset();
+
+ if (responseString != null)
+ {
+ log.debug("Encoded SOAP response {0}", responseString);
+
+ // Keep track of the previous ignoreWhitespace setting (as it is
+ // unfortunately a static API on the intrinsic XML type) so we
+ // can set it back to its original state once we're finished.
+ var oldIgnoreWhitespace:Boolean = XML.ignoreWhitespace;
+ try
+ {
+ // Work around Flash Player bug 192355 by removing whitespace
+ // between processing instructions and the root tag before
+ // constructing an XML instance of the SOAP response.
+ responseString = responseString.replace(PI_WHITESPACE_PATTERN, "?><");
+ responseString = StringUtil.trim(responseString);
+ XML.ignoreWhitespace = ignoreWhitespace;
+ var responseXML:XML = new XML(responseString);
+
+ soapResult = decodeEnvelope(responseXML);
+ }
+ finally
+ {
+ XML.ignoreWhitespace = oldIgnoreWhitespace;
+ }
+ }
+
+ log.info("Decoded SOAP response into result [{0} millis]", getTimer() - startTime);
+ return soapResult;
+ }
+
+ protected function decodeEnvelope(responseXML:XML):SOAPResult
+ {
+ log.debug("Decoding SOAP response envelope");
+ var soapResult:SOAPResult = new SOAPResult();
+
+ var envNS:Namespace;
+
+ if (responseXML != null)
+ {
+ envNS = responseXML.namespace();
+ }
+
+ if (envNS == null)
+ {
+ throw new Error("SOAP Response cannot be decoded. Raw response: " + responseXML);
+ }
+ else if (envNS.uri != SOAPConstants.SOAP_ENVELOPE_URI)
+ {
+ throw new Error("SOAP Response Version Mismatch");
+ }
+ else
+ {
+ // Set the namespaces and the Schema uri for the decoder.
+ var schemaConst:SchemaConstants;
+ var nsArray:Array = responseXML.inScopeNamespaces();
+ for each (var ns:Namespace in nsArray)
+ {
+ schemaManager.namespaces[ns.prefix] = ns;
+ }
+
+ // SOAP Headers
+ var headerXML:XML = responseXML[soapConstants.headerQName][0];
+ if (headerXML != null)
+ {
+ soapResult.headers = decodeHeaders(headerXML);
+ }
+ // SOAP Body
+ var bodyXML:XML = responseXML[soapConstants.bodyQName][0];
+
+ if (bodyXML == null || bodyXML.hasComplexContent() == false || bodyXML.children().length() <= 0)
+ {
+ soapResult.result = undefined;
+ }
+ else
+ {
+ // Check for SOAP faults for all resultFormats
+ var faultXMLList:XMLList = bodyXML[soapConstants.faultQName];
+ if (faultXMLList.length() > 0)
+ {
+ soapResult.isFault = true;
+ soapResult.result = decodeFaults(faultXMLList);
+ }
+ else
+ {
+ if (resultFormat == "object")
+ {
+ decodeBody(bodyXML, soapResult);
+ }
+ else if (resultFormat == "e4x")
+ {
+ // Return the children as an XMLList.
+ soapResult.result = bodyXML.children();
+ }
+ else if (resultFormat == "xml")
+ {
+ // Return the children as an Array of XMLNode
+ // or String for text children
+ var bodyArray:Array = [];
+ var bodyXMLList:XMLList = bodyXML.children();
+ for each (var bodyChild:XML in bodyXMLList)
+ {
+ var nodeKind:String = bodyChild.nodeKind();
+ if (nodeKind == "element")
+ {
+ var xmlDoc:XMLDocument = new XMLDocument(bodyChild.toString());
+ var xmlNode:XMLNode = xmlDoc.firstChild;
+ bodyArray.push(xmlNode);
+ }
+ else if (nodeKind == "text")
+ {
+ bodyArray.push(bodyChild.toString());
+ }
+ }
+ soapResult.result = bodyArray;
+ }
+ }
+ }
+ }
+
+ return soapResult;
+ }
+
+ /**
+ * Decodes the response SOAP Body. The contents may either be the encoded
+ * output parameters, or a collection of SOAP faults.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ protected function decodeBody(bodyXML:XML, soapResult:SOAPResult):void
+ {
+ log.debug("Decoding SOAP response body");
+ var result:*;
+ document = bodyXML;
+
+ // Pre-process encoded body.
+ preProcessXML(bodyXML);
+
+ // Check for operations without an output message
+ if (wsdlOperation.outputMessage == null)
+ {
+ soapResult.result = undefined;
+ return;
+ }
+
+ // Decode WSDL output message parts
+ var parts:Array = wsdlOperation.outputMessage.parts;
+
+ // Check for operations with a void return type
+ if (parts == null || parts.length == 0)
+ {
+ soapResult.result = undefined;
+ return;
+ }
+
+ var outputMessageXML:XML = bodyXML;
+ if (wsdlOperation.style == SOAPConstants.RPC_STYLE)
+ {
+ // Unwrap the output message from the operation; both RPC encoded and literal wrap.
+ outputMessageXML = outputMessageXML.elements()[0];
+ }
+ else if (outputEncoding.useStyle == SOAPConstants.USE_LITERAL && wsdlOperation.outputMessage.isWrapped == true)
+ {
+ // Get the outputMessage definition and (more importantly) move
+ // down a level into the schema stack.
+ var wrappedDefinition:XML = schemaManager.getNamedDefinition(wsdlOperation.outputMessage.wrappedQName,
+ constants.complexTypeQName,
+ constants.elementTypeQName);
+
+ // TODO: Ensure that throwing this error doesn't break compatibility
+ // if (wrappedDefinition == null)
+ // throw new Error("Cannot find definition for wrapped response type '" + wsdlOperation.outputMessage.wrappedQName + "'");
+
+ // Unwrap the output message only if this is wrapped literal.
+ outputMessageXML = outputMessageXML.elements()[0];
+ }
+
+ // The "literal" use style may define a part using a type or
+ // element, the "encoded" use style always defines a part with a
+ // type.
+ for each (var part:WSDLMessagePart in parts)
+ {
+ var encodedPartValues:XMLList;
+ var encodedPartValue:XML;
+ var decodedPart:*;
+ var partQName:QName;
+ var partType:QName;
+ var partDefinition:XML;
+
+ // If we have an element, use that to find the part
+ if (part.element != null)
+ {
+ if (outputMessageXML.hasComplexContent())
+ encodedPartValues = outputMessageXML.elements(part.element);
+ else
+ encodedPartValues = outputMessageXML.text();
+ partQName = part.element;
+ partType = null;
+ }
+ // Otherwise, find the part by name and decode using the
+ // specified type definition
+ else
+ {
+ partType = part.type;
+ partDefinition = part.definition;
+
+ if (outputMessageXML.hasComplexContent())
+ {
+ if (outputEncoding.useStyle == SOAPConstants.USE_ENCODED)
+ {
+ // First, look for the part with an unqualified name
+ partQName = new QName("", part.name.localName);
+ encodedPartValues = outputMessageXML.elements(partQName);
+
+ if (encodedPartValues.length() == 0)
+ {
+ // HACK: Sometimes the soap:body namespace attribute
+ // is used to qualify parts under the operation
+ // wrapper, so we then look with this in mind...
+ var encodedNamespace:String = outputEncoding.namespaceURI;
+ partQName = new QName(encodedNamespace, part.name.localName);
+ encodedPartValues = outputMessageXML.elements(partQName);
+
+ // HACK: Sometimes the inputEncoding soap:body
+ // namespace attribute is incorrectly used
+ // for the output message parts too...
+ if (encodedPartValues.length() == 0)
+ {
+ encodedNamespace = inputEncoding.namespaceURI;
+ partQName = new QName(encodedNamespace, part.name.localName);
+ encodedPartValues = outputMessageXML.elements(partQName);
+ }
+ }
+ }
+ else
+ {
+ encodedPartValues = outputMessageXML.elements(part.name);
+ }
+ }
+ else
+ {
+ encodedPartValues = outputMessageXML.text();
+ }
+ }
+
+ for each (encodedPartValue in encodedPartValues)
+ {
+ decodedPart = decode(encodedPartValue, partQName, partType, partDefinition);
+
+ // Handle multiple output parts separately...
+ if (parts.length > 1)
+ {
+ // Map multiple parts to named properties on the result object
+ if (multiplePartsFormat == "object")
+ {
+ // Create the result object, if not created already
+ // (this is the first part we have seen so far)
+ if (result == null)
+ {
+ // The QName of the element that contains the part
+ // values is used to look up a registered AS type
+ // for the result object. For RPC operations the
+ // QName will be the full operation name. For Doc/Lit
+ // wrapped the QName will be the same as the
+ // outputMessage.wrappedQName. For Doc/Lit bare
+ // the QName will be soap:Body.
+ result = createContent(outputMessageXML.name() as QName);
+ result.isSimple = false;
+ }
+
+ if (result[part.name.localName] == null)
+ {
+ // We need to create an array for this part's values
+ // if there are > 1 encodedPartValues, or we are
+ // forcingPartArrays for parts defined with maxOccurs>1
+ // regardless of number of values.
+ var partMaxOccurs:uint = getMaxOccurs(partDefinition);
+ if ((partMaxOccurs > 1 && forcePartArrays)
+ || encodedPartValues.length() > 1)
+ {
+ result[part.name.localName] = createIterableValue(part.type);
+ }
+ }
+
+ // If we have created an iterable container, this part
+ // value needs to be pushed on it
+ if (TypeIterator.isIterable(result[part.name.localName]))
+ TypeIterator.push(result[part.name.localName], decodedPart);
+ // Otherwise just assign the single value to the named property.
+ else
+ result[part.name.localName] = decodedPart;
+ }
+ else if (multiplePartsFormat == "array")
+ {
+ // If multiplePartsFormat == "array", we return each part
+ // as an element in an Array (or some registered collection)
+ if (result == null)
+ {
+ // If this is the first part/value, we create the
+ // array (or typed collection based on the container
+ // element's QName)
+ result = createIterableValue(outputMessageXML.name());
+ }
+ TypeIterator.push(result, decodedPart);
+ }
+ }
+ else
+ {
+ // Single output part. Create result object if not created.
+ if (result == null)
+ {
+ // The result object with only one part becomes the part
+ // itself. The type of the result object is the type of
+ // the part (if the part specifies a type).
+ var sinlgePartResultType:QName = partType;
+
+ // If the part specifies an element, the type of the result
+ // object is looked up based on the element QName.
+ if (sinlgePartResultType == null)
+ sinlgePartResultType = part.element;
+
+ // If neither a type, nor element is specified (rare case
+ // where part becomes anyType), the part.name is used to
+ // look up a strong type for the result object.
+ if (sinlgePartResultType == null)
+ sinlgePartResultType = part.name;
+
+ var singlePartMaxOccurs:uint = getMaxOccurs(partDefinition);
+ if ((singlePartMaxOccurs > 1 && forcePartArrays)
+ || encodedPartValues.length() > 1)
+ {
+ // If more than one value was returned for a single
+ // output part, or the part is defined with maxOccurs > 1,
+ // we treat it as an array of values. The appropriate
+ // IList class is created based on the singlePartResultType
+ result = createIterableValue(sinlgePartResultType);
+ }
+ else
+ {
+ // decodedPart will already be an instance of the
+ // required strong type (or ObjectProxy or Object).
+ // If the single part has a single value, the result
+ // object itself becomes that value, so we only need
+ // a content proxy here.
+ result = createContent();
+ }
+ }
+
+ if (TypeIterator.isIterable(result))
+ {
+ // Push multiple values to the iterable result
+ TypeIterator.push(result, decodedPart);
+ }
+ else
+ {
+ result = decodedPart;
+ }
+ }
+ }
+ }
+
+ // If necessary, unwrap result from its proxy wrapper
+ if (result is ContentProxy)
+ result = ContentProxy(result).object_proxy::content;
+
+ soapResult.result = result;
+ }
+
+ /**
+ * Decodes a SOAP 1.1. Fault.
+ *
+ * FIXME: We need to add SOAP 1.2 Fault support which is very different
+ * from SOAP 1.1.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ protected function decodeFaults(faultsXMLList:XMLList):Array
+ {
+ log.debug("SOAP: Decoding SOAP response fault");
+ var faults:Array = [];
+
+ for each (var faultXML:XML in faultsXMLList)
+ {
+ var code:QName;
+ var string:String;
+ var detail:String;
+ var element:XML = faultXML;
+ var actor:String;
+
+ var faultProperties:XMLList = faultXML.children();
+ for each (var child:XML in faultProperties)
+ {
+ if (child.localName() == "faultcode")
+ {
+ code = schemaManager.getQNameForPrefixedName(child.toString(), child);
+ }
+ else if (child.localName() == "faultstring")
+ {
+ string = child.toString();
+ }
+ else if (child.localName() == "faultactor")
+ {
+ actor = child.toString();
+ }
+ else if (child.localName() == "detail")
+ {
+ if (child.hasComplexContent())
+ {
+ detail = child.children().toXMLString();
+ }
+ else
+ {
+ detail = child.toString();
+ }
+ }
+ }
+
+ var fault:SOAPFault = new SOAPFault(code, string, detail, element, actor);
+ faults.push(fault);
+ }
+ return faults;
+ }
+
+ protected function decodeHeaders(headerXML:XML):Array
+ {
+ log.debug("Decoding SOAP response headers");
+
+ var headers:Array = [];
+ var headerXMLList:XMLList = headerXML.elements();
+ for each (var headerChild:XML in headerXMLList)
+ {
+ if (headerFormat == "object")
+ {
+ var xsiType:QName = getXSIType(headerChild);
+ var definition:XML = null;
+ var headerContent:Object = null;
+
+ // Check for xsi:type on the header
+ if (xsiType != null)
+ definition = schemaManager.getNamedDefinition(xsiType,
+ constants.complexTypeQName, constants.simpleTypeQName);
+
+ // We found a definition for the type.
+ if (definition != null)
+ {
+ // Release scope, since we were only checking if definition exists.
+ schemaManager.releaseScope();
+ headerContent = decode(headerChild, null, xsiType);
+ }
+ else
+ {
+ // We don't have a type definition. Attempt to find an element
+ // definition for the QName of the header. If there is none,
+ // decode() will fall back to anyType.
+ headerContent = decode(headerChild, headerChild.name() as QName);
+ }
+
+ // Create the SOAPHeader wrapper.
+ var headerObject:SOAPHeader = new SOAPHeader(headerChild.name() as QName, headerContent);
+
+ // decode mustUnderstand attribute
+ var muValue:String = XMLUtil.getAttributeByQName(headerChild,
+ soapConstants.mustUnderstandQName).toString();
+ if (muValue == "1")
+ headerObject.mustUnderstand = true;
+
+ // decode actor attribute
+ var actValue:String = XMLUtil.getAttributeByQName(headerChild,
+ soapConstants.actorQName).toString();
+ if (actValue != "")
+ headerObject.role = actValue;
+
+ headers.push(headerObject);
+ }
+ else if (headerFormat == "e4x")
+ {
+ headers.push(headerChild);
+ }
+ else if (headerFormat == "xml")
+ {
+ headers.push(new XMLDocument(headerChild.toString()));
+ }
+ }
+
+ return headers;
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods - XML Decoding
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ override public function decodeComplexType(definition:XML, parent:*, name:QName, value:*, restriction:XML=null, context:DecodingContext=null):void
+ {
+ if (value is XML)
+ {
+ var valXML:XML = value as XML;
+
+ if (valXML.elements(SOAPConstants.diffgramQName).length() > 0
+ && valXML.elements(schemaConstants.schemaQName).length() > 0)
+ {
+ // If we have XML with the elements of a .NET DataSet, we
+ // short-circuit to decodeType, which will call the special
+ // decode function for the DataSetType
+ decodeType(SOAPConstants.diffgramQName, parent, valXML.name() as QName, value);
+ return;
+ }
+ }
+
+ // If the value provided is not XML, or doesn't have the elements
+ // of a .NET DataSet, we just call super.
+ super.decodeComplexType(definition, parent, name, value, restriction, context);
+ }
+
+ /**
+ * @private
+ */
+ override public function decodeType(type:QName, parent:*, name:QName, value:*, restriction:XML = null):void
+ {
+ // SOAP encoding specifies a type directly on the value and we
+ // can usually use it unless it is a type that is not built-in
+ // nor has a schema type definition. The value's specific type is
+ // retained as originalType in case we need to fall back to using it.
+ var originalType:QName = type;
+ var xsiType:QName = getXSIType(value);
+ if (xsiType != null)
+ type = xsiType;
+
+ // HACK: If encoded, translate simple SOAP types to XSD types.
+ if (outputEncoding.useStyle == SOAPConstants.USE_ENCODED)
+ {
+ // FIXME: This should be managed by the schemaManager's unmarshaller
+ if (SOAPConstants.isSOAPEncodedType(type))
+ {
+ var datatypes:SchemaDatatypes = schemaManager.schemaDatatypes;
+ if (type == soapConstants.soapBase64QName)
+ {
+ type = datatypes.base64BinaryQName;
+ }
+ else
+ {
+ var localName:String = type.localName;
+ if (localName != "Array" && localName != "arrayType")
+ {
+ type = schemaConstants.getQName(localName);
+ }
+ }
+ }
+ }
+
+ // Look for a custom SOAP type to handle the decoding
+ var customType:ICustomSOAPType = SOAPConstants.getCustomSOAPType(type);
+ if (customType != null)
+ {
+ customType.decode(this, parent, name, value, restriction);
+ setXSIType(parent, type);
+ }
+ else
+ {
+ // We didn't do custom SOAP type decoding, so we need to delegate
+ // but we need to pass a valid type to the base processing routine.
+ var constants:SchemaConstants = schemaManager.schemaConstants;
+ if (isBuiltInType(type))
+ {
+ super.decodeType(type, parent, name, value, restriction);
+ }
+ else
+ {
+ var definition:XML = schemaManager.getNamedDefinition(type,
+ constants.complexTypeQName,
+ constants.simpleTypeQName,
+ constants.elementTypeQName);
+
+ if (definition != null)
+ {
+ // We're done with this definition; just needed to see if
+ // we had it so we release the scope.
+ schemaManager.releaseScope();
+ super.decodeType(type, parent, name, value, restriction);
+ }
+ else
+ {
+ // We don't have a type def for the value's specific
+ // xsi type, so fall back to the default type passed in.
+ super.decodeType(originalType, parent, name, value, restriction);
+ }
+ }
+ }
+ }
+
+ /**
+ * This override intercepts dencoding a complexType with complexContent based
+ * on a SOAP encoded Array. This awkward approach to Array type definitions
+ * was popular in WSDL 1.1 rpc-encoded operations and is a special case that
+ * needs to be handled, but note it violates the WS-I Basic Profile 1.0.
+ *
+ * @private
+ */
+ override public function decodeComplexRestriction(restriction:XML, parent:*, name:QName, value:*):void
+ {
+ // Handle <restriction base="soap-enc:Array"> as a special case
+ var schemaConstants:SchemaConstants = schemaManager.schemaConstants;
+ var baseName:String = restriction.@base;
+ var baseQName:QName = schemaManager.getQNameForPrefixedName(baseName, restriction);
+ if (baseQName == soapConstants.soapencArrayQName)
+ {
+ var customType:ICustomSOAPType = SOAPConstants.getCustomSOAPType(baseQName);
+ if (customType != null)
+ {
+ customType.decode(this, parent, name, value, restriction);
+ return;
+ }
+ }
+
+ super.decodeComplexRestriction(restriction, parent, name, value);
+ }
+
+
+ override public function reset():void
+ {
+ super.reset();
+ _referencesResolved = false;
+ _elementsWithId = null;
+ }
+
+ /**
+ * Determines whether a name is in an internal (SOAP or XSD specific)
+ * namespace (as opposed to a user's namespace).
+ * @private
+ */
+ override protected function isInternalNamespace(name:QName):Boolean
+ {
+ var uri:String = (name != null) ? name.uri : null;
+ if (uri)
+ {
+ if (URLUtil.urisEqual(uri, soapConstants.encodingURI) ||
+ URLUtil.urisEqual(uri, soapConstants.envelopeURI))
+ {
+ return true;
+ }
+ }
+
+ return super.isInternalNamespace(name);
+ }
+
+ /**
+ * Overrides XMLDecoder.parseValue to allow us to detect a legacy case
+ * of literal style encoding where by generically encoded compound types
+ * (such as arrays) had entries encoded with multiple child
+ * <code>item</code> elements (instead of matching the correct schema
+ * definition of just repeating the value node).
+ *
+ * @private
+ */
+ override protected function parseValue(name:*, value:XMLList):*
+ {
+ if (supportGenericCompoundTypes
+ && outputEncoding.useStyle == SOAPConstants.USE_LITERAL
+ && value.length() > 0)
+ {
+ // Look for child <item> elements as direct descendents of the value
+ var itemQName:QName = new QName(value[0].name().uri, "item");
+ var items:XMLList = value.elements(itemQName);
+ if (items.length() > 0)
+ value = items;
+ }
+
+ return super.parseValue(name, value);
+ }
+
+ /**
+ * Overrides XMLDecoder.preProcessXML to allow us to handle multi-ref SOAP
+ * encoding.
+ * @private
+ */
+ override protected function preProcessXML(root:XML):void
+ {
+ // Only RPC/encoded uses multi-ref encoding.
+ if (outputEncoding.useStyle == SOAPConstants.USE_ENCODED)
+ resolveReferences(root);
+ }
+
+ /**
+ * Resolves multi-refs in rpc/encoded. Substitutes each reference by its
+ * referent node.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private function resolveReferences(root:XML, cleanupElementsWithIdCache:Boolean=true):void
+ {
+ if (_referencesResolved)
+ return;
+
+ var index:uint = 0;
+ if (_elementsWithId == null)
+ _elementsWithId = document..*.(attribute("id").length() > 0);
+
+ // Note that we must consider all child nodes here, not just elements
+ // as we need the accurate index in terms of child XML nodes to replace
+ // a node with the referent.
+ for each (var child:XML in root.children())
+ {
+ if (child.nodeKind() == "element")
+ {
+ var href:String = getAttributeFromNode("href", child);
+ if (href != null)
+ {
+ var hashPosition:int = href.indexOf("#");
+ if (hashPosition >= 0)
+ href = href.substring(hashPosition + 1);
+
+ // Find the first element with a matching id attribute
+ var matches:XMLList = _elementsWithId.(@id == href);
+ var referent:XML;
+
+ if (matches.length() > 0)
+ referent = matches[0];
+ else
+ throw new Error("The element referenced by id '" + href + "' was not found.");
+
+ referent.setName(child.name());
+
+ if (referent.hasComplexContent())
+ resolveReferences(referent, false);
+
+ // Replace the reference with the referent
+ root.replace(index, referent);
+
+ // Then remove the id attribute from replaced value
+ referent = root.child(index)[0];
+ delete referent.@id;
+ }
+ else if (child.hasComplexContent())
+ {
+ resolveReferences(child, false);
+ }
+ }
+
+ index++;
+ }
+
+ if (cleanupElementsWithIdCache)
+ {
+ _elementsWithId = null;
+ // At this point all references have been resolved.
+ _referencesResolved = true;
+ }
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+
+ private var log:ILogger;
+ private var _elementsWithId:XMLList;
+ private var _forcePartArrays:Boolean;
+ private var _headerFormat:String;
+ private var _ignoreWhitespace:Boolean = true;
+ private var _multiplePartsFormat:String;
+ private var _referencesResolved:Boolean; // Used to prevent repeat resolution passes for a single document.
+ private var _resultFormat:String;
+ private var _wsdlOperation:mx.rpc.wsdl.WSDLOperation;
+
+
+ /**
+ * A RegEx pattern to help replace the whitespace between processing
+ * instructions and root tags.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static var PI_WHITESPACE_PATTERN:RegExp = new RegExp("[\\?][>]\\s*[<]", "g");
+}
+
+}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/SOAPEncoder.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/SOAPEncoder.as
new file mode 100644
index 0000000..bc2880e
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/SOAPEncoder.as
@@ -0,0 +1,912 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap
+{
+
+import flash.xml.XMLDocument;
+import flash.xml.XMLNode;
+
+import mx.core.mx_internal;
+import mx.logging.ILogger;
+import mx.logging.Log;
+import mx.resources.IResourceManager;
+import mx.resources.ResourceManager;
+import mx.rpc.soap.types.ICustomSOAPType;
+import mx.rpc.wsdl.WSDLConstants;
+import mx.rpc.wsdl.WSDLEncoding;
+import mx.rpc.wsdl.WSDLOperation;
+import mx.rpc.wsdl.WSDLMessage;
+import mx.rpc.wsdl.WSDLMessagePart;
+import mx.rpc.xml.Schema;
+import mx.rpc.xml.SchemaConstants;
+import mx.rpc.xml.SchemaDatatypes;
+import mx.rpc.xml.SchemaMarshaller;
+import mx.rpc.xml.XMLEncoder;
+
+[ResourceBundle("rpc")]
+
+[ExcludeClass]
+
+/**
+ * A SOAPEncoder is used to create SOAP 1.1 formatted requests for a web service
+ * operation. A WSDLOperation provides the definition of how SOAP request should
+ * be formatted and thus must be set before a call is made to encode().
+ *
+ * TODO: Create a SOAP 1.2 specific subclass of this encoder.
+ *
+ * @private
+ */
+public class SOAPEncoder extends XMLEncoder implements ISOAPEncoder
+{
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ public function SOAPEncoder()
+ {
+ super();
+ log = Log.getLogger("mx.rpc.soap.SOAPEncoder");
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ private var resourceManager:IResourceManager =
+ ResourceManager.getInstance();
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Determines whether the encoder should ignore whitespace when
+ * constructing an XML representation of a SOAP request.
+ * The default is <code>true</code> and thus whitespace is not preserved.
+ * If an XML Schema type definition specifies a <code>whiteSpace</code>
+ * restriction set to <code>preserve</code> then ignoreWhitespace must
+ * first be set to false. Conversely, if a type <code>whiteSpace</code>
+ * restriction is set to <code>replace</code> or <code>collapse</code> then
+ * that setting will be honored even if ignoreWhitespace is set to false.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get ignoreWhitespace():Boolean
+ {
+ return _ignoreWhitespace;
+ }
+
+ public function set ignoreWhitespace(value:Boolean):void
+ {
+ _ignoreWhitespace = value;
+ }
+
+ /**
+ * @private
+ */
+ protected function get inputEncoding():WSDLEncoding
+ {
+ return _wsdlOperation.inputMessage.encoding;
+ }
+
+ public function get schemaConstants():SchemaConstants
+ {
+ return schemaManager.schemaConstants;
+ }
+
+ public function get soapConstants():SOAPConstants
+ {
+ return wsdlOperation.soapConstants;
+ }
+
+ public function get wsdlOperation():WSDLOperation
+ {
+ return _wsdlOperation;
+ }
+
+ public function set wsdlOperation(value:WSDLOperation):void
+ {
+ _wsdlOperation = value;
+ schemaManager = _wsdlOperation.schemaManager;
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @inheritDoc
+ */
+ public function encodeRequest(args:* = null, headers:Array = null):XML
+ {
+ // FIXME: Some level of validation should occur here
+ // to check we're ready to start encoding.
+
+ reset();
+
+ var envelopeXML:XML;
+
+ // Keep track of the previous ignoreWhitespace setting (as it is
+ // unfortunately a static API on the intrinsic XML type) so we
+ // can set it back to its original state once we're finished.
+ var oldIgnoreWhitespace:Boolean = XML.ignoreWhitespace;
+ var oldPrettyPrinting:Boolean = XML.prettyPrinting;
+ try
+ {
+ XML.ignoreWhitespace = ignoreWhitespace;
+ XML.prettyPrinting = false;
+ envelopeXML = encodeEnvelope(args, headers);
+ }
+ finally
+ {
+ XML.ignoreWhitespace = oldIgnoreWhitespace;
+ XML.prettyPrinting = oldPrettyPrinting;
+ }
+
+ return envelopeXML;
+ }
+
+ /**
+ * A SOAP Envelope element is the root element of a SOAP message. It
+ * must specify the SOAP namespace.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ protected function encodeEnvelope(args:*, headers:Array):XML
+ {
+ log.debug("Encoding SOAP request envelope");
+
+ var envelopeXML:XML = <{soapConstants.envelopeQName.localName}/>;
+ envelopeXML.setNamespace(soapConstants.envelopeNamespace);
+ envelopeXML.addNamespace(schemaConstants.xsdNamespace);
+ envelopeXML.addNamespace(schemaConstants.xsiNamespace);
+
+ // Make sure the envelope namespace is registered with the schemaManager
+ // so that its prefix can be looked up when encoding header attributes.
+ schemaManager.namespaces[soapConstants.envelopeNamespace.prefix] =
+ soapConstants.envelopeNamespace;
+
+ encodeHeaders(headers, envelopeXML);
+ encodeBody(args, envelopeXML);
+ return envelopeXML;
+ }
+
+ /**
+ * Appends SOAP Header to the SOAP Envelope
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ protected function encodeHeaders(headers:Array, envelopeXML:XML):void
+ {
+ if (headers != null)
+ {
+ var count:uint = headers.length;
+ if (count > 0)
+ {
+ var headersXML:XML = <{soapConstants.headerQName.localName}/>
+ headersXML.setNamespace(soapConstants.envelopeNamespace);
+ envelopeXML.appendChild(headersXML);
+
+ for (var i:uint = 0; i < count; i++)
+ {
+ encodeHeaderElement(headers[i], headersXML);
+ }
+ }
+ }
+ }
+
+ /**
+ * Appends a header element to top SOAP Header tag
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ protected function encodeHeaderElement(header:Object, headersXML:XML):void
+ {
+ var preEncodedNode:* = preEncodedCheck(header);
+ if (preEncodedNode != null)
+ {
+ headersXML.appendChild(header);
+ }
+ else
+ {
+ var headerElement:XMLList = new XMLList();
+
+ // header value might contain a mapping
+ if (header.content != null && header.content.hasOwnProperty(header.qname.localName))
+ {
+ header.content = header.content[header.qname.localName];
+ }
+
+ // check the content of the header for pre-encoded values
+ preEncodedNode = preEncodedCheck(header.content);
+ if (preEncodedNode != null)
+ {
+ // We can't set namespaces or attributes on XMLList, so we
+ // just append it and return...
+ if (preEncodedNode is XMLList)
+ {
+ headerElement = preEncodedNode as XMLList;
+ }
+ else
+ {
+ headerElement = new XMLList(preEncodedNode);
+ }
+ }
+ else
+ {
+ // If not pre-encoded, we encode the header value. If there is a
+ // definition in the schema for this header QName, we will use it,
+ // otherwise encode with anyType. This is handled by XMLEncoder.
+ headerElement = encode(header.content, header.qname);
+ }
+
+
+ // Typically headerElement will be an XMLList of length 1, but we
+ // loop through it anyway, in case we were given a pre-encoded XMLList,
+ // or an array value for the header.content
+ for each (var headerElementNode:XML in headerElement)
+ {
+
+ // add namespace to the header, if not already set by encoding.
+ if (header.qname.uri != null && header.qname.uri.length > 0
+ && headerElementNode.namespace().uri != header.qname.uri)
+ {
+ var prefix:String = schemaManager.getOrCreatePrefix(header.qname.uri);
+ var ns:Namespace = new Namespace(prefix, header.qname.uri);
+ headerElementNode.setNamespace(ns);
+ }
+
+ // add header attributes
+ var attrStr:String;
+ if (header.mustUnderstand)
+ {
+ attrStr = schemaManager.getOrCreatePrefix(soapConstants.mustUnderstandQName.uri);
+ headerElementNode.@[attrStr + ":" + soapConstants.mustUnderstandQName.localName] = "1"; // Use "1" form for WS-I compatibility
+ }
+
+ if (header.role != null)
+ {
+ attrStr = schemaManager.getOrCreatePrefix(soapConstants.actorQName.uri);
+ headerElementNode.@[attrStr + ":" + soapConstants.actorQName.localName] = header.role;
+ }
+ }
+
+ // finally, add header list to SOAP Header node
+ headersXML.appendChild(headerElement);
+ }
+ }
+
+ /**
+ * Encodes the SOAP Body. Currently assumes only one operation sub-element.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ protected function encodeBody(inputParams:*, envelopeXML:XML):void
+ {
+ log.debug("Encoding SOAP request body");
+
+ // Create SOAP Body element
+ var bodyXML:XML = <{soapConstants.bodyQName.localName}/>;
+ bodyXML.setNamespace(soapConstants.envelopeNamespace);
+
+ // FIXME: Should we continue to support pre-encoded XML fragments here?
+ // How would we tell the difference between an XML type input and
+ // a pre-encoded message?
+
+ // Special case handling for input params that are pre-encoded SOAP
+ // body contents.
+ var preEncoded:Object = preEncodedCheck(inputParams);
+ if (preEncoded != null)
+ {
+ bodyXML.appendChild(preEncoded);
+ }
+ else
+ {
+ // Encode the operation and append it to the body.
+ if (wsdlOperation.style == SOAPConstants.DOC_STYLE)
+ {
+ if (inputEncoding.useStyle == SOAPConstants.USE_LITERAL)
+ {
+ encodeOperationAsDocumentLiteral(inputParams, bodyXML);
+ }
+ else
+ {
+ //Note: document-encoded not support by WSDL 1.1
+ throw new Error("WSDL 1.1 supports operations with binding style 'document' only if use style is 'literal'.");
+ }
+ }
+ else if (wsdlOperation.style == SOAPConstants.RPC_STYLE)
+ {
+ if (inputEncoding.useStyle == SOAPConstants.USE_LITERAL)
+ {
+ encodeOperationAsRPCLiteral(inputParams, bodyXML);
+ }
+ else if (inputEncoding.useStyle == SOAPConstants.USE_ENCODED)
+ {
+ encodeOperationAsRPCEncoded(inputParams, bodyXML);
+ }
+ else
+ {
+ throw new Error("WSDL 1.1 does not support operations with binding style 'rpc' and use style " + inputEncoding.useStyle + ".");
+ }
+ }
+ else
+ {
+ throw new Error("Unrecognized binding style '" + wsdlOperation.style + "'. Only 'document' and 'rpc' styles are supported.");
+ }
+ }
+
+ // Add the fully encoded body to the envelope.
+ envelopeXML.appendChild(bodyXML);
+ }
+
+ /**
+ * Encodes a WSDL operation using document literal format.
+ * There's no need to generate an operation element so advance directly
+ * to encoding the message.
+ * <p>
+ * From the WSDL 1.1 specification:
+ * </p>
+ * <p>
+ * "If <code>use</code> is <b>literal</b>, then each part references
+ * a concrete schema definition using either the <code>element</code> or
+ * <code>type</code> attribute. In the first case, the element referenced
+ * by the part will appear directly under the Body element (for document
+ * style bindings)... In the second, the type referenced by the part
+ * becomes the schema type of the enclosing element (Body for document
+ * style...)."
+ * </p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ protected function encodeOperationAsDocumentLiteral(inputParams:Object, bodyXML:XML):void
+ {
+ var parts:Array = wsdlOperation.inputMessage.parts;
+ if (wsdlOperation.inputMessage.isWrapped)
+ {
+ // Wrapped-style uses a single part element as the outer wrapper.
+ var wrappedQName:QName = wsdlOperation.inputMessage.wrappedQName;
+ var operationXML:XML = <{wrappedQName.localName}/>;
+ if (wrappedQName.uri != null && wrappedQName.uri != "")
+ {
+ var prefix:String = schemaManager.getOrCreatePrefix(wrappedQName.uri);
+ var inputNamespace:Namespace = new Namespace(prefix, wrappedQName.uri);
+ operationXML.setNamespace(inputNamespace);
+ }
+
+ encodeMessage(inputParams, operationXML);
+ bodyXML.appendChild(operationXML);
+ }
+ else
+ {
+ // Non-wrapped document-literal style directly encodes the parts
+ // as children of the SOAP Body.
+ encodeMessage(inputParams, bodyXML);
+ }
+ }
+
+ /**
+ * Encodes a WSDL operation using RPC literal format.
+ * <p>
+ * From the WSDL 1.1 specification:
+ * </p>
+ * <p>
+ * "If the operation style is <code>rpc</code> each part is a parameter
+ * or a return value and appears inside a wrapper element within the body
+ * (following Section 7.1 of the SOAP specification). The wrapper element
+ * is named identically to the operation name and its namespace is the
+ * value of the namespace attribute. Each message part (parameter) appears
+ * under the wrapper, represented by an accessor named identically to the
+ * corresponding parameter of the call. Parts are arranged in the same
+ * order as the parameters of the call."
+ * </p>
+ * <p>
+ * "If <code>use</code> is <b>literal</b>, then each part references
+ * a concrete schema definition using either the <code>element</code> or
+ * <code>type</code> attribute. In the first case, the element referenced
+ * by the part will appear ... under an accessor element named after the
+ * message part (in rpc style). In the second, the type referenced by the
+ * part becomes the schema type of the enclosing element ( ... part accessor
+ * element for rpc style)."
+ * </p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ protected function encodeOperationAsRPCLiteral(inputParams:Object, bodyXML:XML):void
+ {
+ var operationXML:XML = <{wsdlOperation.name}/>;
+ var prefix:String = schemaManager.getOrCreatePrefix(inputEncoding.namespaceURI);
+ var ns:Namespace = new Namespace(prefix, inputEncoding.namespaceURI);
+ operationXML.setNamespace(ns);
+
+ encodeMessage(inputParams, operationXML);
+
+ bodyXML.appendChild(operationXML);
+ }
+
+ /**
+ * Encodes a WSDL message part using RPC encoded format.
+ * <p>
+ * From the WSDL 1.1 specification:
+ * </p>
+ * <p>
+ * "If the operation style is <code>rpc</code> each part is a parameter
+ * or a return value and appears inside a wrapper element within the body
+ * (following Section 7.1 of the SOAP specification). The wrapper element
+ * is named identically to the operation name and its namespace is the
+ * value of the namespace attribute. Each message part (parameter) appears
+ * under the wrapper, represented by an accessor named identically to the
+ * corresponding parameter of the call. Parts are arranged in the same
+ * order as the parameters of the call."
+ * </p>
+ * <p>
+ * "If <code>use</code> is <b>encoded</b>, then each message part
+ * references an abstract type using the <code>type</code> attribute. These
+ * abstract types are used to produce a concrete message by applying an
+ * encoding specified by the <code>encodingStyle</code> attribute. The part
+ * names, types and value of the namespace attribute are all inputs to the
+ * encoding, although the namespace attribute only applies to content not
+ * explicitly defined by the abstract types. If the referenced encoding
+ * style allows variations in it's format (such as the SOAP encoding does),
+ * then all variations MUST be supported ("reader makes right")."
+ * </p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ protected function encodeOperationAsRPCEncoded(inputParams:*, bodyXML:XML):void
+ {
+ isSOAPEncoding = true;
+ var operationXML:XML = <{wsdlOperation.name}/>;
+ var inputNamespaceURI:String = inputEncoding.namespaceURI;
+ var inputPrefix:String = schemaManager.getOrCreatePrefix(inputNamespaceURI);
+ var inputNamespace:Namespace = new Namespace(inputPrefix, inputNamespaceURI);
+ operationXML.setNamespace(inputNamespace);
+
+ encodeMessage(inputParams, operationXML);
+
+ bodyXML.appendChild(operationXML);
+ bodyXML.@[SOAPConstants.SOAP_ENV_PREFIX + ":encodingStyle"] = soapConstants.encodingURI;
+ }
+
+ /**
+ * Encodes an input message for a WSDL operation. The provided input
+ * parameters are validated against the required message parts.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ protected function encodeMessage(inputParams:*, operationXML:XML):void
+ {
+ var parts:Array;
+ if (wsdlOperation.inputMessage != null)
+ parts = wsdlOperation.inputMessage.parts;
+
+ if (parts == null)
+ return;
+
+ // Keep track of part names for validation
+ var partNames:Object = {};
+
+ // Keep track of any optional parts that were not provided
+ var optionalOmitted:int = 0;
+
+ var message:String;
+
+ // Match the input parameters to WSDL message parts
+ for (var i:uint = 0; i < parts.length; i++)
+ {
+ var part:WSDLMessagePart = parts[i];
+ var value:* = undefined;
+
+ // Ordered Parameters
+ if (inputParams is Array)
+ {
+ value = inputParams[i];
+ if (value === undefined)
+ {
+ if (part.optional)
+ {
+ optionalOmitted++;
+ }
+ else
+ {
+ message = resourceManager.getString(
+ "rpc", "missingInputParameter", [ i ]);
+ throw new Error(message);
+ }
+ }
+ }
+ // Named Parameters
+ else
+ {
+ var name:String = part.name.localName;
+ if (inputParams != null)
+ value = inputParams[name];
+ partNames[name] = value;
+
+ if (value === undefined || (inputParams != null && !inputParams.hasOwnProperty(name)))
+ {
+ if (part.optional)
+ {
+ optionalOmitted++;
+ }
+ else
+ {
+ message = resourceManager.getString(
+ "rpc", "missingInputParameterWithName", [ name ])
+ throw new Error(message);
+ }
+ }
+ }
+
+ if (value !== undefined)
+ {
+ // Finally, encode the value for the WSDL message part
+ var partXMLList:XMLList = encodePartValue(part, value);
+ operationXML.appendChild(partXMLList);
+ }
+ }
+
+ // Check for any unexpected parameters
+ if (inputParams != null)
+ {
+ if (inputParams is Array)
+ {
+ if (inputParams.length < (parts.length - optionalOmitted))
+ {
+ message = resourceManager.getString(
+ "rpc", "tooFewInputParameters",
+ [ parts.length, inputParams.length ]);
+ throw new Error(message);
+ }
+ }
+ else
+ {
+ for (var inName:String in inputParams)
+ {
+ if (!partNames.hasOwnProperty(inName))
+ {
+ message = resourceManager.getString(
+ "rpc", "unexpectedInputParameter", [ inName ]);
+ throw new Error(message);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * A WSDL message part may either refer to an XML Schema type (that is, a
+ * <complexType> or <simpleType>) directly by QName or to an element
+ * definition by QName depending on the SOAP use and encodingStyle
+ * attributes.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ protected function encodePartValue(part:WSDLMessagePart, value:*):XMLList
+ {
+ var partXMLList:XMLList;
+
+ if (part.element != null)
+ {
+ partXMLList = encode(value, part.element);
+ }
+ else
+ {
+ partXMLList = encode(value, part.name, part.type, part.definition);
+ }
+
+ return partXMLList;
+ }
+
+ /**
+ * Looks to see whether a pre-encoded SOAP request has been passed to the
+ * encoder.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ protected function preEncodedCheck(value:*):Object
+ {
+ var preEncodedNode:Object = null;
+ if (value != null)
+ {
+ if (value is XMLList)
+ {
+ preEncodedNode = value as XMLList;
+ }
+ else if (value is XML)
+ {
+ preEncodedNode = value as XML;
+ }
+ else if (value is XMLDocument)
+ {
+ var xmlDocument:XMLDocument = value as XMLDocument;
+ preEncodedNode = new XML(xmlDocument.firstChild.toString());
+ }
+ else if (value is XMLNode)
+ {
+ var xmlNode:XMLNode = value as XMLNode;
+ preEncodedNode = new XML(xmlNode.toString());
+ }
+ }
+ return preEncodedNode;
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Custom XML Encoding Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * SOAP specific override to handle special wrapped-style document-literal
+ * parameters which can specify minOccurs and maxOccurs attributes on
+ * local element definitions that are, for all intents and purposes,
+ * really top-level element definitions representing operation parts.
+ * XML Schema does not normally allow minOccurs or maxOccurs on top-level
+ * element definitions and the SchemaProcessor is not looking out for them
+ * so we have to special case this situation here.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ override public function encode(value:*, name:QName = null, type:QName = null, definition:XML = null):XMLList
+ {
+ if (definition != null)
+ {
+ var result:XMLList = new XMLList();
+
+ // <element minOccurs="..." maxOccurs="..."> occur on a local element
+ // that may act like a top-level element for wrapped-style document
+ // literal.
+ var maxOccurs:uint = getMaxOccurs(definition);
+ var minOccurs:uint = getMinOccurs(definition);
+
+ // If the maximum occurence should 0 this element must not be present.
+ if (maxOccurs == 0)
+ return result;
+
+ // If minOccurs == 0 the element is optional so we can omit it if
+ // a value was not provided.
+ if (value == null && minOccurs == 0)
+ return result;
+
+ if (maxOccurs > 1)
+ {
+ // Create a temporary XML parent to hold the XMLList of values
+ // during encoding ...
+ var content:XMLList = new XMLList();
+ // To make sure we will use the correct namespace if there are more
+ // than one top level schemas, we push the relevant schema as a new scope.
+ var foundScope:Boolean = schemaManager.pushNamespaceInScope(name.uri);
+
+ encodeGroupElement(definition, content, name, value);
+
+ if (foundScope)
+ schemaManager.releaseScope();
+
+ result += content;
+ return result;
+ }
+ }
+
+ return super.encode(value, name, type, definition);
+ }
+
+ /**
+ * SOAP specific override to intercept SOAP encoded types such as base64.
+ * Also, SOAP encoding requires an XSI type attribute to be specified on
+ * encoded types.
+ *
+ * @private
+ */
+ override public function encodeType(type:QName, parent:XML, name:QName, value:*, restriction:XML = null):void
+ {
+ var datatypes:SchemaDatatypes = schemaManager.schemaDatatypes;
+
+ // Allow instance level overrides for the type (which can also be used
+ // to specify the XSI type too).
+ var xsiType:QName = getXSIType(value);
+ if (xsiType != null)
+ type = xsiType;
+
+ // We can encode many SOAP types as their XML Schema equivalents so
+ // long as we set the XSI type correctly for SOAP encoded operations
+ if (isSOAPEncoding)
+ {
+ // Keep track of the real type for setting the SOAP encoding
+ // xsi:type as we may need to use a different type internally for
+ // XML Schema encoding...
+ xsiType = type;
+
+ if (SOAPConstants.isSOAPEncodedType(type))
+ {
+ // We treat SOAP encoded base64 as the XML Schema base64Binary
+ if (type == soapConstants.soapBase64QName)
+ {
+ type = datatypes.base64BinaryQName;
+ }
+ else
+ {
+ // HACK: Translate simple SOAP encoded types to XSD types
+ // for the purposes of schema type marshalling
+ var localName:String = type.localName;
+ if (localName != "Array" && localName != "arrayType")
+ {
+ type = schemaConstants.getQName(localName);
+ }
+ }
+ }
+ }
+
+ // Look for custom handlers to override processing of SOAP types.
+ var customType:ICustomSOAPType = SOAPConstants.getCustomSOAPType(type);
+ if (customType != null)
+ {
+ customType.encode(this, parent, name, value, restriction);
+ }
+ else
+ {
+ super.encodeType(type, parent, name, value, restriction);
+ }
+
+ // Finally, we may need to set an xsi:type attribute on the parent...
+ if (xsiType != null)
+ {
+// var parentNode:XML = parent as XML;
+
+ // ... but we don't override if an existing xsi:type was determined
+ // up stream (ie.. for anyType and anySimpleType).
+ var xsiTypeAttr:String = parent.@[schemaConstants.getXSIToken(schemaConstants.typeAttrQName)]
+ if (xsiTypeAttr == null || xsiTypeAttr == "")
+ {
+ // FIXME: we shouldn't need super anymore since deriveXSIType is separate
+ super.setXSIType(parent, xsiType);
+ }
+ }
+ }
+
+ /**
+ * This override intercepts encoding a complexType with complexContent based
+ * on a SOAP encoded Array. This awkward approach to Array type definitions
+ * was popular in WSDL 1.1 rpc-encoded operations and is a special case that
+ * needs to be handled, but note it violates the WS-I Basic Profile 1.0.
+ *
+ * @private
+ */
+ override public function encodeComplexRestriction(restriction:XML, parent:XML, name:QName, value:*):void
+ {
+ // Handle for <restriction base="soap-enc:Array"> as a special case
+ var schemaConstants:SchemaConstants = schemaManager.schemaConstants;
+ var baseName:String = restriction.@base;
+ var baseQName:QName = schemaManager.getQNameForPrefixedName(baseName, restriction);
+ if (baseQName == soapConstants.soapencArrayQName)
+ {
+ var customType:ICustomSOAPType = SOAPConstants.getCustomSOAPType(baseQName);
+ if (customType != null)
+ {
+ customType.encode(this, parent, name, value, restriction);
+ return;
+ }
+ }
+
+ super.encodeComplexRestriction(restriction, parent, name, value);
+ }
+
+ /**
+ * This override tries to determine the XSI type for the encoded value if
+ * SOAP use style is set to <code>encoded</code>.
+ *
+ * @private
+ */
+ protected override function deriveXSIType(parent:XML, type:QName, value:*):void
+ {
+
+ // Add XSI type if the SOAP message has use style as "encoded"
+ if (isSOAPEncoding)
+ {
+ var datatypes:SchemaDatatypes = schemaManager.schemaDatatypes;
+ var soapType:QName;
+
+ // HACK: For anyType and anySimpleType, try to guess the schema
+ // type for simple values (note we can't guess for complex values).
+ if (type == datatypes.anyTypeQName || type == datatypes.anySimpleTypeQName)
+ {
+ if (isSimpleValue(value) || type == datatypes.anySimpleTypeQName)
+ {
+ var localName:String = SchemaMarshaller.guessSimpleType(value);
+ soapType = new QName(schemaConstants.xsdURI, localName);
+ }
+ }
+ else
+ {
+ soapType = type;
+ }
+
+ if (soapType != null)
+ {
+ // FIXME: should be OK to use setXSIType
+// setXSIType(parent, soapType);
+ parent.@[schemaConstants.getXSIToken(schemaConstants.typeAttrQName)] = schemaConstants.getXSDToken(soapType);
+ }
+ }
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ private var _ignoreWhitespace:Boolean = true;
+ private var isSOAPEncoding:Boolean = false;
+ private var log:ILogger;
+ private var _wsdlOperation:WSDLOperation;
+}
+
+}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/SOAPFault.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/SOAPFault.as
new file mode 100644
index 0000000..900abf3
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/SOAPFault.as
@@ -0,0 +1,183 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap
+{
+
+import flash.xml.XMLNode;
+import mx.rpc.Fault;
+
+/**
+ * A subclass of mx.rpc.Fault that provides SOAP specific information from
+ * a SOAP envelope Fault element.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class SOAPFault extends Fault
+{
+ /**
+ * Constructs a new SOAPFault.
+ *
+ * @param faultCode The fully qualified name of the fault code.
+ *
+ * @param faultString The description of the fault.
+ *
+ * @param detail Any extra details of the fault.
+ *
+ * @param element The raw XML of the SOAP fault.
+ *
+ * @param faultactor Information about who caused the SOAP fault.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function SOAPFault(faultCode:QName,
+ faultString:String,
+ detail:String = null,
+ element:XML = null,
+ faultactor:String = null)
+ {
+ super(faultCode.localName, faultString, detail);
+
+ this.element = element;
+ this.faultactor = faultactor;
+ this.faultcode = faultCode;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * The raw XML of this SOAP Fault.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var element:XML;
+
+ /**
+ * A SOAP Fault may provide information about who caused the fault through
+ * a faultactor property.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var faultactor:String;
+
+ /**
+ * The faultcode property is similar to faultCode but exists to both
+ * match the case of the faultcode element in a SOAP Fault and to provide
+ * the fully qualified name of the code.
+ *
+ * @see mx.rpc.Fault#faultDetail
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var faultcode:QName;
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * The detail property is the same as faultDetail but exists
+ * to match the case of the detail element in a SOAP Fault.
+ *
+ * @see mx.rpc.Fault#faultDetail
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get detail():String
+ {
+ return _faultDetail;
+ }
+
+ public function set detail(value:String):void
+ {
+ _faultDetail = value;
+ }
+
+ /**
+ * The faultstring property is the same as faultString but exists
+ * to match the case of the faultstring element in a SOAP envelope Fault.
+ *
+ * @see mx.rpc.Fault#faultString
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get faultstring():String
+ {
+ return _faultString;
+ }
+
+ public function set faultstring(value:String):void
+ {
+ _faultString = value;
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Returns the String "SOAPFault" plus the faultCode, faultString, and
+ * faultDetail.
+ *
+ * @return Returns the String "SOAPFault" plus the faultCode, faultString, and
+ * faultDetail.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ override public function toString():String
+ {
+ return "SOAPFault (" + faultCode + "): " + faultString + " " + faultDetail;
+ }
+}
+
+}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/SOAPHeader.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/SOAPHeader.as
new file mode 100644
index 0000000..68db529
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/SOAPHeader.as
@@ -0,0 +1,120 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap
+{
+
+/**
+ * You use a SOAPHeader to specify the headers that need
+ * to be added to a SOAP envelope of a WebService Operation request.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class SOAPHeader
+{
+ /**
+ * Constructs a new SOAPHeader. The qualified name and content for the
+ * SOAP header are required.
+ *
+ * @param qname The qualified name of the SOAP header.
+ *
+ * @param content The content to send for the header value.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function SOAPHeader(qname:QName, content:Object)
+ {
+ super();
+ this.qname = qname;
+ this.content = content;
+ }
+
+ /**
+ * The content to send for the header value.
+ * If you provide an XML or flash.xml.XMLNode instance for the header, it is
+ * used directly as pre-encoded content and appended as a child to the soap:header element.
+ * Otherwise, you can provide the value as a String or Number, etc. and the underlying SOAP encoder
+ * attempts to encode the value correctly based on the QName provided in the SOAPHeader
+ * (with the last resort being xsd:anyType if a type definition is not present).
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var content:Object;
+
+ /**
+ * The qualified name of the SOAP header.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var qname:QName;
+
+ /**
+ * Internal use only. The internal datatype as determined from
+ * the WSDL schema that should be used to encode the content.
+ * @private
+ */
+ public var xmlType:QName;
+
+ /**
+ * Specifies whether the header must be understood by the endpoint. If
+ * the header is handled but must be understood the endpoint should
+ * return a SOAP fault.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var mustUnderstand:Boolean;
+
+ /**
+ * Specifies the URI for the role that this header is intended in a
+ * potential chain of endpoints processing a SOAP request. If defined,
+ * this value is used to specify the <code>actor</code> for the SOAP
+ * header.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var role:String;
+
+ /**
+ * @private
+ */
+ public function toString():String
+ {
+ return qname + ", " + content + ", " + role;
+ }
+}
+
+}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/SOAPResult.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/SOAPResult.as
new file mode 100644
index 0000000..b3f2207
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/SOAPResult.as
@@ -0,0 +1,81 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap
+{
+
+
+/**
+ * A context for the result of a SOAP based Remote Procedure Call.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class SOAPResult
+{
+ /**
+ * A collection of header objects. A SOAPDecoder can populate this array with
+ * elements of type SOAPHeader, XML, or XMLDocument, based on the headerFormat
+ * setting on the decoder.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var headers:Array;
+
+ /**
+ * Flag indicating if this result object represents a SOAP Fault message.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var isFault:Boolean;
+
+ /**
+ * Body of the SOAP result. A SOAPDecoder can populate this value based on the
+ * resultFormat setting on the decoder.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var result:*;
+
+ /**
+ * Creates a new SOAPResult.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function SOAPResult()
+ {
+ super();
+ }
+}
+
+}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/WebService.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/WebService.as
index d35fce4..e506674 100644
--- a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/WebService.as
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/WebService.as
@@ -25,7 +25,7 @@ package mx.rpc.soap
import org.apache.royale.events.Event;
import mx.core.mx_internal;
-/* import mx.logging.ILogger;
+import mx.logging.ILogger;
import mx.logging.Log;
import mx.messaging.ChannelSet;
import mx.messaging.channels.DirectHTTPChannel;
@@ -44,8 +44,7 @@ import mx.rpc.wsdl.WSDLLoader;
import mx.rpc.wsdl.WSDLOperation;
import mx.rpc.wsdl.WSDLPort;
import mx.utils.URLUtil;
-import mx.utils.XMLUtil;
- */
+
use namespace mx_internal;
/**
@@ -59,9 +58,9 @@ use namespace mx_internal;
* @playerversion AIR 1.1
* @productversion Royale 0.9.4
*/
-/* [Event(name="load", type="mx.rpc.soap.LoadEvent")]
+[Event(name="load", type="mx.rpc.soap.LoadEvent")]
-[ResourceBundle("rpc")] */
+//[ResourceBundle("rpc")]
/**
* The WebService class provides access to SOAP-based web services on remote
@@ -72,8 +71,8 @@ use namespace mx_internal;
* @playerversion AIR 1.1
* @productversion Royale 0.9.4
*/
-public dynamic class WebService
-{ // extends AbstractWebService
+public dynamic class WebService extends AbstractWebService
+{
//--------------------------------------------------------------------------
//
// Constructor
@@ -98,10 +97,10 @@ public dynamic class WebService
*/
public function WebService(destination:String = null, rootURL:String = null)
{
- /* super(destination, rootURL);
+ super(destination, rootURL);
_ready = false;
- _log = Log.getLogger("mx.rpc.soap.WebService"); */
+ _log = Log.getLogger("mx.rpc.soap.WebService");
}
//-------------------------------------------------------------------------
@@ -121,12 +120,12 @@ public dynamic class WebService
//
//-------------------------------------------------------------------------
- /* mx_internal function get wsdlFault():Boolean
+ mx_internal function get wsdlFault():Boolean
{
return _wsdlFault;
}
- [Inspectable(defaultValue="true", category="General")] */
+ [Inspectable(defaultValue="true", category="General")]
/**
* The location of the WSDL document for this WebService. If you use a
@@ -138,7 +137,7 @@ public dynamic class WebService
* @playerversion AIR 1.1
* @productversion Royale 0.9.4
*/
- /* public function get wsdl():String
+ public function get wsdl():String
{
return _wsdlURL;
}
@@ -146,7 +145,7 @@ public dynamic class WebService
public function set wsdl(w:String):void
{
_wsdlURL = w;
- } */
+ }
//-------------------------------------------------------------------------
//
@@ -166,7 +165,7 @@ public dynamic class WebService
* @playerversion AIR 1.1
* @productversion Royale 0.9.4
*/
- /* public function canLoadWSDL():Boolean
+ public function canLoadWSDL():Boolean
{
if (wsdl)
return true;
@@ -174,7 +173,7 @@ public dynamic class WebService
&& destination != DEFAULT_DESTINATION_HTTPS)
return true;
return false;
- } */
+ }
/**
* Returns an Operation of the given name. If the Operation wasn't
@@ -192,7 +191,7 @@ public dynamic class WebService
* @playerversion AIR 1.1
* @productversion Royale 0.9.4
*/
- /* override public function getOperation(name:String):mx.rpc.AbstractOperation
+ override public function getOperation(name:String):mx.rpc.AbstractOperation
{
var op:mx.rpc.AbstractOperation = super.getOperation(name);
if (op == null)
@@ -204,7 +203,7 @@ public dynamic class WebService
initializeOperation(op as Operation);
}
return op;
- } */
+ }
/**
* Instructs the WebService to download the WSDL document. The WebService
@@ -223,7 +222,7 @@ public dynamic class WebService
*/
public function loadWSDL(uri:String = null):void
{
- /* if (uri != null)
+ if (uri != null)
{
wsdl = uri;
}
@@ -235,8 +234,8 @@ public dynamic class WebService
var message:String;
if (!useProxy)
{
- message = resourceManager.getString(
- "rpc", "mustSpecifyWSDLLocation");
+ message = /*resourceManager.getString(
+ "rpc", */"mustSpecifyWSDLLocation"/*)*/;
var fault:Fault = new Fault("Client.WSDL", message);
dispatchEvent(FaultEvent.createEvent(fault));
return;
@@ -245,8 +244,8 @@ public dynamic class WebService
|| (destination == DEFAULT_DESTINATION_HTTP)
|| (destination == DEFAULT_DESTINATION_HTTPS))
{
- message = resourceManager.getString(
- "rpc", "destinationOrWSDLNotSpecified");
+ message = /*resourceManager.getString(
+ "rpc", */"destinationOrWSDLNotSpecified"/*)*/;
var fault1:Fault = new Fault("Client.WSDL", message);
dispatchEvent(FaultEvent.createEvent(fault1));
return;
@@ -269,7 +268,7 @@ public dynamic class WebService
// Get the WSDL
_wsdlFault = false;
- _wsdlLoader.load(wsdl); */
+ _wsdlLoader.load(wsdl);
}
/**
@@ -284,7 +283,8 @@ public dynamic class WebService
* @playerversion AIR 1.1
* @productversion Royale 0.9.4
*/
- /* public function toString():String
+ COMPILE::JS { override }
+ public function toString():String
{
var s:String = "[WebService ";
s += " destination=\"" + destination + "\"";
@@ -292,13 +292,13 @@ public dynamic class WebService
s += " wsdl=\"" + wsdl + "\"";
s += " channelSet=\"" + channelSet + "\"]";
return s;
- } */
+ }
//---------------------------------
// Helper methods
//---------------------------------
- /* mx_internal function wsdlFaultHandler(event:FaultEvent):void
+ mx_internal function wsdlFaultHandler(event:FaultEvent):void
{
// remember that the wsdl failed
_wsdlFault = true;
@@ -308,9 +308,9 @@ public dynamic class WebService
// also inform enqueued operations of the wsdl failure
unEnqueueCalls(event.fault);
- } */
+ }
- /* mx_internal function wsdlHandler(event:WSDLLoadEvent):void
+ mx_internal function wsdlHandler(event:WSDLLoadEvent):void
{
_log.debug("WSDL loaded");
_wsdl = event.wsdl;
@@ -355,8 +355,8 @@ public dynamic class WebService
catch(error:Error)
{
var errorMessage:String = error.message ? error.message : "";
- var message:String = resourceManager.getString(
- "rpc", "unexpectedException", [ errorMessage ])
+ var message:String = /*resourceManager.getString(
+ "rpc",*/ "unexpectedException" /*, [ errorMessage ])*/;
var fault:Fault = new Fault("WSDLError", message);
fault.rootCause = error;
var faultEvent2:FaultEvent = FaultEvent.createEvent(fault);
@@ -364,12 +364,12 @@ public dynamic class WebService
super.unEnqueueCalls(fault); // Jump straight to fault handling; ops cannot be initialized.
return;
}
- } */
+ }
/**
* @private
*/
- /* mx_internal function deriveHTTPService():HTTPService
+ mx_internal function deriveHTTPService():HTTPService
{
var httpService:HTTPService = new HTTPService();
httpService.asyncRequest = asyncRequest;
@@ -381,7 +381,7 @@ public dynamic class WebService
httpService.rootURL = rootURL;
httpService.headers = httpHeaders;
return httpService;
- } */
+ }
/**
* Initializes a new Operation.
@@ -393,7 +393,7 @@ public dynamic class WebService
* @playerversion AIR 1.1
* @productversion Royale 0.9.4
*/
- /* protected function initializeOperation(operation:Operation):void
+ protected function initializeOperation(operation:Operation):void
{
if (_wsdl != null)
{
@@ -402,32 +402,32 @@ public dynamic class WebService
operation.endpointURI = endpointURI;
operation.wsdlOperation = wsdlOp;
}
- } */
+ }
- /* private function dispatchFault(faultCode:String, faultString:String, faultDetail:String = null):void
+ private function dispatchFault(faultCode:String, faultString:String, faultDetail:String = null):void
{
var fault:Fault = new Fault(faultCode, faultString, faultDetail);
var event:FaultEvent = FaultEvent.createEvent(fault);
dispatchEvent(event);
- } */
+ }
//--------------------------------------------
// Backing variables for public getter/setters
//--------------------------------------------
- //private var _wsdlURL:String;
+ private var _wsdlURL:String;
//---------------------------------
// Internal properties
//---------------------------------
- /* private var _log:ILogger;
+ private var _log:ILogger;
private var _wsdlFault:Boolean;
private var _wsdl:mx.rpc.wsdl.WSDL;
- private var _wsdlLoader:WSDLLoader; */
+ private var _wsdlLoader:WSDLLoader;
//--------------------------------------------------------------------------
//
@@ -435,9 +435,9 @@ public dynamic class WebService
//
//--------------------------------------------------------------------------
- /* public static const DEFAULT_DESTINATION_HTTP:String = "DefaultHTTP";
+ public static const DEFAULT_DESTINATION_HTTP:String = "DefaultHTTP";
- public static const DEFAULT_DESTINATION_HTTPS:String = "DefaultHTTPS"; */
+ public static const DEFAULT_DESTINATION_HTTPS:String = "DefaultHTTPS";
}
}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/mxml/Operation.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/mxml/Operation.as
new file mode 100644
index 0000000..4f44b48
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/mxml/Operation.as
@@ -0,0 +1,272 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap.mxml
+{
+
+import mx.core.mx_internal;
+import mx.managers.CursorManager;
+import mx.messaging.events.MessageEvent;
+import mx.messaging.messages.AsyncMessage;
+import mx.messaging.messages.IMessage;
+import mx.resources.IResourceManager;
+import mx.resources.ResourceManager;
+import mx.rpc.AbstractService;
+import mx.rpc.AsyncToken;
+import mx.rpc.AsyncDispatcher;
+import mx.rpc.Fault;
+import mx.rpc.events.FaultEvent;
+import mx.rpc.mxml.Concurrency;
+import mx.rpc.mxml.IMXMLSupport;
+import mx.rpc.soap.WebService;
+import mx.rpc.soap.Operation;
+import mx.rpc.soap.mxml.WebService;
+import mx.validators.Validator;
+
+use namespace mx_internal;
+
+//[ResourceBundle("rpc")]
+
+/**
+* An Operation used specifically by WebServices. An Operation is an individual method on a service. An Operation can be called either by invoking the function of the same name on the service or by accessing the Operation
+* as a property on the service and calling the <code>send()</code> method.
+*
+* @langversion 3.0
+* @playerversion Flash 9
+* @playerversion AIR 1.1
+* @productversion Flex 3
+*/
+public class Operation extends mx.rpc.soap.Operation implements IMXMLSupport
+{
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Creates a new Operation.
+ *
+ * @param webService The web service upon which this Operation is invoked.
+ *
+ * @param name The name of this Operation.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function Operation(webService:mx.rpc.soap.WebService = null, name:String = null)
+ {
+ super(webService, name);
+
+ this.webService = mx.rpc.soap.mxml.WebService(webService);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ private var resourceManager:IResourceManager =
+ ResourceManager.getInstance();
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ [Inspectable(enumeration="multiple,single,last", defaultValue="multiple", category="General")]
+ /**
+ * The concurrency for this Operation. If it has not been explicitly set the setting from the WebService
+ * will be used.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get concurrency():String
+ {
+ if (_concurrencySet)
+ {
+ return _concurrency;
+ }
+ //else
+ return webService.concurrency;
+ }
+
+ /**
+ * @private
+ */
+ public function set concurrency(c:String):void
+ {
+ _concurrency = c;
+ _concurrencySet = true;
+ }
+
+ override mx_internal function setService(ro:AbstractService):void
+ {
+ super.setService(ro);
+
+ webService = mx.rpc.soap.mxml.WebService(ro);
+ }
+
+
+ /**
+ * Whether this operation should show the busy cursor while it is executing.
+ * If it has not been explicitly set the setting from the WebService
+ * will be used.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get showBusyCursor():Boolean
+ {
+ if (_showBusyCursorSet)
+ {
+ return _showBusyCursor;
+ }
+ //else
+ return webService.showBusyCursor;
+ }
+
+ public function set showBusyCursor(sbc:Boolean):void
+ {
+ _showBusyCursor = sbc;
+ _showBusyCursorSet = true;
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ override public function cancel(id:String = null) : AsyncToken
+ {
+ if (showBusyCursor)
+ {
+ CursorManager.removeBusyCursor();
+ }
+ return super.cancel(id);
+ }
+
+ /**
+ * @private
+ */
+ override public function send(... args:Array):AsyncToken
+ {
+ if (Concurrency.SINGLE == concurrency && (hasPendingInvocations() || activeCalls.hasActiveCalls()))
+ {
+ var token:AsyncToken = new AsyncToken(null);
+ var message:String = /*resourceManager.getString(
+ "rpc", */"pendingCallExists"/*);*/
+ var fault:Fault = new Fault("ConcurrencyError", message);
+ var faultEvent:FaultEvent = FaultEvent.createEvent(fault, token);
+ new AsyncDispatcher(dispatchRpcEvent, [faultEvent], 10);
+ return token;
+ }
+
+ return super.send.apply(null, args);
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Internal Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * Return the id for the NetworkMonitor
+ */
+ override mx_internal function getNetmonId():String
+ {
+ return webService.id;
+ }
+
+
+ override mx_internal function invoke(message:IMessage, token:AsyncToken = null):AsyncToken
+ {
+ if (showBusyCursor)
+ {
+ CursorManager.setBusyCursor();
+ }
+
+ return super.invoke(message, token);
+ }
+
+ /*
+ * Kill the busy cursor, find the matching call object and pass it back
+ */
+ override mx_internal function preHandle(event:MessageEvent):AsyncToken
+ {
+ if (showBusyCursor)
+ {
+ CursorManager.removeBusyCursor();
+ }
+
+ var wasLastCall:Boolean = activeCalls.wasLastCall(AsyncMessage(event.message).correlationId);
+ var token:AsyncToken = super.preHandle(event);
+
+ if (Concurrency.LAST == concurrency && !wasLastCall)
+ {
+ return null;
+ }
+ //else
+ return token;
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ private var _concurrency:String;
+
+ private var _concurrencySet:Boolean;
+
+ private var webService:mx.rpc.soap.mxml.WebService;
+
+ private var _showBusyCursor:Boolean;
+
+ private var _showBusyCursorSet:Boolean;
+}
+
+}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/mxml/WebService.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/mxml/WebService.as
new file mode 100644
index 0000000..56d6bd0
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/mxml/WebService.as
@@ -0,0 +1,376 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap.mxml
+{
+
+import org.apache.royale.events.Event;
+import mx.events.ErrorEvent;
+import org.apache.royale.events.IEventDispatcher;
+
+import mx.core.IMXMLObject;
+import mx.core.mx_internal;
+import mx.resources.IResourceManager;
+import mx.resources.ResourceManager;
+import mx.rpc.AbstractOperation;
+import mx.rpc.events.FaultEvent;
+import mx.rpc.mxml.Concurrency;
+import mx.rpc.mxml.IMXMLSupport;
+import mx.rpc.soap.mxml.Operation;
+import mx.rpc.soap.WebService;
+
+use namespace mx_internal;
+
+[ResourceBundle("rpc")]
+
+/**
+ * The <mx:WebService> tag gives you access to the operations of SOAP-compliant
+ * web services.
+ * @mxml
+ * <p>
+ * The <mx:WebService> tag accepts the following tag attributes:
+ * </p>
+ * <pre>
+ * <mx:WebService
+ * <b>Properties</b>
+ * concurrency="multiple|single|last"
+ * destination="<i>No default.</i>"
+ * id="<i>No default.</i>"
+ * serviceName="<i>No default.</i>"
+ * showBusyCursor="false|true"
+ * makeObjectsBindable="false|true"
+ * useProxy="false|true"
+ * wsdl="<i>No default.</i>"
+ *
+ * <b>Events</b>
+ * fault="<i>No default.</i>"
+ * result="<i>No default.</i>"
+ * />
+ * </pre>
+ * </p>
+ * <p>
+ * An <mx:WebService> tag can have multiple <mx:operation> tags, which have the following tag attributes:
+ * </p>
+ * <pre>
+ * <mx:operation
+ * <b>Properties</b>
+ * concurrency="multiple|single|last"
+ * name=<i>No default, required.</i>
+ * resultFormat="object|xml|e4x"
+ * makeObjectsBindable="false|true"
+ *
+ *
+ * <b>Events</b>
+ * fault=<i>No default.</i>
+ * result=<i>No default.</i>
+ * />
+ * </pre>
+ *
+ * An <mx:Operation> tag contains an <mx:request> tag.
+ * To specify an XML structure in an <mx:request> tag, you must set the value of the tag's
+ * <code>format</code> attribute to <code>"xml"</code>. Otherwise, the body is converted into Objects.
+ *
+ * @includeExample examples/WebServiceExample.mxml -noswf
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public dynamic class WebService extends mx.rpc.soap.WebService implements IMXMLSupport, IMXMLObject
+{
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Creates a new WebService component.
+ *
+ * @param destination The destination of the WebService, which should
+ * match a destination name in the services-config.xml file. If
+ * unspecified, the WebService component uses the DefaultHTTP destination.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function WebService(destination:String = null)
+ {
+ super(destination);
+
+ concurrency = Concurrency.MULTIPLE;
+ showBusyCursor = false;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ private var resourceManager:IResourceManager =
+ ResourceManager.getInstance();
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ [Inspectable(enumeration="multiple,single,last", defaultValue="multiple", category="General")]
+ /**
+ * Value that indicates how to handle multiple calls to the same service. The default
+ * value is multiple. The following values are permitted:
+ * <ul>
+ * <li>multiple - Existing requests are not cancelled, and the developer is
+ * responsible for ensuring the consistency of returned data by carefully
+ * managing the event stream. This is the default.</li>
+ * <li>single - Making only one request at a time is allowed on the method; additional requests made
+ * while a request is outstanding are immediately faulted on the client and are not sent to the server.</li>
+ * <li>last - Making a request causes the client to ignore a result or fault for any current outstanding request.
+ * Only the result or fault for the most recent request will be dispatched on the client.
+ * This may simplify event handling in the client application, but care should be taken to only use
+ * this mode when results or faults for requests may be safely ignored.</li>
+ * </ul>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get concurrency():String
+ {
+ return _concurrency;
+ }
+
+ /**
+ * @private
+ */
+ public function set concurrency(c:String):void
+ {
+ _concurrency = c;
+ }
+
+ /**
+ * Deprecated, use the appropriate destination instead, or if using a url, use <code>DefaultHTTP</code> or <code>DefaultHTTPS</code>.
+ * The deprecated behavior will simply update the destination if the default is being used.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ [Deprecated(replacement="channelSet")]
+ public function set protocol(protocol:String):void
+ {
+ if (destination == DEFAULT_DESTINATION_HTTP || destination == DEFAULT_DESTINATION_HTTP)
+ {
+ if (protocol == "http")
+ {
+ destination = DEFAULT_DESTINATION_HTTP;
+ }
+ else if (protocol == "https")
+ {
+ destination = DEFAULT_DESTINATION_HTTPS;
+ }
+ else
+ {
+ var message:String = resourceManager.getString(
+ "rpc", "unknownProtocol", [ protocol ]);
+ throw new Error(message);
+ }
+ }
+ }
+
+ [Deprecated(replacement="destination")]
+ public function get serviceName():String
+ {
+ return destination;
+ }
+
+ public function set serviceName(sn:String):void
+ {
+ destination = sn;
+ }
+
+ [Inspectable(defaultValue="false", category="General")]
+
+ /**
+ * If <code>true</code>, a busy cursor is displayed while a service is executing. The default
+ * value is <code>false</code>.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get showBusyCursor():Boolean
+ {
+ return _showBusyCursor;
+ }
+
+ public function set showBusyCursor(sbc:Boolean):void
+ {
+ _showBusyCursor = sbc;
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * This handler is called after the document fires the creationComplete event so that
+ * if errors occur while loading the WSDL all components will be ready to handle the fault.
+ * @private
+ */
+ public function creationComplete(event:Event):void
+ {
+ if (canLoadWSDL())
+ {
+ loadWSDL();
+ }
+ }
+
+ /**
+ * If this event is an error or fault, and the event type does not
+ * have a listener, we notify the parent document. If the
+ * parent document does not have a listener, then we throw
+ * a runtime exception. However, this is an asynchronous runtime
+ * exception which is only exposed through the debug player.
+ * A listener should be defined.
+ *
+ * @private
+ */
+ override public function dispatchEvent(event:Event):Boolean
+ {
+ if (hasEventListener(event.type))
+ {
+ return super.dispatchEvent(event);
+ }
+ else if ((event is FaultEvent && !hasTokenResponders(event)) || event is ErrorEvent)
+ {
+ var reason:String = (event is FaultEvent) ?
+ FaultEvent(event).fault.faultString :
+ ErrorEvent(event).text;
+
+ if (document && document.willTrigger(ErrorEvent.ERROR))
+ {
+ var evt:ErrorEvent = new ErrorEvent(ErrorEvent.ERROR, true, true);
+ evt.text = reason;
+ return document.dispatchEvent(evt);
+ }
+ else if (event is FaultEvent)
+ {
+ throw FaultEvent(event).fault;
+ }
+ else
+ {
+ var message:String = resourceManager.getString(
+ "rpc", "noListenerForEvent", [ reason ]);
+ throw new Error(message);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns an Operation of the given name. If the Operation wasn't
+ * created beforehand, a new <code>mx.rpc.soap.mxml.Operation</code> is
+ * created during this call. Operations are usually accessible by simply
+ * naming them after the service variable
+ * (<code>myService.someOperation</code>), but if your Operation name
+ * happens to match a defined method on the service
+ * (like <code>setCredentials</code>), you can use this method to get the
+ * Operation instead.
+ * @param name Name of the Operation.
+ * @return Operation that executes for this name.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ override public function getOperation(name:String):AbstractOperation
+ {
+ var o:Object = _operations[name];
+ var op:AbstractOperation = (o is AbstractOperation) ? AbstractOperation(o) : null;
+ if (op == null)
+ {
+ op = new Operation(this, name);
+ _operations[name] = op;
+ op.asyncRequest = asyncRequest;
+ op.setKeepLastResultIfNotSet(_keepLastResult);
+ initializeOperation(op as Operation);
+ }
+ return op;
+ }
+
+ /**
+ * Called automatically by the MXML compiler if the WebService is setup using a tag. If you create
+ * the WebService through ActionScript you may want to call this method yourself as it is useful for
+ * validating any arguments.
+ *
+ * @param document the MXML document on which this WebService lives
+ * @param id the id of this WebService within the document
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function initialized(document:Object, id:String):void
+ {
+ this.document = document;
+ this.id = id;
+ if (document is IEventDispatcher)
+ {
+ IEventDispatcher(document).addEventListener("creationComplete", creationComplete);
+ }
+
+ initialize();
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ mx_internal var document:Object;
+
+ mx_internal var id:String;
+
+ private var _concurrency:String;
+
+ private var _showBusyCursor:Boolean;
+}
+
+}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/ApacheDocumentType.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/ApacheDocumentType.as
new file mode 100644
index 0000000..399e092
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/ApacheDocumentType.as
@@ -0,0 +1,55 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap.types
+{
+
+import mx.rpc.soap.SOAPDecoder;
+import mx.rpc.soap.SOAPEncoder;
+import mx.rpc.xml.ContentProxy;
+import mx.utils.object_proxy;
+import mx.utils.ObjectProxy;
+
+use namespace object_proxy;
+
+[ExcludeClass]
+
+/**
+ * Marshalls between an Apache SOAP Document type and ActionScript XML.
+ * @private
+ */
+public class ApacheDocumentType implements ICustomSOAPType
+{
+ public function ApacheDocumentType()
+ {
+ super();
+ }
+
+ public function encode(encoder:SOAPEncoder, parent:XML, name:QName, value:*, restriction:XML = null):void
+ {
+ encoder.setValue(parent, value);
+ }
+
+ public function decode(decoder:SOAPDecoder, parent:*, name:*, value:*, restriction:XML = null):void
+ {
+ decoder.setValue(parent, name, XML(value).elements());
+ }
+
+}
+}
\ No newline at end of file
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/DataSetType.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/DataSetType.as
new file mode 100644
index 0000000..060004a
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/DataSetType.as
@@ -0,0 +1,165 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap.types
+{
+
+import mx.rpc.soap.SOAPConstants;
+import mx.rpc.soap.SOAPDecoder;
+import mx.rpc.soap.SOAPEncoder;
+import mx.rpc.xml.ContentProxy;
+import mx.rpc.xml.Schema;
+import mx.rpc.xml.SchemaConstants;
+import mx.rpc.xml.TypeIterator;
+import mx.rpc.xml.XMLDecoder;
+import mx.utils.ObjectProxy;
+import mx.utils.object_proxy;
+
+use namespace object_proxy;
+
+[ExcludeClass]
+
+/**
+ * Marshalls between a .NET DataSet diffgram and ActionScript.
+ * @private
+ */
+public class DataSetType implements ICustomSOAPType
+{
+ public function DataSetType()
+ {
+ super();
+ }
+
+ public function encode(encoder:SOAPEncoder, parent:XML, name:QName, value:*, restriction:XML = null):void
+ {
+ throw new Error("Unsupported operation - .NET DataSet diffgrams cannot be sent from client.");
+ }
+
+ /**
+ * Decode a response part that contains a serialized DataSet.
+ *
+ * @param SOAPDecoder the decoder instance
+ * @param * parent object (content proxy)
+ * @param name ignored
+ * @param value the top level XML node. Must have two child elements, schema and diffgram.
+ * @param restriction ignored
+ *
+ * @private
+ */
+ public function decode(decoder:SOAPDecoder, parent:*, name:*, value:*, restriction:XML = null):void
+ {
+ if (parent is ContentProxy)
+ ContentProxy(parent).object_proxy::isSimple = false;
+
+ schemaConstants = decoder.schemaConstants;
+
+ var schemaXML:XML = XML(value).elements(schemaConstants.schemaQName)[0];
+
+ //TODO: handle <diffgr:before> and <diffgr:errors>
+ var rootDataXML:XML = XML(value).elements(SOAPConstants.diffgramQName)[0].elements()[0];
+ var dataSet:* = parent;
+ var tableDefinitions:Object = processTables(schemaXML);
+
+ // First create .Tables and .Columns and .Rows for each table
+ var tableCollection:* = decoder.createContent();
+ if (tableCollection is ContentProxy)
+ ContentProxy(tableCollection).object_proxy::isSimple = false;
+
+ for (var tblName:String in tableDefinitions)
+ {
+ var tableObj:* = decoder.createContent();
+ if (tableObj is ContentProxy)
+ ContentProxy(tableObj).object_proxy::isSimple = false;
+ decoder.setValue(tableObj, "Columns",
+ processColumns(decoder, tableDefinitions[tblName]));
+ decoder.setValue(tableObj, "Rows",
+ decoder.createIterableValue());
+ decoder.setValue(tableCollection, tblName, tableObj);
+ }
+
+ if (rootDataXML != null)
+ {
+ var schema:Schema = new Schema(schemaXML);
+ decoder.schemaManager.addSchema(schema, false);
+
+ for (tblName in tableCollection)
+ {
+ for each (var rowXML:XML in rootDataXML.elements(tblName))
+ {
+ var rowObj:* = decoder.decode(rowXML, rowXML.name() as QName, null, tableDefinitions[tblName]);
+ TypeIterator.push(tableCollection[tblName]["Rows"], rowObj);
+ }
+ }
+
+ decoder.schemaManager.releaseScope();
+ }
+
+ decoder.setValue(dataSet, "Tables", tableCollection);
+ }
+
+ /**
+ * Parse table information out of the inline schema
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private function processTables(schemaXML:XML):Object
+ {
+ // The table definitions are elements inside a choice inside
+ // a complexType inside a top-level element in the schema
+ var tblsXMLList:XMLList = schemaXML.elements(schemaConstants.elementTypeQName)[0]
+ .elements(schemaConstants.complexTypeQName)[0]
+ .elements(schemaConstants.choiceQName)[0]
+ .elements(schemaConstants.elementTypeQName);
+
+ var tables:Object = {};
+ for each (var tblXML:XML in tblsXMLList)
+ tables[tblXML.attribute("name")] = tblXML;
+
+ return tables;
+ }
+
+ /**
+ * Parse column definitions out of a table definition
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private function processColumns(decoder:SOAPDecoder, tableXML:XML):*
+ {
+ // The column definitions are elements inside a sequence inside
+ // a complexType in the table definition element.
+ var colsXMLList:XMLList = tableXML.elements(schemaConstants.complexTypeQName)[0]
+ .elements(schemaConstants.sequenceQName)[0]
+ .elements(schemaConstants.elementTypeQName);
+
+ var columns:* = decoder.createIterableValue();
+ for each (var colXML:XML in colsXMLList)
+ TypeIterator.push(columns, colXML.attribute("name").toString());
+
+ return columns;
+ }
+
+ private var schemaConstants:SchemaConstants;
+}
+}
\ No newline at end of file
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/ICustomSOAPType.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/ICustomSOAPType.as
new file mode 100644
index 0000000..d43fe16
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/ICustomSOAPType.as
@@ -0,0 +1,41 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap.types
+{
+
+import mx.rpc.soap.SOAPDecoder;
+import mx.rpc.soap.SOAPEncoder;
+
+[ExcludeClass]
+
+/**
+ * Implementations handle encoding and decoding between custom SOAP types and
+ * ActionScript.
+ *
+ * @private
+ */
+public interface ICustomSOAPType
+{
+ function encode(encoder:SOAPEncoder, parent:XML, name:QName, value:*, restriction:XML = null):void;
+
+ function decode(decoder:SOAPDecoder, parent:*, name:*, value:*, restriction:XML = null):void;
+}
+
+}
\ No newline at end of file
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/MapType.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/MapType.as
new file mode 100644
index 0000000..65a0198
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/MapType.as
@@ -0,0 +1,168 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap.types
+{
+
+import mx.utils.ByteArray;
+
+import mx.rpc.soap.SOAPDecoder;
+import mx.rpc.soap.SOAPEncoder;
+import mx.rpc.xml.ContentProxy;
+import mx.rpc.xml.SchemaConstants;
+import mx.rpc.xml.SchemaDatatypes;
+import mx.rpc.xml.SchemaMarshaller;
+import mx.utils.object_proxy;
+
+use namespace object_proxy;
+
+[ExcludeClass]
+
+/**
+ * Marshalls between the SOAP representation of a java.util.Map and
+ * ActionScript.
+ * @private
+ */
+public class MapType implements ICustomSOAPType
+{
+ public function MapType()
+ {
+ super();
+ }
+
+ public function encode(encoder:SOAPEncoder, parent:XML, name:QName, value:*, restriction:XML = null):void
+ {
+ var datatypes:SchemaDatatypes = encoder.schemaManager.schemaDatatypes;
+
+ for (var item:String in value)
+ {
+ var itemNode:XML = encoder.createElement(itemQName);
+ var keyNode:XML = encoder.createElement(keyQName);
+ var valueNode:XML = encoder.createElement(valueQName);
+
+ // TODO: a better solution is needed for both key and value processing here...
+ if (item != null)
+ encoder.encodeType(datatypes.stringQName, keyNode, keyQName, item);
+ else
+ encoder.setValue(keyNode, null);
+
+ encoder.setValue(itemNode, keyNode);
+
+ //FIXME: We need a public API to handle any, even complex values
+ var keyValue:Object = value[item];
+ if (keyValue != null)
+ {
+ // FIXME: completely.
+ var typeLocalName:String = "string";
+ if (keyValue is Number)
+ {
+ if (keyValue is uint)
+ {
+ typeLocalName = "unsignedInt";
+ }
+ else if (keyValue is int)
+ {
+ typeLocalName = "int";
+ }
+ else
+ {
+ typeLocalName = "double";
+ }
+ }
+ else if (keyValue is Boolean)
+ {
+ typeLocalName = "boolean";
+ }
+ else if (keyValue is String)
+ {
+ typeLocalName = "string";
+ }
+ else if (keyValue is ByteArray)
+ {
+ if (SchemaMarshaller.byteArrayAsBase64Binary)
+ typeLocalName = "base64Binary";
+ else
+ typeLocalName = "hexBinary";
+ }
+ else if (keyValue is Date)
+ {
+ typeLocalName = "dateTime";
+ }
+
+ var constants:SchemaConstants = encoder.schemaManager.schemaConstants;
+ var type:QName = (typeLocalName != null) ? new QName(constants.xsdURI, typeLocalName) : null;
+
+ encoder.encodeType(type, valueNode, valueQName, keyValue);
+ }
+ else
+ {
+ encoder.setValue(valueNode, null);
+ }
+
+ encoder.setValue(itemNode, valueNode);
+ encoder.setValue(parent, itemNode);
+ }
+ }
+
+ public function decode(decoder:SOAPDecoder, parent:*, name:*, value:*, restriction:XML = null):void
+ {
+ if (parent is ContentProxy)
+ parent.object_proxy::isSimple = false;
+
+ var constants:SchemaConstants = decoder.schemaManager.schemaConstants;
+ var mapValue:XML = value as XML;
+
+ for each (var item:XML in mapValue.elements())
+ {
+ var key:Object;
+ var itemValue:Object;
+ for each (var itemChild:XML in item.elements())
+ {
+ var typeName:String = itemChild.attribute(constants.typeAttrQName);
+ var type:QName;
+ if (typeName != null && typeName != "")
+ type = decoder.schemaManager.getQNameForPrefixedName(typeName, itemChild);
+ else
+ type = constants.anyTypeQName;
+
+ if (itemChild.localName() == "key")
+ {
+ key = decoder.createContent();
+ decoder.decodeType(type, key, itemChild.name() as QName, itemChild);
+ }
+ else if (itemChild.localName() == "value")
+ {
+ itemValue = decoder.createContent();
+ decoder.decodeType(type, itemValue, itemChild.name() as QName, itemChild);
+ }
+ else
+ {
+ throw new Error("Apache Map datatype must only contain key/value pairs.");
+ }
+ }
+ decoder.setValue(parent, key, itemValue);
+ }
+ }
+
+ public static var itemQName:QName = new QName("", "item");
+ public static var keyQName:QName = new QName("", "key");
+ public static var valueQName:QName = new QName("", "value");
+}
+
+}
\ No newline at end of file
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/QueryBeanType.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/QueryBeanType.as
new file mode 100644
index 0000000..4343abc
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/QueryBeanType.as
@@ -0,0 +1,107 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap.types
+{
+
+import mx.rpc.soap.SOAPDecoder;
+import mx.rpc.soap.SOAPEncoder;
+import mx.rpc.xml.ContentProxy;
+import mx.rpc.xml.TypeIterator;
+import mx.rpc.xml.XMLDecoder;
+import mx.utils.object_proxy;
+import mx.utils.ObjectProxy;
+
+use namespace object_proxy;
+
+[ExcludeClass]
+
+/**
+ * Marshalls between the SOAP representation of a ColdFusion Query (aka a
+ * "Query Bean") and ActionScript.
+ * @private
+ */
+public class QueryBeanType implements ICustomSOAPType
+{
+ public function QueryBeanType()
+ {
+ super();
+ }
+
+ public function encode(encoder:SOAPEncoder, parent:XML, name:QName, value:*, restriction:XML = null):void
+ {
+ throw new Error("Unsupported operation - Query Beans cannot be sent to ColdFusion.");
+ }
+
+ public function decode(decoder:SOAPDecoder, parent:*, name:*, value:*, restriction:XML = null):void
+ {
+ var beanXML:XML = value as XML;
+
+ var returnVal:*;
+ if (decoder.makeObjectsBindable)
+ returnVal = new XMLDecoder.listClass();
+ else
+ returnVal = [];
+
+ // Query Column Names or "columnList" section
+ var colXML:XML = beanXML.columnList[0];
+ if (colXML == null)
+ return;
+
+ var columnsXMLList:XMLList = colXML.elements();
+ var columnNames:Array = [];
+ for each (var columnName:XML in columnsXMLList)
+ {
+ columnNames.push(columnName.toString());
+ }
+
+ // Query Rows or "data" section
+ var dataXML:XML = beanXML.data[0];
+ if (dataXML == null)
+ return;
+
+ var soapArrayType:SOAPArrayType = new SOAPArrayType();
+ var tempParent:Array = [];
+ soapArrayType.decode(decoder, tempParent, name, dataXML, restriction);
+
+ // Turn the Array of Arrays into an Array of Objects keyed by a
+ // column name to value...
+ var iterator:TypeIterator = new TypeIterator(tempParent);
+ while (iterator.hasNext())
+ {
+ var item:* = iterator.next();
+ var resultItem:*;
+ if (decoder.makeObjectsBindable)
+ resultItem = new ObjectProxy();
+ else
+ resultItem = {};
+
+ for (var i:uint = 0; i < columnNames.length; i++)
+ {
+ resultItem[columnNames[i]] = item[i];
+ }
+
+ TypeIterator.push(returnVal, resultItem);
+ }
+
+ decoder.setValue(parent, name, returnVal);
+ }
+}
+
+}
\ No newline at end of file
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/RowSetType.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/RowSetType.as
new file mode 100644
index 0000000..fcbcf1d
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/RowSetType.as
@@ -0,0 +1,119 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap.types
+{
+
+import mx.rpc.soap.SOAPDecoder;
+import mx.rpc.soap.SOAPEncoder;
+import mx.rpc.xml.ContentProxy;
+import mx.rpc.xml.TypeIterator;
+import mx.utils.object_proxy;
+
+use namespace object_proxy;
+
+[ExcludeClass]
+
+/**
+ * Marshalls between the SOAP representation of a ColdFusion Query (aka a
+ * "Query Bean") and ActionScript.
+ * @private
+ */
+public class RowSetType implements ICustomSOAPType
+{
+ public function RowSetType()
+ {
+ super();
+ }
+
+ public function encode(encoder:SOAPEncoder, parent:XML, name:QName, value:*, restriction:XML = null):void
+ {
+ throw new Error("Unsupported operation - RowSet cannot be sent to a server.");
+ }
+
+ // Custom deserialization for rowsets, which look like this:
+ //
+ // <rowSet>
+ // <fields>
+ // <field type="xsd:string">Field1</field>
+ // <field type="xsd:int">Field2</field>
+ // </fields>
+ // <data>
+ // <item>
+ // <d>a string</d>
+ // <d>52</d>
+ // </item>
+ // </data>
+ // </rowSet>
+ //
+ // (That would decode into an Array with a single object {Field1:"a string", Field2:52})
+ //
+ public function decode(decoder:SOAPDecoder, parent:*, name:*, value:*, restriction:XML = null):void
+ {
+ if (parent is ContentProxy)
+ parent.object_proxy::isSimple = false;
+
+ var rowSetNode:XML = value as XML;
+
+ var returnVal:Array = [];
+ var types:Array = [];
+ var fields:Array = [];
+
+ var fieldNodes:XMLList = rowSetNode.elements()[0].elements();
+ var i:uint;
+
+ // Gather each of the field names and types
+ for each (var field:XML in fieldNodes)
+ {
+ var typeAttr:String = field.attribute("type").toString();
+ var typeQName:QName;
+
+ if (typeAttr != null && typeAttr != "")
+ typeQName = decoder.schemaManager.getQNameForPrefixedName(typeAttr, field);
+
+ if (typeQName == null)
+ typeQName = decoder.schemaManager.schemaDatatypes.stringQName;
+
+ types[i] = typeQName;
+ fields[i] = field.text().toString();
+ i++;
+ }
+
+ var items:XMLList = rowSetNode.elements()[1].elements();
+
+ // Process each Row using field names and types
+ i = 0;
+ for each (var item:XML in items)
+ {
+ var columns:XMLList = item.elements();
+ var row:* = decoder.createContent();
+ var j:uint = 0;
+ for each (var column:XML in columns)
+ {
+ row[fields[j]] = decoder.decode(column, null, types[j] as QName);
+ j++;
+ }
+ returnVal[i] = row;
+ i++;
+ }
+
+ decoder.setValue(parent, name, returnVal);
+ }
+}
+}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/SOAPArrayType.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/SOAPArrayType.as
new file mode 100644
index 0000000..ccad810
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/soap/types/SOAPArrayType.as
@@ -0,0 +1,614 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.soap.types
+{
+
+import mx.collections.IList;
+import mx.rpc.soap.SOAPConstants;
+import mx.rpc.soap.SOAPEncoder;
+import mx.rpc.soap.SOAPDecoder;
+import mx.rpc.wsdl.WSDLConstants;
+import mx.rpc.xml.ContentProxy;
+import mx.rpc.xml.SchemaConstants;
+import mx.rpc.xml.SchemaDatatypes;
+import mx.rpc.xml.SchemaManager;
+import mx.rpc.xml.SchemaMarshaller;
+import mx.rpc.xml.SchemaProcessor;
+import mx.rpc.xml.TypeIterator;
+import mx.rpc.xml.XMLEncoder;
+import mx.rpc.xml.XMLDecoder;
+import mx.utils.object_proxy;
+import mx.utils.StringUtil;
+import mx.utils.ObjectUtil;
+
+use namespace object_proxy;
+
+[ExcludeClass]
+
+/**
+ * Marshalls SOAP 1.1 encoded Arrays between XML and ActionScript.
+ * @private
+ */
+public class SOAPArrayType implements ICustomSOAPType
+{
+ public function SOAPArrayType()
+ {
+ super();
+ itemName = new QName("", "item");
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Encode an ActionScript Array as a SOAP encoded Array in XML.
+ *
+ * TODO: Support soap array offset and item position attributes?
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function encode(encoder:SOAPEncoder, parent:XML, name:QName, value:*, restriction:XML = null):void
+ {
+ processor = encoder;
+ soapConstants = encoder.soapConstants;
+ schemaManager = encoder.schemaManager;
+ schemaConstants = schemaManager.schemaConstants;
+
+ // HACK: Handle the MXML artifact where by <mx:request> based syntax
+ // for SOAP parameters can lead to Arrays of properties being wrapped
+ // in an Object with a single property with the Array as its value.
+ value = unwrapMXMLArray(value);
+
+ // FIXME: Should we look in the restriction definition to see
+ // if a sequence was provided to define the element name? The
+ // SOAPArrayEncoder will just assume "item" for now...
+
+ if (restriction != null)
+ {
+ // Look for arrayType under <restriction base="soap-enc:Array">
+ var wsdlArrayType:String = determineWSDLArrayType(restriction, encoder.wsdlOperation.wsdlConstants);
+
+ // Parse the arrayType looking for XML Schema type, dimensions and size info
+ parseWSDLArrayType(wsdlArrayType);
+ }
+
+ schemaType = schemaManager.getQNameForPrefixedName(schemaTypeName, restriction);
+
+ // Ensure SOAP encoding namespace has been declared
+ // e.g. <myArray xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
+ parent.addNamespace(soapConstants.encodingNamespace);
+
+ // Add SOAP encoding arrayType attribute for parent node
+ // e.g. <myArray soapenc:arrayType="xsd:int[][3]">
+ encodeDimensionInformation(parent, dimensionString);
+ encodeArray(parent, dimensions, value);
+ }
+
+ /**
+ * Decodes a SOAP encoded array assuming the XML Schema type definiton
+ * uses a complexType restriction base to declare the array type, e.g.
+ *
+ * <pre>
+ * <xsd:complexType name="Example">
+ * <xsd:complexContent mixed="false">
+ * <xsd:restriction base="soapenc:Array">
+ * <xsd:attribute wsdl:arrayType="tns:Example[]" ref="soapenc:arrayType"
+ * xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" />
+ * </xsd:restriction>
+ * </xsd:complexContent>
+ * </xsd:complexType>
+ * </pre>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function decode(decoder:SOAPDecoder, parent:*, name:*, value:*, restriction:XML = null):void
+ {
+ processor = decoder;
+ soapConstants = decoder.soapConstants;
+ schemaManager = decoder.schemaManager;
+ schemaConstants = schemaManager.schemaConstants;
+
+ // Handle short-hand syntax for SOAP encoded arrayType
+ var valueXML:XML = value as XML;
+ if (valueXML != null)
+ {
+ var arrayTypeString:String = valueXML.@[soapConstants.soapencArrayTypeQName];
+ if (arrayTypeString != null && arrayTypeString != "")
+ {
+ parseWSDLArrayType(arrayTypeString);
+ schemaType = schemaManager.getQNameForPrefixedName(schemaTypeName, valueXML);
+ }
+ }
+
+ // Otherwise look for arrayType under <restriction base="soap-enc:Array">
+ if (schemaType == null && restriction != null)
+ {
+ var wsdlArrayType:String = determineWSDLArrayType(restriction, decoder.wsdlOperation.wsdlConstants);
+ parseWSDLArrayType(wsdlArrayType);
+ schemaType = schemaManager.getQNameForPrefixedName(schemaTypeName, restriction);
+ }
+
+ if (schemaType != null)
+ {
+ // Change the parent to an Array. Parent is originally created with
+ // createContent in the XMLDecoder, before decodeType is called. We
+ // need to make sure that the created parent can be used as an array.
+
+ if (parent is ContentProxy)
+ {
+ var proxy:ContentProxy = parent as ContentProxy;
+ proxy.object_proxy::isSimple = false;
+ // Only replace parent with iterable value if not already an IList
+ // or an Array.
+ if (!(proxy.object_proxy::content is IList) && !(proxy.object_proxy::content is Array))
+ proxy.object_proxy::content = decoder.createIterableValue();
+ }
+
+ decodeArray(parent, dimensions, value, decoder.makeObjectsBindable);
+ }
+ }
+
+ /**
+ * Recursively called to encode a set of dimensions at a particular level
+ * (potentially many of a jagged/nested array) of an Array.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private function encodeArray(parent:XML, dimensions:Array, value:*):void
+ {
+ // Add XSI attribute for SOAP encoded Array
+ // e.g. <myArray xsi:type="soapenc:Array" />
+ var typeAttr:String = schemaConstants.getXSIToken(schemaConstants.typeAttrQName)
+ parent.@[typeAttr] = soapConstants.getSOAPEncodingToken(soapConstants.soapencArrayQName);
+
+ if (!TypeIterator.isIterable(value))
+ value = [value];
+
+ var iter:TypeIterator = new TypeIterator(value);
+ var d:uint = 0;
+
+ if (dimensions.length > 0)
+ {
+ // For a non-jagged Array we have a single entry that describes the
+ // length of each dimension (which can be unbounded), otherwise
+ // we have multiple entries, but the first is used to describe
+ // the number of jagged arrays at this level...
+ var entry:* = dimensions[0];
+ if (!(entry is Array))
+ entry = [entry];
+
+ for each (var dimensionSize:int in entry)
+ {
+ var itemValue:*;
+ var nestedDimension:Array;
+ var nestedDimensionString:String;
+ var nestedArray:XML;
+ d++;
+
+ if (dimensionSize < 0)
+ {
+ // Unbounded dimension
+ if (dimensions.length == 1)
+ {
+ while (iter.hasNext())
+ {
+ itemValue = iter.next();
+ nestedArray = <{itemName.localName}/>;
+ encodeArrayItem(nestedArray, itemValue);
+ parent.appendChild(nestedArray);
+ }
+ }
+ else if (dimensions.length > 1)
+ {
+ nestedDimensionString = "[]";
+
+ // FIXME: We should detect before iterating whether
+ // sufficient definitions exist for the number of
+ // jagged arrays provided in the value...
+ while (iter.hasNext())
+ {
+ itemValue = iter.next();
+ nestedDimension = dimensions[d];
+ nestedArray = <{itemName.localName}/>;
+ encodeDimensionInformation(nestedArray, nestedDimensionString);
+ encodeArray(nestedArray, nestedDimension, itemValue);
+ parent.appendChild(nestedArray);
+ }
+ }
+ }
+ else
+ {
+ // Bounded dimension
+ for (var i:uint = 0; i < dimensionSize; i++)
+ {
+ itemValue = TypeIterator.getItemAt(iter.value, i);
+ if (dimensions.length == 1)
+ {
+ nestedArray = <{itemName.localName}/>;
+ encodeArrayItem(nestedArray, itemValue);
+ parent.appendChild(nestedArray);
+ }
+ else if (dimensions.length > 1)
+ {
+ nestedDimensionString = "[" + dimensionSize + "]";
+
+ // FIXME: We should detect invalid no. of nested
+ // dimensions compared to value...
+ nestedDimension = dimensions[d];
+ nestedArray = <{itemName.localName}/>;
+ encodeDimensionInformation(nestedArray, nestedDimensionString);
+ encodeArray(nestedArray, nestedDimension, itemValue);
+ parent.appendChild(nestedArray);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private function decodeArray(parent:*, dimensions:Array, value:*, makeObjectsBindable:Boolean):void
+ {
+ // If we have a single node, grab the XMLList of child elements as
+ // the actual Array members...
+ if (value is XML)
+ {
+ var dataXML:XML = value as XML;
+ value = dataXML.elements();
+ }
+
+ if (!TypeIterator.isIterable(value) && value != "")
+ value = [value];
+
+ var iter:TypeIterator = new TypeIterator(value);
+ var d:uint = 0;
+
+ if (dimensions.length > 0)
+ {
+ // For a non-jagged Array we have a single entry that describes the
+ // length of each dimension (which can be unbounded), otherwise
+ // we have multiple entries, but the first is used to describe
+ // the number of jagged arrays at this level...
+ var entry:* = dimensions[0];
+ if (!(entry is Array))
+ entry = [entry];
+
+ for each (var dimensionSize:int in entry)
+ {
+ var itemValue:*;
+ var nestedDimension:Array;
+ var nestedArray:*;
+ d++;
+
+ if (dimensionSize < 0)
+ {
+ // Unbounded dimension
+ if (dimensions.length == 1)
+ {
+ while (iter.hasNext())
+ {
+ itemValue = iter.next();
+ decodeArrayItem(parent, itemValue);
+ }
+ }
+ else if (dimensions.length > 1)
+ {
+ // FIXME: We should detect before iterating whether
+ // sufficient definitions exist for the number of
+ // jagged arrays provided in the value...
+ while (iter.hasNext())
+ {
+ itemValue = iter.next();
+ nestedDimension = dimensions[d];
+ nestedArray = SOAPDecoder(processor).createIterableValue(schemaType);
+ decodeArray(nestedArray, nestedDimension, itemValue, makeObjectsBindable);
+ TypeIterator.push(parent, nestedArray);
+ }
+ }
+ }
+ else
+ {
+ // Bounded dimension
+ for (var i:uint = 0; i < dimensionSize; i++)
+ {
+ itemValue = TypeIterator.getItemAt(iter.value, i);
+ if (dimensions.length == 1)
+ {
+ decodeArrayItem(parent, itemValue);
+ }
+ else if (dimensions.length > 1)
+ {
+ // FIXME: We should detect invalid no. of nested
+ // dimensions compared to value...
+ nestedDimension = dimensions[d];
+ nestedArray = SOAPDecoder(processor).createIterableValue(schemaType);
+ decodeArray(nestedArray, nestedDimension, itemValue, makeObjectsBindable);
+ TypeIterator.push(parent, nestedArray);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private function encodeArrayItem(item:XML, value:*):void
+ {
+ var encoder:SOAPEncoder = processor as SOAPEncoder;
+ encoder.encodeType(schemaType, item, itemName, value);
+ }
+
+ private function decodeArrayItem(parent:*, value:*):void
+ {
+ var decoder:SOAPDecoder = processor as SOAPDecoder;
+ var item:* = decoder.createContent(schemaType);
+ decoder.decodeType(schemaType, item, itemName, value);
+ decoder.setValue(parent, itemName, item, schemaType);
+ }
+
+ private function encodeDimensionInformation(parent:XML, dimensionString:String):void
+ {
+ var uri:String = schemaType.uri;
+ var prefix:String = schemaManager.getOrCreatePrefix(uri);
+ var ns:Namespace = new Namespace(prefix, uri);
+ var arrayTypeString:String = prefix + ":" + schemaType.localName;
+ arrayTypeString = arrayTypeString + dimensionString;
+ parent.addNamespace(ns);
+ var arrayTypeAttr:String = soapConstants.getSOAPEncodingToken(soapConstants.soapencArrayTypeQName);
+ parent.@[arrayTypeAttr] = arrayTypeString;
+ }
+
+ private function getSingleElementFromNode(node:XML, ...types:Array):XML
+ {
+ var elements:XMLList = node.elements();
+ for each (var element:XML in elements)
+ {
+ if (types != null && types.length > 0)
+ {
+ for each (var type:QName in types)
+ {
+ if (element.name() == type)
+ {
+ return element;
+ }
+ }
+ }
+ else
+ {
+ return element;
+ }
+ }
+ return null;
+ }
+
+ private function determineWSDLArrayType(restriction:XML, wsdlConstants:WSDLConstants):String
+ {
+ var arrayTypeString:String = "";
+
+ // We expect a <attribute ref="soap-enc:ArrayType"> in the restriction
+ var attribute:XML = getSingleElementFromNode(restriction, schemaConstants.attributeQName);
+ if (attribute != null)
+ {
+ // The attribute must declare that it is using the SOAP encoded Array
+ // type using a ref="soapenc:Array" attribute...
+ var soapencArrayTypeRef:String = attribute.@ref;
+ var soapencArrayType:QName = schemaManager.getQNameForPrefixedName(soapencArrayTypeRef, attribute, true);
+ if (soapencArrayType == soapConstants.soapencArrayTypeQName)
+ {
+ // Next, we look for wsdl:arrayType attribute
+ arrayTypeString = attribute.attribute(wsdlConstants.wsdlArrayTypeQName).toString();
+ }
+ }
+
+ return arrayTypeString;
+ }
+
+
+ /**
+ * Parses the WSDL arrayType to determine the type of the members in a SOAP
+ * encoded array, the rank and dimensions of the Array, and potentially
+ * the size of the Array (if not unbounded).
+ *
+ * TODO: Support SOAP 1.2 syntax for Arrays.
+ *
+ * Examples:
+ * 1. An unbounded Array of strings:
+ * <xsd:attribute ref="soap-enc:arrayType" wsdl:arrayType="xsd:string[]" />
+ *
+ * 2. An Array with 5 members of type "Array of integers":
+ * <xsd:attribute ref="soap-enc:arrayType" wsdl:arrayType="xsd:int[][5]" />
+ *
+ * 3. An Array with 3 members of type "two-dimensional arrays of integers":
+ * <xsd:attribute ref="soap-enc:arrayType" wsdl:arrayType="xsd:int[,][3]" />
+ *
+ * @param wsdlArrayType The value of the wsdl:arrayType attribute that
+ * specifies the signature of the SOAP encoded array including the type and
+ * the dimensions and size information.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private function parseWSDLArrayType(wsdlArrayType:String):void
+ {
+ // Isolate the prefixed schemaType from the rank and length information
+ // QName *(rank) size
+ var typeName:String;
+ var startBracket:int = wsdlArrayType.indexOf("[");
+ var endBracket:int = -1;
+
+ if (startBracket > 0)
+ {
+ dimensionString = wsdlArrayType.substring(startBracket);
+ schemaTypeName = StringUtil.trim(wsdlArrayType.substring(0, startBracket));
+ endBracket = wsdlArrayType.indexOf("]", startBracket);
+ }
+
+ if (startBracket < 0 || endBracket < 0)
+ {
+ throw new Error("Invalid SOAP-encoded Array type '" + wsdlArrayType + "'.");
+ }
+
+ var rankOrSizeString:String = StringUtil.trim(wsdlArrayType.substring(startBracket));
+ var dimsArray:Array = rankOrSizeString.split("[");
+ var currentDimension:Array = dimensions;
+
+ // We process the rank from right to left as the size of the type is the
+ // right most set of brackets. Jagged arrays are treated as a nested
+ // set of dimensions.
+ for (var i:int = dimsArray.length - 1; i >= 0; i--)
+ {
+ var dimsString:String = dimsArray[i] as String;
+
+ // We should have at the very least a close bracket
+ if (dimsString.length > 0)
+ {
+ // A rank may define none [], one [x], or multiple dimensions [x,y]
+ if (currentDimension.length > 0)
+ {
+ var newDimension:Array = [];
+ currentDimension.push(newDimension);
+ currentDimension = newDimension;
+ }
+ parseDimensions(wsdlArrayType, dimsString, currentDimension);
+ }
+ }
+ }
+
+ private function parseDimensions(wsdlArrayType:String, dimensionsString:String, currentDimension:Array):void
+ {
+ // Remove leading or trailing braces from [x,y,...] to reveal x,y,...
+ if (dimensionsString.charAt(0) == "[")
+ dimensionsString = dimensionsString.substring(1);
+
+ if (dimensionsString.charAt(dimensionsString.length - 1) == "]")
+ dimensionsString = dimensionsString.substring(0, dimensionsString.length - 1);
+
+ var dim:Number;
+ var dimensions:Array = dimensionsString.split(",");
+ if (dimensions.length > 0)
+ {
+ // Process each dimension from x,y,... as "x" or "y" etc...
+ for each (var dimString:String in dimensions)
+ {
+ if (dimString.length > 0)
+ {
+ dim = parseInt(dimString);
+ if (!isNaN(dim) && dim < int.MAX_VALUE)
+ {
+ currentDimension.push(int(dim));
+ }
+ else
+ {
+ throw new Error("Invalid dimension '" + dimString + "' for SOAP encoded Array type '" + wsdlArrayType +"'.");
+ }
+ }
+ else
+ {
+ // Unbounded dimension, record as -1
+ currentDimension.push(-1);
+ }
+ }
+ }
+ }
+
+ /**
+ * Attempts to unwrap MXML Array properties that are wrapped in an Object
+ * with a single child element that is an Array itself.
+ *
+ * e.g. the following MXML:
+ *
+ * <mx:request>
+ * <inputArray>
+ * <item>A</item>
+ * <item>B</item>
+ * </inputArray>
+ * </mx:request>
+ *
+ * would return an Object for inputArray as {item:[A,B]} instead of
+ * simply the Array [A,B].
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private function unwrapMXMLArray(value:*):*
+ {
+ var result:* = value;
+
+ if (!(value is Array))
+ {
+ try
+ {
+ var classInfo:Object = ObjectUtil.getClassInfo(value as Object);
+ var properties:Array = classInfo["properties"];
+ if (properties.length == 1)
+ {
+ var property:String = properties[0];
+ if (property != null && value.hasOwnProperty(property))
+ {
+ var childValue:* = value[property];
+ if (childValue is Array)
+ {
+ result = childValue;
+ }
+ }
+ }
+ }
+ catch(e:Error)
+ {
+ }
+ }
+
+ return result;
+ }
+
+ private function get dimensions():Array
+ {
+ if (_dimensions == null)
+ _dimensions = [];
+
+ return _dimensions;
+ }
+
+ private var _dimensions:Array;
+ private var dimensionString:String;
+ private var itemName:QName;
+ private var processor:SchemaProcessor;
+ private var schemaConstants:SchemaConstants;
+ private var schemaManager:SchemaManager;
+ private var schemaTypeName:String;
+ private var schemaType:QName;
+ private var soapConstants:SOAPConstants;
+}
+
+}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/wsdl/WSDL.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/wsdl/WSDL.as
new file mode 100644
index 0000000..b83cd85
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/wsdl/WSDL.as
@@ -0,0 +1,1366 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.wsdl
+{
+
+import mx.logging.ILogger;
+import mx.logging.Log;
+import mx.resources.IResourceManager;
+import mx.resources.ResourceManager;
+import mx.rpc.Fault;
+import mx.rpc.soap.SOAPConstants;
+import mx.rpc.xml.QualifiedResourceManager;
+import mx.rpc.xml.Schema;
+import mx.rpc.xml.SchemaConstants;
+import mx.rpc.xml.SchemaManager;
+import mx.rpc.xml.SchemaTypeRegistry;
+
+[ResourceBundle("rpc")]
+
+[ExcludeClass]
+
+/**
+ * Manages a WSDL top-level <code>definitions</code> element. WSDL definitions
+ * may contain imports to other WSDL definitions. Only SOAP bindings are
+ * supported.
+ *
+ * @private
+ */
+public class WSDL
+{
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructs a WSDL from XML. Services and their operations are
+ * parsed into object representations on the first call to
+ * <code>getService()</code>, <code>getPort()</code> or
+ * <code>getOperation()</code>.
+ *
+ * @param xml An XML document starting from the top-level WSDL
+ * <code>defintions</code> element.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function WSDL(xml:XML, topLevelManager:SchemaManager=null)
+ {
+ super();
+
+ // Fix for SDK-18926
+ // If this wsdl was imported, the top-level wsdl should pass it's own schemaManager
+ // which we should reuse.
+ if (topLevelManager != null)
+ {
+ _schemaManager = topLevelManager;
+ }
+ _xml = xml;
+ _log = Log.getLogger("mx.rpc.wsdl.WSDL");
+ processNamespaces();
+ processSchemas();
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ private var resourceManager:IResourceManager =
+ ResourceManager.getInstance();
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ public function get schemaManager():SchemaManager
+ {
+ if (_schemaManager == null)
+ {
+ _schemaManager = new SchemaManager();
+ _schemaManager.schemaConstants = schemaConstants;
+ }
+
+ return _schemaManager;
+ }
+
+ public function get schemaConstants():SchemaConstants
+ {
+ if (_schemaConstants == null)
+ _schemaConstants = SchemaConstants.getConstants(xml);
+
+ return _schemaConstants;
+ }
+
+ public function get soapConstants():SOAPConstants
+ {
+ if (_soapConstants == null)
+ _soapConstants = SOAPConstants.getConstants(xml);
+
+ return _soapConstants;
+ }
+
+ public function get targetNamespace():Namespace
+ {
+ return _targetNamespace;
+ }
+
+ public function get wsdlConstants():WSDLConstants
+ {
+ if (_wsdlConstants == null)
+ _wsdlConstants = WSDLConstants.getConstants(xml);
+
+ return _wsdlConstants;
+ }
+
+ /**
+ * The raw XML representing the WSDL starting from the top-level
+ * definitions element.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get xml():XML
+ {
+ return _xml;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /*
+ FIXME:
+ 1. Validate that the targetNamespace matches the one defined on the
+ import XML
+ 2. Also, check that the import being added does not cause a cyclic
+ relationship.
+ */
+ public function addImport(targetNamespace:Namespace, wsdl:WSDL):void
+ {
+ if (importsManager == null)
+ importsManager = new QualifiedResourceManager();
+
+ importsManager.addResource(targetNamespace, wsdl);
+ }
+
+ public function addSchema(schema:Schema):void
+ {
+ schemaManager.addSchema(schema);
+ }
+
+ public function getOperation(operationName:String, serviceName:String = null, portName:String = null):WSDLOperation
+ {
+ var port:WSDLPort = getPort(serviceName, portName);
+ var binding:WSDLBinding = port.binding;
+ var portType:WSDLPortType = binding.portType;
+ var operation:WSDLOperation = portType.getOperation(operationName);
+ return operation;
+ }
+
+ /**
+ * Locate a port for a service by name. If a serviceName is provided, a
+ * service is first located, otherwise the first service is used by default.
+ * Once a service has been selected, the search then considers the port.
+ * If a portName is not provided, the first port is used by default.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function getPort(serviceName:String = null, portName:String = null):WSDLPort
+ {
+ var port:WSDLPort;
+
+ var service:WSDLService = getService(serviceName, portName);
+ if (service != null)
+ {
+ if (portName == null)
+ port = service.defaultPort;
+ else
+ port = service.getPort(portName);
+ }
+
+ if (port == null)
+ {
+ var message:String = resourceManager.getString(
+ "rpc", "noServiceAndPort", [ serviceName, portName ]);
+ throw new Fault("Client.NoSuchPort", message);
+ }
+
+ return port;
+ }
+
+ /**
+ * Search for WSDL service and port by name. If a serviceName is not
+ * provided the first service found will be selected by default.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function getService(serviceName:String = null, portName:String = null):WSDLService
+ {
+ var service:WSDLService;
+ var port:WSDLPort;
+
+ if (serviceMap != null && serviceName != null)
+ {
+ service = serviceMap[serviceName];
+ if (service != null)
+ {
+ if (portName != null)
+ port = service.getPort(portName);
+
+ if (port == null)
+ {
+ var tempService:WSDLService = parseService(serviceName, portName);
+ for each (var p:WSDLPort in tempService.ports)
+ {
+ service.addPort(p);
+ }
+ }
+ }
+ }
+
+ // We didn't find a service, so we parse to find one...
+ if (service == null)
+ {
+ service = parseService(serviceName, portName);
+
+ var message:String;
+ var detail:String;
+
+ if (service != null)
+ {
+ if (serviceMap == null)
+ serviceMap = {};
+
+ serviceMap[service.name] = service;
+ }
+ else if (serviceName != null)
+ {
+ message = resourceManager.getString(
+ "rpc", "noSuchServiceInWSDL", [ serviceName ]);
+ throw new Fault("Client.NoSuchService", message);
+ }
+ else
+ {
+ message = resourceManager.getString(
+ "rpc", "noServiceElement");
+ detail = resourceManager.getString(
+ "rpc", "noServiceElement.details", [ "" ]);
+ throw new Fault("Server.NoServicesInWSDL", message, detail);
+ }
+ }
+
+ return service;
+ }
+
+ public function getTypes(targetNamespace:Namespace):XML
+ {
+ var types:XML;
+
+ // First, check current WSDL for types element
+ var typesXMLList:XMLList = xml.elements(wsdlConstants.typesQName);
+ if (typesXMLList.length() > 0)
+ {
+ // There should only be one types element.
+ types = typesXMLList[0];
+ }
+ else if (importsManager != null)
+ {
+ // Check WSDL imports for types element
+ var imports:Array = importsManager.getResourcesForNamespace(targetNamespace);
+ for each (var childWSDL:WSDL in imports)
+ {
+ types = childWSDL.getTypes(targetNamespace);
+ if (types != null)
+ break;
+ }
+ }
+
+ return types;
+ }
+
+ /**
+ * Search for a requested service in the definitions XML, including all
+ * WSDL imports. This is the usual entry point to start parsing the WSDL as
+ * only one service and one of its port will be used at any time.
+ * <p>
+ * If the service name is not specified, the first service is used by
+ * default. If a service is located it is parsed and then the search
+ * continues for the requested port, which is in turn parsed, and so forth.
+ * </p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private function parseService(serviceName:String = null, portName:String = null):WSDLService
+ {
+ var service:WSDLService;
+ var serviceXML:XML;
+
+ // First, look for the service in this WSDL
+ var serviceXMLList:XMLList = xml.elements(wsdlConstants.serviceQName);
+ for each (var x:XML in serviceXMLList)
+ {
+ if (serviceName == null)
+ {
+ // Select the first service if a service name wasn't specified
+ serviceXML = x;
+ serviceName = x.@name.toString();
+ break;
+ }
+ else if (x.@name == serviceName)
+ {
+ serviceXML = x;
+ break;
+ }
+ }
+
+ if (serviceXML != null)
+ {
+ // We have the service, now look for the port
+ service = new WSDLService(serviceName);
+
+ var port:WSDLPort = parsePort(service, serviceXML, portName);
+
+ if (port != null)
+ {
+ service.addPort(port);
+ }
+ }
+ else if (importsManager != null)
+ {
+ // Otherwise, look for the service in our WSDL imports (assuming
+ // the port must be in the same import as the service).
+ var imports:Array = importsManager.getResources();
+ for each (var childWSDL:WSDL in imports)
+ {
+ service = childWSDL.parseService(serviceName, portName);
+ if (service != null)
+ break;
+ }
+ }
+
+ return service;
+ }
+
+ /**
+ * Search for a requested port in the given service XML. If a port
+ * name was not specified, the first port is used by default.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private function parsePort(service:WSDLService, serviceXML:XML, portName:String = null):WSDLPort
+ {
+ var port:WSDLPort;
+ var portXML:XML;
+
+ var portXMLList:XMLList = serviceXML.elements(wsdlConstants.portQName);
+ for each (var x:XML in portXMLList)
+ {
+ if (portName == null)
+ {
+ portXML = x;
+ portName = x.@name.toString();
+ break;
+ }
+ else if (x.@name == portName)
+ {
+ portXML = x;
+ break;
+ }
+ }
+
+ if (portXML != null)
+ {
+ // We have the port, now look for the location and binding
+ port = new WSDLPort(portName, service);
+
+ var soapAddressXMLList:XMLList;
+ soapAddressXMLList = portXML.elements(wsdlConstants.soapAddressQName);
+ if (soapAddressXMLList.length() > 0)
+ {
+ port.endpointURI = soapAddressXMLList[0].@location.toString();
+ }
+
+ var prefixedBindingName:String = portXML.@binding.toString();
+ var bindingQName:QName = schemaManager.getQNameForPrefixedName(prefixedBindingName, portXML);
+
+ var binding:WSDLBinding = parseBinding(bindingQName);
+
+ if (binding != null)
+ {
+ port.binding = binding;
+ }
+ else
+ {
+ var message:String = resourceManager.getString(
+ "rpc", "unrecognizedBindingName",
+ [ bindingQName.localName, bindingQName.uri ]);
+ throw new Fault("WSDL.UnrecognizedBindingName", message);
+ }
+ }
+
+ return port;
+ }
+
+ /**
+ * Search for a binding by QName. If a URI is not specified, the
+ * targetNamespace is assumed. FIXME: We may need to consider whether
+ * formElementDefault is set to qualified or not.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private function parseBinding(bindingQName:QName):WSDLBinding
+ {
+ var binding:WSDLBinding;
+ var bindingXML:XML;
+
+ // First, look for the binding in this WSDL
+ var bindingXMLList:XMLList = xml.elements(wsdlConstants.bindingQName);
+ for each (var x:XML in bindingXMLList)
+ {
+ if (x.@name == bindingQName.localName)
+ {
+ bindingXML = x;
+ break;
+ }
+ }
+
+ if (bindingXML != null)
+ {
+ // We have the binding, now look for the style, transport,
+ // operation and portType information
+ binding = new WSDLBinding(bindingQName.localName);
+
+ // Look for the SOAP specific binding that controls the basic
+ // structure of requests made to and from a WSDL operation, and
+ // specifies the default style for operations. It does not make any
+ // claims as to the encoding or format of the message.
+ //
+ // <soap:binding transport="uri"? style="rpc|document"?>
+ //
+ var soapBindingXMLList:XMLList;
+ soapBindingXMLList = bindingXML.elements(wsdlConstants.soapBindingQName);
+ if (soapBindingXMLList.length() > 0)
+ {
+ var style:String = soapBindingXMLList[0].@style.toString();
+ binding.style = style;
+
+ var transport:String = soapBindingXMLList[0].@transport.toString();
+ binding.transport = transport;
+ }
+
+ // The port type name must match the type specified on the binding.
+ //
+ // <wsdl:binding name="nmtoken" type="qname">*
+ //
+ var prefixedTypeName:String = bindingXML.@type.toString();
+ var portTypeQName:QName = schemaManager.getQNameForPrefixedName(prefixedTypeName, bindingXML);
+ var portType:WSDLPortType = new WSDLPortType(portTypeQName.localName);
+ binding.portType = portType;
+
+ // We parse binding information for each operation and its
+ // input, output and fault messages before processing the port type
+ // so that we can establish encoding rules and whether subsets of
+ // the parts have been declared for the Body.
+ //
+ // <wsdl:operation name="nmtoken">*
+ //
+ var operationXMLList:XMLList = bindingXML.elements(wsdlConstants.operationQName);
+ for each (var operationXML:XML in operationXMLList)
+ {
+ var operationName:String = operationXML.@name.toString();
+ var operation:WSDLOperation = new WSDLOperation(operationName);
+ operation.schemaManager = schemaManager;
+ operation.namespaces = namespaces;
+ operation.wsdlConstants = wsdlConstants;
+
+ // Look for soapAction as we expect HTTP based SOAP binding
+ // and any operation-specific style information.
+ //
+ // <soap:operation soapAction="uri"? style="rpc|document"?>?
+ //
+ var soapOperationXMLList:XMLList = operationXML.elements(wsdlConstants.soapOperationQName);
+ if (soapOperationXMLList.length() > 0)
+ {
+ var soapAction:String = soapOperationXMLList[0].@soapAction.toString();
+ operation.soapAction = soapAction;
+ var opStyle:String = soapOperationXMLList[0].@style.toString();
+ if (opStyle == "")
+ operation.style = binding.style;
+ else
+ operation.style = opStyle;
+ }
+
+ // Record the encoding format each of the messages of this
+ // operation. The SOAP Body, Fault and Header sections are
+ // described.
+ //
+ // <soap:body parts="nmtokens"? use="literal|encoded"?
+ // encodingStyle="uri-list"? namespace="uri"?>
+ //
+ // <soap:header message="qname" part="nmtoken" use="literal|encoded"
+ // encodingStyle="uri-list"? namespace="uri"?>*
+ //
+
+ var operationExtensionXMLList:XMLList;
+ var operationExtensionXML:XML;
+ var encoding:WSDLEncoding;
+ var extensionXMLList:XMLList;
+ var extensionXML:XML;
+ var extensionName:String;
+ var extensionMessage:WSDLMessage;
+
+ // WSDL Input Message
+ operationExtensionXMLList = operationXML.elements(wsdlConstants.inputQName);
+ if (operationExtensionXMLList.length() > 0)
+ {
+ operationExtensionXML = operationExtensionXMLList[0];
+ operation.inputMessage = new WSDLMessage();
+
+ // SOAP Body
+ extensionXMLList = operationExtensionXML.elements(wsdlConstants.soapBodyQName);
+ if (extensionXMLList.length() > 0)
+ {
+ extensionXML = extensionXMLList[0];
+ encoding = parseEncodingExtension(extensionXML);
+ operation.inputMessage.encoding = encoding;
+ }
+
+ // SOAP Header
+ extensionXMLList = operationExtensionXML.elements(wsdlConstants.soapHeaderQName);
+ for each (extensionXML in extensionXMLList)
+ {
+ extensionMessage = parseHeader(operationName, extensionXML);
+ operation.inputMessage.addHeader(extensionMessage);
+ }
+
+ // SOAP Header Fault
+ extensionXMLList = operationExtensionXML.elements(wsdlConstants.soapHeaderFaultQName);
+ for each (extensionXML in extensionXMLList)
+ {
+ extensionMessage = parseHeader(operationName, extensionXML);
+ operation.inputMessage.addHeaderFault(extensionMessage);
+ }
+ }
+
+ // WSDL Output Message
+ operationExtensionXMLList = operationXML.elements(wsdlConstants.outputQName);
+ if (operationExtensionXMLList.length() > 0)
+ {
+ operationExtensionXML = operationExtensionXMLList[0];
+ operation.outputMessage = new WSDLMessage();
+
+ // SOAP Body
+ extensionXMLList = operationExtensionXML.elements(wsdlConstants.soapBodyQName);
+ if (extensionXMLList.length() > 0)
+ {
+ extensionXML = extensionXMLList[0];
+ encoding = parseEncodingExtension(extensionXML);
+ operation.outputMessage.encoding = encoding;
+ }
+
+ // SOAP Header
+ extensionXMLList = operationExtensionXML.elements(wsdlConstants.soapHeaderQName);
+ for each (extensionXML in extensionXMLList)
+ {
+ extensionMessage = parseHeader(operationName, extensionXML);
+ operation.outputMessage.addHeader(extensionMessage);
+ }
+
+ // SOAP Header Fault
+ extensionXMLList = operationExtensionXML.elements(wsdlConstants.soapHeaderFaultQName);
+ for each (extensionXML in extensionXMLList)
+ {
+ extensionMessage = parseHeader(operationName, extensionXML);
+ operation.outputMessage.addHeaderFault(extensionMessage);
+ }
+ }
+
+ // WSDL Fault Message
+ //
+ // <soap:fault name="nmtoken" use="literal|encoded"
+ // encodingStyle="uri-list"? namespace="uri"?>
+ //
+ operationExtensionXMLList = operationXML.elements(wsdlConstants.faultQName);
+ for each (operationExtensionXML in operationExtensionXMLList)
+ {
+ // SOAP Fault
+ extensionXMLList = operationExtensionXML.elements(wsdlConstants.soapFaultQName);
+ if (extensionXMLList.length() > 0)
+ {
+ extensionXML = extensionXMLList[0];
+ var faultName:String = extensionXML.@["name"].toString();
+ extensionMessage = new WSDLMessage(faultName);
+ encoding = parseEncodingExtension(extensionXML, false, true);
+ extensionMessage.encoding = encoding;
+ operation.addFault(extensionMessage);
+ }
+ }
+
+ portType.addOperation(operation);
+ }
+
+ // Now that we've read the SOAP binding information for each
+ // operation, we can find and parse the port type which is a
+ // named set of abstract operations and the abstract messages
+ // involved.
+ parsePortType(portTypeQName, portType);
+ }
+ else if (importsManager != null)
+ {
+ // FIXME: USE QNAME URI TO LOOK UP IMPORT BY NAMESPACE!
+
+ // Otherwise, look for the binding in our WSDL imports.
+ var imports:Array = importsManager.getResources();
+ for each (var childWSDL:WSDL in imports)
+ {
+ binding = childWSDL.parseBinding(bindingQName);
+ if (binding != null)
+ break;
+ }
+ }
+
+ return binding;
+ }
+
+ /**
+ * Search for a portType by QName. If a URI is not specified, the
+ * targetNamespace is assumed.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private function parsePortType(portTypeQName:QName, portType:WSDLPortType):Boolean
+ {
+ var portTypeXML:XML;
+ var foundMatchingPortType:Boolean;
+
+ // First, look for the portType in this WSDL
+ var portTypeXMLList:XMLList = xml.elements(wsdlConstants.portTypeQName);
+ for each (var x:XML in portTypeXMLList)
+ {
+ if (x.@name == portTypeQName.localName)
+ {
+ portTypeXML = x;
+ break;
+ }
+ }
+
+ if (portTypeXML != null)
+ {
+ foundMatchingPortType = true;
+
+ var operationsXMLList:XMLList = portTypeXML.elements(wsdlConstants.operationQName);
+ for each(var operationXML:XML in operationsXMLList)
+ {
+ // TODO: We may need to consider operation overloading!
+
+ // The binding operation nmtoken is unique and must match an
+ // operation defined in the associated portType. We've
+ // previously parsed the binding, so this operation must be
+ // located by name.
+ var operationName:String = operationXML.@name.toString();
+ var operation:WSDLOperation = portType.getOperation(operationName);
+
+ // If we don't have the binding information for this operation,
+ // skip it.
+ if (operation == null)
+ {
+ _log.warn("An operation '{0}' was found in the port type but is missing binding information.", operationName);
+ continue;
+ }
+
+ var messageName:String;
+ var messageQName:QName;
+ var message:WSDLMessage;
+
+ // Input Message
+ //
+ // <wsdl:input name="nmtoken"? message="qname"/>
+ //
+ var inputXMLList:XMLList = operationXML.elements(wsdlConstants.inputQName);
+ if (inputXMLList.length() > 0)
+ {
+ // Reset the schema scope for each message
+ schemaManager.reset();
+
+ messageName = inputXMLList[0].@message.toString();
+ messageQName = schemaManager.getQNameForPrefixedName(messageName, inputXMLList[0]);
+ message = operation.inputMessage;
+ message.name = messageQName.localName;
+ parseMessage(message, messageQName, operationName, WSDLConstants.MODE_IN);
+ }
+
+ // Output Message
+ //
+ // <wsdl:output name="nmtoken"? message="qname"/>
+ //
+ var outputXMLList:XMLList = operationXML.elements(wsdlConstants.outputQName);
+ if (outputXMLList.length() > 0)
+ {
+ // Reset the schema scope for each message
+ schemaManager.reset();
+
+ messageName = outputXMLList[0].@message.toString();
+ messageQName = schemaManager.getQNameForPrefixedName(messageName, outputXMLList[0]);
+ message = operation.outputMessage;
+ message.name = messageQName.localName;
+ parseMessage(message, messageQName, operationName, WSDLConstants.MODE_OUT);
+ }
+
+ // Fault Messages
+ //
+ // <wsdl:fault name="nmtoken" message="qname"/>*
+ //
+ var faultsXMLList:XMLList = operationXML.elements(wsdlConstants.faultQName);
+ for each (var faultXML:XML in faultsXMLList)
+ {
+ // Reset the schema scope for each message
+ schemaManager.reset();
+
+ var faultName:String = faultXML.@name.toString();
+ message = operation.getFault(faultName);
+ if (message != null)
+ {
+ messageName = faultXML.@message.toString();
+ messageQName = schemaManager.getQNameForPrefixedName(messageName, faultXML);
+ parseMessage(message, messageQName, operationName, WSDLConstants.MODE_FAULT);
+ }
+ }
+
+ if (operation.style == SOAPConstants.DOC_STYLE)
+ {
+ parseDocumentOperation(operation);
+ }
+ }
+ }
+ else if (importsManager != null)
+ {
+ // Then look for the portType in the imports...
+ var imports:Array = importsManager.getResources();
+ for each (var childWSDL:WSDL in imports)
+ {
+ foundMatchingPortType = childWSDL.parsePortType(portTypeQName, portType);
+ if (foundMatchingPortType)
+ break;
+ }
+ }
+
+ return foundMatchingPortType;
+ }
+
+ /**
+ * Search for a message by QName. If a URI is not specified, the
+ * targetNamespace is assumed.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private function parseMessage(message:WSDLMessage, messageQName:QName, operationName:String, mode:int):Boolean
+ {
+ var messageXML:XML;
+ var foundMatchingMessage:Boolean;
+ var encoding:WSDLEncoding = message.encoding;
+
+ // First, look for the message in this WSDL
+ var messageXMLList:XMLList = xml.elements(wsdlConstants.messageQName);
+ for each (var x:XML in messageXMLList)
+ {
+ if (x.@name == messageQName.localName)
+ {
+ messageXML = x;
+ break;
+ }
+ }
+
+ if (messageXML != null)
+ {
+ foundMatchingMessage = true;
+
+ // If the message is not named we default to the operation name
+ // plus a standard suffix for input or output mode:
+ if (message.name == null || message.name == "")
+ {
+ if (mode == WSDLConstants.MODE_IN)
+ {
+ message.name = operationName + "Request";
+ }
+ else if (mode == WSDLConstants.MODE_OUT)
+ {
+ message.name = operationName + "Response";
+ }
+
+ // FIXME: Handle soap fault message name if one wasn't provided
+ }
+
+ // Parse the message types
+ var partXMLList:XMLList = messageXML.elements(wsdlConstants.partQName);
+ for each (var partXML:XML in partXMLList)
+ {
+ var partName:String = partXML.@name;
+
+ // We skip a part if the SOAP encoding extension defines a
+ // subset of parts and this part nmtoken isn't in the list...
+ if (encoding != null && !encoding.hasPart(partName))
+ {
+ continue;
+ }
+
+ var part:WSDLMessagePart = parseMessagePart(partXML);
+ message.addPart(part);
+ }
+ }
+ else if (importsManager != null)
+ {
+ // Then look for the message in the imports...
+ var imports:Array = importsManager.getResources();
+ for each (var childWSDL:WSDL in imports)
+ {
+ foundMatchingMessage = childWSDL.parseMessage(message, messageQName, operationName, mode);
+ if (foundMatchingMessage)
+ break;
+ }
+ }
+
+ return foundMatchingMessage;
+ }
+
+ /**
+ * Returns a WSDL message part based on the name and looks for either an
+ * element QName or type QName to determine which definition describes
+ * this message part.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private function parseMessagePart(partXML:XML):WSDLMessagePart
+ {
+ var partName:String = partXML.@name;
+ var partQName:QName = new QName("", partName);
+ var part:WSDLMessagePart = new WSDLMessagePart(partQName);
+ var partXMLElement:String = partXML.@element;
+ var partXMLType:String = partXML.@type;
+
+ // Consider type or element
+ if (partXMLElement != "")
+ {
+ var elementName:String = partXML.@element;
+ var elementQName:QName = schemaManager.getQNameForPrefixedName(elementName, partXML);
+ part.element = elementQName;
+ }
+ else if (partXMLType != "")
+ {
+ var typeName:String = partXML.@type;
+ var typeQName:QName = schemaManager.getQNameForPrefixedName(typeName, partXML);
+ part.type = typeQName;
+ }
+
+ return part;
+ }
+
+ /**
+ * Looks for the SOAP encoding extensions based on the type of WSDL
+ * operation message. SOAP encoding is required for SOAP Body, Header
+ * (header and headerfault) and Fault extensions.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private function parseHeader(operationName:String, headerXML:XML):WSDLMessage
+ {
+ var headerName:String = headerXML.@["part"].toString();
+ var headerMessage:WSDLMessage = new WSDLMessage(headerName);
+ var encoding:WSDLEncoding = parseEncodingExtension(headerXML, true);
+ headerMessage.encoding = encoding;
+ parseMessage(headerMessage, encoding.message, operationName, WSDLConstants.MODE_HEADER);
+ return headerMessage;
+ }
+
+ /**
+ * Looks for the SOAP encoding extensions based on the type of WSDL
+ * operation message. SOAP encoding is required for SOAP Body, Header
+ * (header and headerfault) and Fault extensions.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private function parseEncodingExtension(extensionXML:XML, isHeader:Boolean = false, isFault:Boolean = false):WSDLEncoding
+ {
+ var encoding:WSDLEncoding = new WSDLEncoding();
+ encoding.useStyle = extensionXML.@["use"].toString();
+ encoding.namespaceURI = extensionXML.@["namespace"].toString();
+ encoding.encodingStyle = extensionXML.@["encodingStyle"].toString();
+
+ if (isHeader)
+ {
+ var messageName:String = extensionXML.@["message"].toString();
+ encoding.message = schemaManager.getQNameForPrefixedName(messageName, extensionXML);
+ encoding.setParts(extensionXML.@["part"].toString());
+ }
+ else if (!isFault)
+ {
+ encoding.setParts(extensionXML.@["parts"].toString());
+ }
+
+ return encoding;
+ }
+
+ /**
+ * A Document-Literal operation may make use of "wrapped" style. If so,
+ * then the message parts should be replaced by the the individual wrapped
+ * parts so that the SOAP encoders correctly bind ActionScript input params
+ * to message params, and SOAP decoders correctly bind output params
+ * to predictable ActionScript constructs. Essentially the wrappers should
+ * be an encoding detail that is invisible to the Flex developer.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private function parseDocumentOperation(operation:WSDLOperation):void
+ {
+ var part:WSDLMessagePart;
+ var element:XML;
+ var elementTypeString:String;
+ var elementType:QName;
+ var complexTypes:XMLList;
+ var complexType:XML;
+ var attributes:XMLList;
+ var sequences:XMLList;
+ var sequence:XML;
+
+ // Check whether this operation's input is literal and "wrapped".
+ if (operation.inputMessage != null
+ && operation.inputMessage.encoding != null
+ && operation.inputMessage.encoding.useStyle == SOAPConstants.USE_LITERAL)
+ {
+ // A "wrapped" input message must:
+ // 1. Have a single part.
+ // 2. The part is an element.
+ // 3. The element's name MUST be the same as the name of the operation.
+ // 4. The element's complex type must have no attributes and define
+ // a sequence of zero or more elements (which serve as the input
+ // params).
+ var input:WSDLMessage = operation.inputMessage;
+ if (input.parts != null && input.parts.length == 1)
+ {
+ // Reset the schema scope for each wrapped part
+ schemaManager.reset();
+
+ part = input.parts[0];
+ if (part.element != null)
+ {
+ element = schemaManager.getNamedDefinition(part.element, schemaConstants.elementTypeQName);
+ if (element != null && element.@["name"] == operation.name)
+ {
+ elementTypeString = element.@["type"];
+ if (elementTypeString != null && elementTypeString != "")
+ {
+ elementType = schemaManager.getQNameForPrefixedName(elementTypeString, element);
+ complexType = schemaManager.getNamedDefinition(elementType, schemaConstants.complexTypeQName);
+ }
+ else
+ {
+ complexTypes = element.elements(schemaConstants.complexTypeQName);
+ if (complexTypes.length() == 1)
+ {
+ complexType = complexTypes[0];
+ }
+ }
+
+ if (complexType != null)
+ {
+ attributes = complexType.elements(schemaConstants.attributeQName);
+ if (attributes.length() == 0)
+ {
+ sequences = complexType.elements(schemaConstants.sequenceQName);
+
+ // The sequence may be omitted entirely for
+ // zero-param operation signatures
+ if (complexType.elements().length() == 0 || sequences.length() == 1)
+ {
+ input.isWrapped = true;
+ input.wrappedQName = part.element;
+ input.parts = [];
+
+ if (sequences.length() == 1)
+ {
+ // Use the wrapped parts to redefine the
+ // signature of the input message.
+ sequence = sequences[0];
+ var requestElements:XMLList = sequence.elements(schemaConstants.elementTypeQName);
+ for each (var requestElement:XML in requestElements)
+ {
+ // FIXME: Should we skip wrapped parts
+ // if the SOAP encoding extension defines
+ // a subset?
+ part = parseWrappedMessagePart(requestElement);
+ input.addPart(part);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Reset wrapped element's type variables
+ complexType = null;
+ elementTypeString = null;
+
+ // Check whether this operation's output is literal and "wrapped".
+ if (operation.outputMessage != null
+ && operation.outputMessage.encoding != null
+ && operation.outputMessage.encoding.useStyle == SOAPConstants.USE_LITERAL)
+ {
+ // A "wrapped" output message must:
+ // 1. Have a single part.
+ // 2. The part is an element.
+ // 3. This element's complexType must have no attributes and define
+ // a sequence of zero or more elements (which serve as the output
+ // params).
+ var output:WSDLMessage = operation.outputMessage;
+ if (output.parts != null && output.parts.length == 1)
+ {
+ part = output.parts[0];
+ if (part.element != null)
+ {
+ // Reset the schema scope for each wrapped part
+ schemaManager.reset();
+
+ element = schemaManager.getNamedDefinition(part.element, schemaConstants.elementTypeQName);
+ if (element != null)
+ {
+ elementTypeString = element.@["type"];
+ if (elementTypeString != null && elementTypeString != "")
+ {
+ elementType = schemaManager.getQNameForPrefixedName(elementTypeString, element);
+ complexType = schemaManager.getNamedDefinition(elementType, schemaConstants.complexTypeQName);
+ }
+ else
+ {
+ complexTypes = element.elements(schemaConstants.complexTypeQName);
+ if (complexTypes.length() == 1)
+ {
+ complexType = complexTypes[0];
+ }
+ }
+
+ if (complexType != null)
+ {
+ attributes = complexType.elements(schemaConstants.attributeQName);
+ if (attributes.length() == 0)
+ {
+ sequences = complexType.elements(schemaConstants.sequenceQName);
+
+ // The sequence may be omitted entirely for
+ // zero-param operation signatures
+ if (complexType.elements().length() == 0 || sequences.length() == 1)
+ {
+ output.isWrapped = true;
+ output.wrappedQName = part.element;
+ output.parts = [];
+
+ if (sequences.length() == 1)
+ {
+ // Use the wrapped parts to redefine the
+ // return type signature of the output
+ // message (multiple output parts will
+ // be returned as a map)
+ sequence = sequences[0];
+ var resultElements:XMLList = sequence.elements(schemaConstants.elementTypeQName);
+ for each (var resultElement:XML in resultElements)
+ {
+ // FIXME: Should we skip wrapped parts
+ // if the SOAP encoding extension defines
+ // a subset?
+ part = parseWrappedMessagePart(resultElement);
+ output.addPart(part);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns a WSDL message part based on the name and looks for either an
+ * element QName or type QName to determine which definition describes
+ * this message part.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private function parseWrappedMessagePart(elementXML:XML):WSDLMessagePart
+ {
+ // <element ref="..."> may be used to point to a top-level element definition
+ var ref:QName;
+ if (elementXML.attribute("ref").length() == 1)
+ {
+ ref = schemaManager.getQNameForPrefixedName(elementXML.@ref, elementXML, true);
+ elementXML = schemaManager.getNamedDefinition(ref, schemaConstants.elementTypeQName);
+ if (elementXML == null)
+ throw new Error("Cannot resolve element definition for ref '" + ref + "'");
+ }
+
+ var partName:String = elementXML.@name;
+ var partQName:QName = schemaManager.getQNameForElement(partName, elementXML.@form);
+ var part:WSDLMessagePart = new WSDLMessagePart(partQName);
+
+ // However, since this is a local element that acts like a
+ // top-level element, we first check whether we need to
+ // special case the element definition.
+ var minOccurs:String = elementXML.@minOccurs;
+ var maxOccurs:String = elementXML.@maxOccurs;
+
+ // Furthermore, if minOccurs is set to 0, this part is optional
+ if (minOccurs != "" && parseInt(minOccurs) == 0)
+ part.optional = true;
+
+ if (ref != null)
+ {
+ // We have a reference to a top level element definition
+ part.element = ref;
+ }
+ else
+ {
+ var partType:String = elementXML.@type;
+ if (partType != "" || !elementXML.hasComplexContent())
+ {
+ // We have a reference to a type definition
+ if (partType == null || partType == "")
+ part.type = schemaConstants.anyTypeQName;
+ else
+ part.type = schemaManager.getQNameForPrefixedName(partType, elementXML);
+
+ if (minOccurs != "" || maxOccurs != "")
+ {
+ part.definition = elementXML;
+ }
+ }
+ else if (elementXML.hasComplexContent())
+ {
+ // We have an inline type definition
+ part.definition = elementXML;
+ }
+ }
+
+ // If we found our element by reference, we now release the schema scope
+ if (ref != null)
+ schemaManager.releaseScope();
+
+ return part;
+ }
+
+ /**
+ * Determines the WSDL and SOAP versions from the definitions and creates
+ * a map of top level prefixes to namespaces.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private function processNamespaces():void
+ {
+ if (_xml != null)
+ {
+ // Record the targetNamespace
+ var tns:String = _xml.@targetNamespace.toString();
+ _targetNamespace = new Namespace(tns);
+
+ // Initialize Namespaces
+ namespaces = {};
+
+ // Determine WSDL and SOAP Version
+ var nsArray:Array = _xml.namespaceDeclarations();
+ for each (var ns:Namespace in nsArray)
+ {
+ namespaces[ns.prefix] = ns;
+ }
+
+ // Initialize WSDL Constants
+ _wsdlConstants = WSDLConstants.getConstants(_xml);
+ _schemaConstants = SchemaConstants.getConstants(_xml);
+
+ // Also record these top level namespaces with our SchemaManager
+ schemaManager.addNamespaces(namespaces);
+ }
+ }
+
+ private function processSchemas():void
+ {
+ var types:XML = getTypes(targetNamespace);
+ if (types != null)
+ {
+ var schemas:XMLList = types.elements(schemaConstants.schemaQName);
+ for each (var schemaXML:XML in schemas)
+ {
+ var schema:Schema = new Schema(schemaXML);
+ addSchema(schema);
+ }
+ }
+ }
+
+ /**
+ * Manages WSDL imports.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private var importsManager:QualifiedResourceManager;
+
+ /**
+ * Logs warnings encountered while parsing WSDL.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private var _log:ILogger;
+
+ /**
+ * Maps a namespace prefix (as a <code>String</code>) to a
+ * <code>Namespace</code> (i.e. this helps to resolve a prefix to a URI).
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private var namespaces:Object;
+
+ /**
+ * Provides a static cache of the constants for various versions of XSD.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private var _schemaConstants:SchemaConstants;
+
+ /**
+ * A map of target namespaces to XSD Schemas that describe the types
+ * used in this WSDL.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private var _schemaManager:SchemaManager;
+
+ /**
+ * Map to cache a WSDLService by service name. The cache is cleared
+ * when a new definitions element is set for the WSDL.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private var serviceMap:Object;
+
+ private var _soapConstants:SOAPConstants;
+
+ /**
+ * WSDL target namespace.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private var _targetNamespace:Namespace;
+
+ /**
+ * Provides a static cache of the constants for various versions of WSDL.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private var _wsdlConstants:WSDLConstants;
+
+ /**
+ * The raw XML representing the WSDL definitions top level element.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private var _xml:XML;
+}
+
+}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/wsdl/WSDLBinding.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/wsdl/WSDLBinding.as
new file mode 100644
index 0000000..8497d46
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/wsdl/WSDLBinding.as
@@ -0,0 +1,171 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.wsdl
+{
+
+import mx.rpc.soap.SOAPConstants;
+
+/**
+ * A binding defines the message format and protocol for messages sent
+ * to and from operations as defined by a particular portType.
+ * <p>
+ * Currently only SOAP binding is supported for WSDL.
+ * </p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class WSDLBinding
+{
+ /**
+ * Creates a new WSDLBinding. Currently, only SOAP binding is
+ * supported for WSDL.
+ *
+ * @param name The unique name of this binding.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function WSDLBinding(name:String)
+ {
+ super();
+ _name = name;
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * The unique name of this binding.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get name():String
+ {
+ return _name;
+ }
+
+ /**
+ * The portType for this binding which provides the interface definitions
+ * for the operations of this binding.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get portType():WSDLPortType
+ {
+ return _portType;
+ }
+
+ public function set portType(value:WSDLPortType):void
+ {
+ _portType = value;
+ }
+
+ [Inspectable(enumeration="document,rpc", defaultValue="document", category="General")]
+ /**
+ * Represents a SOAP binding style attribute which is the default for any
+ * operation defined under this binding. The style indicates whether an
+ * operation is RPC-oriented (messages containing parameters and return
+ * values) or document-oriented (message containing document(s)).
+ * <p>
+ * The default is <code>document</code>.
+ * </p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get style():String
+ {
+ if (_style == null)
+ _style = SOAPConstants.DEFAULT_OPERATION_STYLE;
+
+ return _style;
+ }
+
+ public function set style(value:String):void
+ {
+ _style = value;
+ }
+
+ [Inspectable(defaultValue="http://schemas.xmlsoap.org/soap/http/", category="General")]
+ /**
+ * Represents a SOAP binding transport attribute which indicates the
+ * URI of the transport used to send SOAP encoded messages.
+ * The default URI is http://schemas.xmlsoap.org/soap/http/ which signifies
+ * SOAP over HTTP (and is currently the only transport supported).
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get transport():String
+ {
+ if (_transport == null)
+ _transport = WSDLConstants.SOAP_HTTP_URI;
+
+ return _transport;
+ }
+
+ public function set transport(value:String):void
+ {
+ _transport = value;
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ public function toString():String
+ {
+ return "WSDLBinding name=" + _name
+ + ", style=" + _style
+ + ", transport=" + _transport;
+ }
+
+ private var _name:String;
+ private var _portType:WSDLPortType;
+ private var _style:String;
+ private var _transport:String;
+}
+
+}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/wsdl/WSDLConstants.as b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/wsdl/WSDLConstants.as
new file mode 100644
index 0000000..7f2da3c
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/rpc/wsdl/WSDLConstants.as
@@ -0,0 +1,257 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.wsdl
+{
+
+import mx.utils.StringUtil;
+import mx.utils.URLUtil;
+
+[ExcludeClass]
+
+/**
+ * Manages the constants for a particular version of WSDL (and its
+ * accompanying version of SOAP).
+ *
+ * The default version is WSDL 1.1.
+ *
+ * @private
+ */
+public class WSDLConstants
+{
+ public function WSDLConstants(wsdlNS:Namespace = null, soapNS:Namespace = null)
+ {
+ super();
+
+ // Default to WSDl 1.1 and SOAP 1.1
+ if (wsdlNS == null)
+ wsdlNS = new Namespace(WSDL_PREFIX, WSDL_URI);
+ if (soapNS == null)
+ soapNS = new Namespace(WSDL_SOAP_PREFIX, WSDL_SOAP_URI);
+
+ _wsdlNS = wsdlNS;
+ _soapNS = soapNS;
+
+ definitionsQName = new QName(wsdlURI, "definitions");
+ importQName = new QName(wsdlURI, "import");
+ typesQName = new QName(wsdlURI, "types");
+ messageQName = new QName(wsdlURI, "message");
+ portTypeQName = new QName(wsdlURI, "portType");
+ bindingQName = new QName(wsdlURI, "binding");
+ serviceQName = new QName(wsdlURI, "service");
+ documentationQName = new QName(wsdlURI, "documentation");
+ portQName = new QName(wsdlURI, "port");
+ operationQName = new QName(wsdlURI, "operation");
+ inputQName = new QName(wsdlURI, "input");
+ outputQName = new QName(wsdlURI, "output");
+ partQName = new QName(wsdlURI, "part");
+ faultQName = new QName(wsdlURI, "fault");
+ wsdlArrayTypeQName = new QName(wsdlURI, "arrayType");
+
+ soapAddressQName = new QName(soapURI, "address");
+ soapBindingQName = new QName(soapURI, "binding");
+ soapOperationQName = new QName(soapURI, "operation");
+ soapBodyQName = new QName(soapURI, "body");
+ soapFaultQName = new QName(soapURI, "fault");
+ soapHeaderQName = new QName(soapURI, "header");
+ soapHeaderFaultQName = new QName(soapURI, "headerfault");
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ public function get soapURI():String
+ {
+ return soapNamespace.uri;
+ }
+
+ public function get wsdlURI():String
+ {
+ return wsdlNamespace.uri;
+ }
+
+ public function get soapNamespace():Namespace
+ {
+ return _soapNS;
+ }
+
+ public function get wsdlNamespace():Namespace
+ {
+ return _wsdlNS;
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ public static function getConstants(xml:XML):WSDLConstants
+ {
+ var wsdlNS:Namespace;
+ var soapNS:Namespace;
+
+ if (xml != null)
+ {
+ var nsArray:Array = xml.inScopeNamespaces();
+ for each (var ns:Namespace in nsArray)
+ {
+ if (URLUtil.urisEqual(ns.uri, WSDL_URI))
+ {
+ wsdlNS = ns;
+ }
+ else if (URLUtil.urisEqual(ns.uri, WSDL20_URI))
+ {
+ wsdlNS = ns;
+ }
+ if (URLUtil.urisEqual(ns.uri, WSDL_SOAP_URI))
+ {
+ soapNS = ns;
+ }
+ else if (URLUtil.urisEqual(ns.uri, WSDL20_SOAP_URI))
+ {
+ soapNS = ns;
+ }
+ else if (URLUtil.urisEqual(ns.uri, WSDL20_SOAP12_URI))
+ {
+ soapNS = ns;
+ }
+ }
+ }
+
+ // Default to WSDL 1.1
+ if (wsdlNS == null)
+ wsdlNS = new Namespace(WSDL_PREFIX, WSDL_URI);
+
+ if (soapNS == null)
+ soapNS = new Namespace(WSDL_SOAP_PREFIX, WSDL_SOAP_URI);
+
+ if (constantsCache == null)
+ constantsCache = {};
+
+ var constants:WSDLConstants = constantsCache[wsdlNS.uri];
+ if (constants == null)
+ {
+ constants = new WSDLConstants(wsdlNS, soapNS);
+ constantsCache[wsdlNS.uri] = constants;
+ }
+
+ return constants;
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ // WSDL QNames
+ public var definitionsQName:QName;
+ public var typesQName:QName;
+ public var messageQName:QName;
+ public var portTypeQName:QName;
+ public var bindingQName:QName;
+ public var serviceQName:QName;
+ public var importQName:QName;
+ public var documentationQName:QName;
+ public var portQName:QName;
+ public var operationQName:QName;
+ public var inputQName:QName;
+ public var outputQName:QName;
+ public var partQName:QName;
+ public var faultQName:QName;
+ public var wsdlArrayTypeQName:QName;
+
+ // WSDL SOAP QNames
+ public var soapAddressQName:QName;
+ public var soapBindingQName:QName;
+ public var soapOperationQName:QName;
+ public var soapBodyQName:QName;
+ public var soapFaultQName:QName;
+ public var soapHeaderQName:QName;
+ public var soapHeaderFaultQName:QName;
+
+ /**
+ * The namespace representing the version of SOAP used by a WSDL,
+ * currently 1.1 is supported.
+ * FIXME: Need SOAP 1.2 support.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private var _soapNS:Namespace;
+
+ /**
... 12758 lines suppressed ...