1. #1
    Ext User
    Join Date
    Dec 2007
    Posts
    6
    Vote Rating
    0
    resmond is on a distinguished road

      0  

    Default a trial SoapProxy object

    a trial SoapProxy object


    I have read, and left a number of posts about using Ext with a classic SOAP implemenation and hadn't seen anything definitive about how to do this. I still suspect that there is an existing solution to this problem, but since I couldn't find it, I started writing one. I have built a SoapProxy implementation by starting with the HttpProxy and reading through the codeset for the Ext.lib.Ajax implementation and making a few guesses. I now have this working quite well with the latest Apache Axis implementation, so I figured I would post the code and get some feedback. I should warn everyone that I have only been using Ext for about a week and I suspect that this might not be the best way of building this interface... but it certainly is working correctly in my application.

    The sample that sets up a Store and Grid object to use the SoapProxy was cut from a working application and then edited down to be smaller and more portable, so I might have screwed it up somewhere. If anyone has a problem getting it to run, I would suspect the sample setup code is the problem rather than the SoapProxy code, because that has gotten a good bit of testing.

    I just realized that I didn't externalize the URI-Namespace of the specific SOAP api, so that
    would have to be changed in the code for someone to use this... but I will fix that and post
    it again later. For now you would have to edit the 'http:www.company.com/api" string in
    the envelope building function to reflect the namespace of 'your' api, if you want to use a
    namespace. In my next post I will move that to a parameter that defaults to no namespace.

    If anyone has any feedback, I would appreciate it...

    Code:
    Ext.namespace( "Ext.soap" );
    
    Ext.data.SoapProxy = function()
    {
      Ext.data.SoapProxy.superclass.constructor.call(this);
    };
    
    Ext.extend(Ext.data.SoapProxy, Ext.data.DataProxy,
    {
        getConnection : function()
        {
          return Ext.Ajax
        },
    
        load : function(params, reader, callback, scope, arg)
        {
          if(this.fireEvent("beforeload", this, params) !== false)
          {
            var xmlData = Ext.brit.makeSoapEnvelope( params.methodName, params.xmlParams );
            if ( params.method == "get" )
              xmlData = "";
            else 
                params.methodName = "post";
    
            // if you want to 
            var  o = { method:  params.method,
                       url:     params.url,
                       headers: {SOAPAction: params.methodName},
                       xmlData: xmlData,
                       params: null,
                       request:
                         { callback : callback,
                           scope : scope,
                           arg : arg },
                       reader: reader,
                       callback : this.loadResponse,
                       scope: this };
    
            if(this.activeRequest)
            {
              Ext.Ajax.abort(this.activeRequest);
            }
    
            // This may be somewhat of a hack to drive below the Ext.Ajax layer and
            // talk directly to the Ext.lib.Ajax layer, but the Apache - Axis container
            // gave an error until I got rid of the default post headers
            Ext.lib.Ajax.setDefaultPostHeader(false);
            this.activeRequest = Ext.Ajax.request( o );
          }
          else
          {
            callback.call(scope||this, null, arg, false);
          }
        },
    
        loadResponse : function(o, success, response)
        {
          delete this.activeRequest;
          if(!success)
          {
            this.fireEvent("loadexception", this, o, response);
            o.request.callback.call(o.request.scope, null, o.request.arg, false);
            return;
          }
          var result;
          try
          {
            result = o.reader.read(response);
          }
          catch(e)
          {
            this.fireEvent("loadexception", this, o, response, e);
            o.request.callback.call(o.request.scope, null, o.request.arg, false);
            return;
          }
    
          this.fireEvent("load", this, o, o.request.arg);
          o.request.callback.call(o.request.scope, result, o.request.arg, true);
        },
    
        update : function(dataSet)
        {
        },
    
        updateResponse : function(dataSet)
        {
        }
    });
    
    /********************************************************************************
     *
     * makeSoapEnvelope - I have hard coded the url to a company API as a namespace referred
     * to as api:... this needs to be externalized in the call!
     *
    ******************************************************************************/
    Ext.soap.makeSoapEnvelope = function( methodName, soapEnvelope )
    {
      var xmlStr = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" +
                   "<SOAP-ENV:Envelope xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\r\n" +
                   "  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\r\n" +
                   "  xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\"\r\n" +
                   "  SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"\r\n" +
                   "  xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"\r\n" +
                   "  xmlns:api=\"http://www.company.com/api\">\r\n" +
                   "  <SOAP-ENV:Body>\r\n" +
                   "    <api:" + methodName + ">\r\n";
    
      this.buildParam = function(paramName, paramValue )
      {
        xmlStr += "      <api:"+paramName+">" + paramValue + "</api:" + paramName + ">\r\n";
      }
    
      for(var prop in soapEnvelope )
        if(soapEnvelope.hasOwnProperty(prop))
          this.buildParam( prop, soapEnvelope[ prop ] );
    
      xmlStr += "    </api:" + methodName + ">\r\n" +
                "  </SOAP-ENV:Body>\r\n" +
                "</SOAP-ENV:Envelope>";
    
      return xmlStr;
    }
    /********************************************************************************
     *
     * SoapGridPanel() - sample code to show how to use the SoapProxy... was cut from other
     * code, so it may contain some errors...
     * *******************************************************************************/
    function SoapGridPanel(  )
    {
    
      // list of elements in the response list to parse out of the result XML
      var fieldList = [ 'id', 'name', 'date', 'desc' ];
    
      // this is the XML element that will be the parent of the 'fieldList'
      var recordName = 'record';
    
      var colList =
        [ {header: "Id",    width: 120, dataIndex: 'id',   sortable: true},
          {header: "Name",   width:  80, dataIndex: 'name',  sortable: true},
          {header: "Date",   width:  80, dataIndex: 'date',  sortable: true},
          {header: "Description",   width:  80, dataIndex: 'desc',  sortable: true} ];
    
      Ext.soapStore =
        new Ext.data.Store(
          { proxy: new Ext.data.SoapProxy(),
            reader: new Ext.data.XmlReader({ record: recordName }, 
                                                           fieldList )});
    
      var soapGrid =
        {  id:           'soapgrid',
           xtype:      'grid',
           store:       Ext.soapStore,
           columns:   columnList,
           listeners:   listenerList };
    
      // these will be passed to the SOAP container as XML in the body of the post
      var xmlParams = { param1 : 'testparam1', param2: 'testparam2' };
    
      this.doQuery = function( url, methodName, xmlParams )
      {
        Ext.soapStore.load({ params: { url: url, 
                                                   methodName: methodName, 
                                                   xmlParams : xmlParams }});
      }
    
      return soapGrid;
    }
    Last edited by brian.moeskau; 23 Dec 2007 at 8:37 AM. Reason: code tags

  2. #2
    Sencha User pgiuseppe's Avatar
    Join Date
    Oct 2007
    Posts
    27
    Vote Rating
    0
    pgiuseppe is on a distinguished road

      0  

    Default SOAP for Java script alternative

    SOAP for Java script alternative


    Nice job but do you already know this one?
    http://www.codeplex.com/JavaScriptSoapClient

  3. #3
    Ext User
    Join Date
    Dec 2007
    Posts
    6
    Vote Rating
    0
    resmond is on a distinguished road

      0  

    Default I wanted it integrated with Ext.data...

    I wanted it integrated with Ext.data...


    I really like the XML parsing support and Grid support that I got from Ext, so I figured I would get the best bang for the buck by having a SOAP implementation that as native to Ext as possible. It seemed like the most appropriate way from an Ext perspective was to build a Soap based Proxy.

    Once I looked at the source code for the HttpProxy, I realized that that it wasn't a very coding intense solution either. The most difficult thing turned out to be getting the headers right to work with Apache Axis. It was kind-of particular about what could be included in the header without producing a 'Unable to internalize SOAP request' failure. But after I figured out that it went pretty smooth.

    It can still use some further elaboration on parameter passing and turning error response codes into something useful... like a Exception. I will add that stuff this week, but I figured I might get some useful feedback from other people with more Ext experience before I tried to finalize anything... Who knows what kind of stuff I might not know about.

  4. #4
    Sencha - Ext JS Dev Team Animal's Avatar
    Join Date
    Mar 2007
    Location
    Notts/Redwood City
    Posts
    30,496
    Vote Rating
    44
    Animal has a spectacular aura about Animal has a spectacular aura about Animal has a spectacular aura about

      0  

    Default


    I have to say nice job. Considering you have just started with Ext, I admire your initiative in getting stuck into the source, and getting your idea off the ground without fuss!

    I'm no expert, but I have written some SOAP serialization/deserialization for other languages, so I think there's more that can be done. You can also encapsulate data type into each parameter. And represent Arrays, compound data types, and null values

    Here is a good resource which explains this: http://www.soapware.org/bdg

    Just something to be thinking about over the holidays. I think it could be very useful to have a native Ext way of communicating with SOAP webservices.

  5. #5
    Ext User
    Join Date
    Dec 2007
    Posts
    6
    Vote Rating
    0
    resmond is on a distinguished road

      0  

    Default Thanks for the link

    Thanks for the link


    That site looks good... I will take a look at it and update the Proxy and re-post it later this week...

    Thanks!

Thread Participants: 2