<?xml version="1.0" encoding="ISO-8859-1" ?>

<?xml-stylesheet type="text/xsl" 
href="/lib/xsl/devedge-1.00/article_en.xsl"?>
<nde:article 
  xmlns:nde="http://devedge.netscape.com/2002/de"
  url="/viewsource/2003/soap/01/"
  xmlns="http://www.w3.org/1999/xhtml"  
  xml:lang="en">

  <nde:header>
    <nde:title>SOAP in Netscape Gecko-based Browsers</nde:title>
    <nde:category>Article</nde:category>
    <nde:authlist>
      <nde:author>
        <nde:authname>Doron Rosenberg</nde:authname>
        <nde:authaffil>Netscape Communications</nde:authaffil>
        <nde:email href="/community/feedback/">Feedback</nde:email>
      </nde:author>
    </nde:authlist>
    <nde:pubdate year="2003" month="03" day="14"/>

    <nde:channels>
      <nde:channel id="viewsource" />
      <nde:channel id="gecko" />
      <nde:channel id="xml" />
      <nde:channel id="ns-7" />
      <nde:channel id="ns-7.1" />
    </nde:channels>
  
    <nde:summary>
      Learn how to use SOAP in Netscape Gecko to access web services.
    </nde:summary>  
  
    <nde:abstract>
      This article shows how to access web services using the SOAP and JavaScript capabilities 
      available in recent Netscape Gecko-based browsers.
    </nde:abstract>    
  </nde:header>

 <nde:head>
   <style type="text/css">
     .sourceCode {padding-left: 5px; padding-top:5px;}        
     
     .sourceView {margin: 5px; padding: 5px; border: 1px dashed grey; font-family: Verdana,sans-serif;}
     .sourceInfo {padding-bottom: 5px; font-size: 0.9em; padding-right: 5px; border-bottom: 1px dashed gray; 
                  border-right: 1px dashed gray;}
      /*#content h2 {margin-top: 1em}*/
    </style>
</nde:head>

<nde:content>

  <h2>Introduction</h2>
     <p>
       Simple Object Access Protocol (<a href="http://www.w3.org/TR/SOAP/">SOAP</a>) is the basis on which web services are built.  It 
       is an XML-based protocol used to communicate and interoperate with web services.  With Mozilla 1.0 (upon which Netscape 7.0x is 
       built), it is now possible for the browser to directly communicate with web services using its low-level SOAP implementation 
       through JavaScript.
     </p>
        
    <p>
      Gecko's JavaScript interface for establishing SOAP calls is a low-level API which requires one to build the SOAP envelope using
      several SOAP-specific JavaScript objects.  This article will cover the basic SOAP operations, for a more detailed look at 
      the low-level SOAP API in Gecko click 
      <a href="http://lxr.mozilla.org/mozilla/source/extensions/webservices/docs/Soap_Scripts_in_Mozilla.html">here</a>.      
    </p>

     <p>
       Using JavaScript to talk to web services is subject to the same security policies as other scripts in terms of cross 
       domain access.  Therefore, accessing web services on a server other than the one where the JavaScript lives
       will violate the cross-domain policy.  This article will show how to temporarily circumvent this for testing purposes.
     </p>  
       
  <h2>Setting Up a SOAP Call</h2>
     
    <p>
      The most basic object is <code>SOAPCall</code>, which is used to initiate and invoke a SOAP call.
    </p>
     
     <p>     
       <div class="sourceView">
         <span class="sourceInfo">Figure 1 : Basic setup and invocation of a SOAP Call</span>
    
         <p class="sourceCode">           
            var mySOAPCall = new SOAPCall();<br />
            mySOAPCall.transportURI = "http-based service URI"<br />
            mySOAPCall.encode(0, "method name ", "target object namespaceURI ", 0, null, SOAPParameter array.length, SOAPParameter 
              array);<br />
            var response = mySOAPCall.invoke();
         </p>         
       </div>        
     </p>
     
     <p>
       A <code>SOAPCall</code> object has a member called <code>transportURI</code>, which is the URI of the location where it 
       should send the SOAP call to.  The <code>encode</code> method requires the name of the method to call at the web service, 
       its namespaceURI, the amount of SOAPParameters passed in, and an array of SOAPParameters which contains all the parameters.
       All these parameters can be found in the WSDL file for the web service, which is discussed in the Example section.
     </p>
     
     <p>
       SOAP parameters are created using the <code>SOAPParameter</code> object.  They are name/value pairs that are passed to the
       web service.
     </p>
     
     <p>     
       <div class="sourceView">
         <span class="sourceInfo">Figure 2 : Creating a SOAP parameter</span>
    
         <p class="sourceCode">           
	       var param = new SOAPParameter(); <br />
		   param.name = "translationmode"; <br />
           param.value = "en_fr";
         </p>         
       </div>        
     </p>     

  <h2>Handling the Response</h2>     
  
    <p>
      Once <code>invoke</code> is called, Gecko generates the SOAP envelope and sends it to the URI specified.  Since the request is 
      synchronous, the response is the return value of <code>invoke</code>.
    </p>  
    
     <p>
       <div class="sourceView">
         <span class="sourceInfo">Figure 3 : Handling the response of a SOAP call</span>
    
         <p class="sourceCode">           
           var returnObject = mySOAPCall.invoke(); <br /><br />
      
           if(returnObject.fault){<br />
             &#160;&#160;alert("An error occured: " + returnObject.fault.faultString);<br />
           } else {<br />
             &#160;&#160;var response = new Array();<br />
             &#160;&#160;response = returnObject.getParameters(false, {});<br />
             &#160;&#160;alert("Return value: " + response[0].value);<br />
           }
         </p>         
       </div>        
     </p>

     <p>
       The return value of <code>invoke</code> is stored and checked for a <code>fault</code> member.  If it exists,
       an error occurred at the web service, and the error message is stored in <code>fault.faultString</code>.  If 
       <code>fault</code> doesn't exist, we call the <code>getParameters</code> function on the returned object to retrieve
       the returned SOAPParameters.
     </p>   

  <h2>Example</h2>

    <p>
      The example uses an existing web service, Babelfish, which is provided by <a href="http://www.xmethods.net">xmethods.net</a>.  
      The Babelfish web service allows translating between several languages.  It takes as an input two parameter: a string in the 
      format of "originalLanguage_resultLanguage" and the text to translate as another string.  The WSDL file for the Babelfish 
      web service is available 
      <a href="http://www.xmethods.net/sd/2001/BabelFishService.wsdl">here</a> and contains all the information needed to setup a
      low-level SOAP call to the web service.  
    </p>    
    
    <p>
      The first step is to figure out the location of the web service, which will be the value of the <code>SOAPCall</code>'s 
      <code>transportURI</code> member.  This can be found in the WSDL's <code>service</code> element, specifically the 
      <code>location</code> attribute of <code>soap:address</code>.      
    </p>

     <p>
       <div class="sourceView">
         <span class="sourceInfo">Figure 4 : Figuring out the location of a web service from its WSDL</span>
    
         <p class="sourceCode">
           <strong>WSDL:</strong><br />
             &lt;service name="BabelFishService"><br />
           	   &#160;&#160;&lt;documentation><br />
                 &#160;&#160;&#160;&#160;Translates text of up to 5k in length, between a variety of languages.<br />
               &#160;&#160;&lt;/documentation><br />
               &#160;&#160;&lt;port name="BabelFishPort" binding="tns:BabelFishBinding"><br />
                 &#160;&#160;&#160;&#160;<span style="color:green;">&lt;soap:address location="http://services.xmethods.net:80/perl/soaplite.cgi"/></span><br />
               &#160;&#160;&lt;/port><br />
             &lt;service><br /><br />
           
           <strong>JavaScript:</strong><br />
           var babelFishCall = new SOAPCall();<br />
           babelFishCall.transportURI = "http://services.xmethods.net:80/perl/soaplite.cgi";<br />
           ...
         </p>         
       </div>        
     </p>    

    <p>
      The next step is the most complex one - figuring out exactly what the web service expects to be sent in terms of 
      parameters.  The Babelfish web service only has one method, "BabelFish", which in the WSDL is represented
      in <code>operation</code> tags, which is a child of the <code>portType</code> element.  Each WSDL <code>operation</code>
      has two children: the input and output elements, which contain the type expected.  The types are defined in <code>message</code>
      elements, of which there are two:  BabelFishRequest, which is what is going to be passed into the web service, and 
      BabelFishResponse, the return type.  As can be seen, the operation BabelFish expects two in parameters: <code>translationmode</code>
      and <code>sourcedata</code>.  The example will translate from english to french the string "I am".
    </p>

     <p>
       <div class="sourceView">
         <span class="sourceInfo">Figure 5 : Setting up the needed parameters</span>
    
         <p class="sourceCode">
           <strong>WSDL:</strong><br />
             &lt;message <span style="color:blue;">name="BabelFishRequest"></span><br />
               &#160;&#160;<span style="color:green;">&lt;part name="translationmode" type="xsd:string"/></span><br />
               &#160;&#160;<span style="color:green;">&lt;part name="sourcedata" type="xsd:string"/></span><br />
             &lt;/message><br /><br />

          	 &lt;message name="BabelFishResponse"><br />
               &#160;&#160;&lt;part name="return" type="xsd:string"/><br />
             &lt;/message><br /><br />
 
           	&lt;portType name="BabelFishPortType"><br />
              &#160;&#160;&lt;operation name="BabelFish"><br />
                &#160;&#160;&#160;&#160;<span style="color:green;">&lt;input message="tns:BabelFishRequest"/></span><br />
                &#160;&#160;&#160;&#160;&lt;output message="tns:BabelFishResponse"/><br />
              &#160;&#160;&lt;/operation><br />
            &lt;/portType><br /><br />
           
           <strong>JavaScript:</strong><br />
             // SOAP params<br />
             var param1 = new SOAPParameter();<br />
             param1.value = "en_fr";<br />
             param1.name = "translationmode";<br /><br />
        
             var param2 = new SOAPParameter();<br />
             param2.value = "I am";<br />
             param2.name = "sourcedate";<br /><br />

             // combine the 2 params into an array<br />
             var myParamArray = [param1,param2];
         </p>         
       </div>        
     </p>         
     
     <p>
       Next it's time to setup and invoke the SOAPCall object.  "BabelFish" is the method the example wants to use at the 
       web service.  The next parameter is the namespace expected to be passed into the web service for the method BabelFish.
       This can be found in the WSDL <code>binding</code> element.  The <code>binding</code> element has again an <code>operation</code>
       child for the BabelFish method.  The namespace needed is the value of the <code>namespace</code> attribute of <code>soap:body</code>
       inside the <code>input</code> element.
     </p>
     
     <p>
       <div class="sourceView">
         <span class="sourceInfo">Figure 6 : Setting up the encode method</span>
    
         <p class="sourceCode">
           <strong>WSDL:</strong><br />
             &lt;binding name="BabelFishBinding" type="tns:BabelFishPortType"><br />
               &#160;&#160;&lt;soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/><br />
               &#160;&#160;&lt;operation name="BabelFish"><br />
                 &#160;&#160;&#160;&#160;&lt;soap:operation soapAction="urn:xmethodsBabelFish#BabelFish"/><br />
 	             &#160;&#160;&#160;&#160;&lt;input><br />
                   &#160;&#160;&#160;&#160;&#160;&#160;<span style="color:green;">&lt;soap:body use="encoded" namespace="urn:xmethodsBabelFish" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></span><br />
                 &#160;&#160;&#160;&#160;&lt;/input><br />
                 &#160;&#160;&#160;&#160;...<br />
               &#160;&#160;&lt;/operation><br />
             &lt;/binding><br /><br />
            
           <strong>JavaScript:</strong><br />          
           babelFishCall.encode(0, "BabelFish", "urn:xmethodsBabelFish", 0, null, myParamArray.length, myParamArray);<br /><br />
	
           var translation = babelFishCall.invoke();
         </p>         
       </div>        
     </p>             

     <p>
       As seen in Figure 5, the response of the BabelFish method ("BabelFishResponse") has one parameter, namely a string.  After
       making sure no fault was returned, the returned object's <code>getParameters</code> method is used to retrieve an array of
       SOAPResponses.  Since only one return parameter is expected, it is alerted as the translation.
     </p>
     
     <p>
       <div class="sourceView">
         <span class="sourceInfo">Figure 7 : Handling the response</span>
    
         <p class="sourceCode">            
           <strong>JavaScript:</strong><br />
           if(translation.fault){<br />
               &#160;&#160;// error returned from the web service<br />
               &#160;&#160;alert(translation.fault.faultString);<br />
           } else {<br />
               &#160;&#160;// we expect only one return SOAPParameter - the translated string.<br />
               &#160;&#160;var response = new Array();<br />
               &#160;&#160;response = translation.getParameters(false, {});<br />
               &#160;&#160;alert("Translation: " + response[0].value);<br />
           }               
         </p>         
       </div>        
     </p>     
     
     <p>
       As mentioned in the introduction, SOAP calls obey the cross domain access policy for scripting.  
       There are two ways to circumvent the security policy for testing purposes: 
     </p> 
    
    <ol>
      <li>
        <p>Run the script from your local drive</p>
        <p>
          Save the code locally to your hard disk.  
          The cross-domain security model does not affect code run from the local hard disk.
        </p>
      </li>
      <li>
        <p>Enable Cross Domain Access</p>
        <p>
          You can bypass the cross-domain check by setting a preference as explained in 
          <a href="/viewsource/2002/bypassing-security-restrictions/">Bypassing 
            Security Restrictions and Signing Code</a> article and in adding a JavaScript 
          command to request overriding of the cross-domain check.  The first step is to 
          locate the profile used in the Netscape Gecko-based browser.  The Netscape 7.0x 
          <a href="http://wp.netscape.com/eng/mozilla/ns7/relnotes/7.html#profiles_location">release 
            notes</a> contain a table of profile location depending on operating system.  
          Each profile has a "salt" directory, which then leads to the actual profile.  
          Shut down the browser and place <a href="user.js">user.js</a> in that directory 
          (there should be a prefs.js file in the same directory).
        </p>  
        <p>
          After adding the the file, start the browser and load this <a href="example-crossdomain.html">modified 
            example page</a>. It will ask (via a dialog) for permissions to turn off cross-domain (for this session) for the function generating the SOAP call.
          The only change made is adding <code>netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");</code> to
          the function that generates the SOAP call.
        </p>
      </li>
    </ol>
     
     <p>
       <div class="sourceView">
         <span class="sourceInfo">Figure 8 : Final Code - 
           <a href="example.html">Local example</a>,
           <a href="example-crossdomain.html">Cross-Domain example</a>,
         </span>
    
         <p class="sourceCode">            
           <strong>JavaScript:</strong><br />            
           var babelFishCall = new SOAPCall();<br />
           babelFishCall.transportURI = "http://services.xmethods.net:80/perl/soaplite.cgi";<br /><br />

           // SOAP params<br />
           var param1 = new SOAPParameter();<br />
           param1.value = "en_fr";<br />
           param1.name = "translationmode";<br /><br />
        
           var param2 = new SOAPParameter();<br />
           param2.value = "I am";<br />
           param2.name = "sourcedate";<br /><br />

           // combine the 2 params into an array<br />
           var myParamArray = [param1,param2];<br /><br />
       
           babelFishCall.encode(0, "BabelFish", "urn:xmethodsBabelFish", 0, null, myParamArray.length, myParamArray);<br /><br />
	
           var translation = babelFishCall.invoke();<br /><br />

           if(translation.fault){<br />
               &#160;&#160;// error returned from the web service<br />
               &#160;&#160;alert(translation.fault.faultString);<br />
           } else {<br />
               &#160;&#160;// we expect only one return SOAPParameter - the translated string.<br />
               &#160;&#160;var response = new Array();<br />
               &#160;&#160;response = translation.getParameters(false, {});<br />
               &#160;&#160;alert("Translation: " + response[0].value);<br />
           }               
         </p>         
       </div>        
     </p>

    <h2>Tracking the SOAP Envelope</h2> 
     <p>
       Here is a HTTP dump (using the cross-platform <a href="http://www.ethereal.com/">Ethereal</a> tool) of what actually gets sent 
       and retrieved when the example gets executed:
     </p>
     
     <p>
       <div class="sourceView">
         <span class="sourceInfo">Figure 9 : HTTP Dumps</span>
    
         <p class="sourceCode">            
           <strong>Sent:</strong><br />
           POST /perl/soaplite.cgi HTTP/1.1<br />
           Host: services.xmethods.net:80<br />
           ...<br />
           Content-Type: text/xml<br />
           Content-Length: 516<br /><br />
           &lt;env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:enc="http://schemas.xmlsoap.org/soap/encoding/"<br />
             &#160;&#160;&#160;&#160;env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xs="http://www.w3.org/1999/XMLSchema"<br />
             &#160;&#160;&#160;&#160;xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"><br />
             &#160;&#160;&lt;env:Header/><br />
             &#160;&#160;&lt;env:Body><br />
               &#160;&#160;&#160;&#160;&lt;a0:BabelFish xmlns:a0="<span style="color:green;">urn:xmethodsBabelFish</span>"><br />
                 &#160;&#160;&#160;&#160;&#160;&#160;<span style="color:green;">&lt;a0:translationmode xsi:type="xs:string">en_fr&lt;/a0:translationmode></span><br />
                 &#160;&#160;&#160;&#160;&#160;&#160;<span style="color:green;">&lt;a0:sourcedata xsi:type="xs:string">I am&lt;/a0:sourcedata></span><br />
               &#160;&#160;&#160;&#160;&lt;/a0:BabelFish><br />
             &#160;&#160;&lt;/env:Body><br />
           &lt;/env:Envelope><br /><br />
           
           <strong>Recieved:</strong><br />
           HTTP/1.1 200 OK<br />
           Date: Tue, 11 Mar 2003 20:28:11 GMT<br />
           Server: Apache/1.3.26 (Unix) Enhydra-Director/3 PHP/4.0.6 DAV/1.0.3 AuthNuSphere/1.0.0<br />
           SOAPServer: SOAP::Lite/Perl/0.52<br />
           Content-Length: 532<br />
           ...<br />
           Content-Type: text/xml; charset=utf-8<br /><br />

          &lt;?xml version="1.0" encoding="UTF-8"?><br />
          &lt;SOAP-ENV:Envelope xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema"><br />
            &#160;&#160;&lt;SOAP-ENV:Body><br />
              &#160;&#160;&#160;&#160;&lt;namesp1:BabelFishResponse xmlns:namesp1="urn:xmethodsBabelFish"><br />
                &#160;&#160;&#160;&#160;&#160;&#160;<span style="color:green;">&lt;return xsi:type="xsd:string">je suis&lt;/return></span><br />
               &#160;&#160;&#160;&#160;&lt;/namesp1:BabelFishResponse><br />
            &#160;&#160;&lt;/SOAP-ENV:Body><br />
          &lt;/SOAP-ENV:Envelope><br />
         </p>         
       </div>        
     </p>    
     
  <h2>Resources</h2>    
     <ul>
       <li><a href="http://lxr.mozilla.org/mozilla/source/extensions/webservices/docs/Soap_Scripts_in_Mozilla.html">
         SOAP Scripts in Mozilla</a> by Ray Whitmer</li>
       <li><a href="http://developer.apple.com/internet/webservices/mozillasoapapi.html">Using the Mozilla SOAP API</a> 
         at Apple Developer.</li>
       <li><a href="http://www.w3.org/TR/SOAP/">The w3.org SOAP Specification</a></li>
       <li><a href="/viewsource/2002/bypassing-security-restrictions/">Bypassing Security Restrictions and Signing Code</a></li>       

     </ul>    
  </nde:content>

  <nde:related area="nde">
    <nde:item url="/central/xml">XML Central</nde:item>
    <nde:item url="/library/releases/netscape-7/">Other Articles about Netscape 7</nde:item>
  </nde:related> 

  <nde:related area="ext">
  	<nde:item url="http://www.mozilla.org/projects/webservices/">Web Services Project Page - Mozilla.org</nde:item>
    <nde:item url="http://lxr.mozilla.org/mozilla/source/extensions/webservices/docs/Soap_Scripts_in_Mozilla.html">
      SOAP Scripts in Mozilla</nde:item>
    <nde:item url="http://developer.apple.com/internet/webservices/mozillasoapapi.html">Using the Mozilla SOAP API</nde:item>
    <nde:item url="http://www.w3.org/TR/SOAP/">W3.org SOAP Specification</nde:item>    
  </nde:related>
  
</nde:article>

