3 Replies Latest reply on May 10, 2010 1:28 PM by jemiller0

    Question on wrapping web services in Flex 4

    kpaul_rc

      Hi all,

       

      A brief intro:

       

      - I have several Java based web services (jax-ws/soap) that I've written on the server side.
      - The services are secured via WSSecurity.
      - I'm writing a Flex app to consume the above services.

       

      In Flex 3, I've had to manually tackle the wrapping of these services on the client because of the limited/unpredictable access to the underlying Flex base classes and their members.  Primarily I needed to be able to manage the soap headers of the web service calls to insert the appropriate WSS header info prior to the service calls, but there were a handful of other issues with the Flex 3 implementation that made the use of the default generated mappings unuseable (or at least not worth the time).

       

      I was hoping that Flex 4 did a better job with this, but it looks like there are still problems with using the generated wrapper code...  So I got to wondering if I am just not doing things the proper Flex way.  I've done a lot of reading on the web, but maybe someone here can offer some advice.

       

      Here's an example of what I'm doing:

       

      I'm importing the wsdl for my services in Flash Builder 4 (Data | Connect to web service...).  Here's an example snippet of a Flex 4 generated class for one of my services:

       

      internal class _Super_SessionManagerService extends com.adobe.fiber.services.wrapper.WebServiceWrapper
      {
          // Constructor
          public function _Super_SessionManagerService()
          {
              // initialize service control
              _serviceControl = new mx.rpc.soap.mxml.WebService();
              var operations:Object = new Object();
              var operation:mx.rpc.soap.mxml.Operation;
             
              operation = new mx.rpc.soap.mxml.Operation(null, "Logout");
              operations["Logout"] = operation;
        
              _serviceControl.operations = operations;
              try
              {
                  _serviceControl.convertResultHandler = com.adobe.serializers.utility.TypeUtility.convertResultHandler;
              }
              catch (e: Error)
              { /* Flex 3.4 and eralier does not support the convertResultHandler functionality. */ }

       

              _serviceControl.service = "SessionManagerService";
              _serviceControl.port = "SessionManagerPort";
              wsdl = "https://localhost:8181/app/service/SessionManagerService?wsdl";
              model_internal::loadWSDLIfNecessary();
         
              model_internal::initialize();
          }

       

          public function Logout(Id:String) : mx.rpc.AsyncToken
          {
              model_internal::loadWSDLIfNecessary();
              var _internal_operation:mx.rpc.AbstractOperation = _serviceControl.getOperation("Logout");
              var _internal_token:mx.rpc.AsyncToken = _internal_operation.send(Id) ;

       

              return _internal_token;
          }

       

      ... et. al.
      }

       


      So from my vantagepoint, there are still some familiar problems with this:

       

      1) The url is hard coded in the constructor of the generated base class for my service and there is no way to alter this value before the class is constructed (at which point it attempts to load the wsdl and initialize the service).  I know that I can just edit this value in the generated class, but I and my team will need to remember to do this for all of my services each time they're regenerated (which is fairly often since this is an ongoing and growing project.)  This is a problem for us since we are developing and then deploying in several different environments with several different server url's.  It seems to me that you would never want to hard code this url anyway since it ties your binaries to a specific server (or virtual or url or etc.) - I just don't see why this decision was made since it causes more problems than it solves (i.e. why not pass this value as a parameter into the ctor?)

       

      2) If I attempt to copy/paste the constructor to a derived class to better manage 1 above, the member variables are all out of scope since they're declared as private in the WebServiceWrapper base class.  So, no solution there.

       

      3) When I attempt to look at the WebServiceWrapper base class to try and gain a little insight into how I might come up with a work-around, Flex 4 is telling me that it can't find the source code (and I can't seem to find the source for this class anywhere...)  So, now no hope for a solution.

       

      4) Finally, in the Logout method in the above class, there is still no way for me to intercede in the web service call to properly insert the WSS headers prior to the call being made to the server.  'model_internal' is not acessible outside this generated class, so overriding this method seems pointless.  I've looked around and there doesn't seem to be any Flex alternative to handling web service security headers, so it looks like I still need to manually provide at least this additional functionality, but the generated code doesn't account for anyone wanting to set/update the soap headers.

       


      Again, I know I can basically start hacking up this class to do anything special I might need, but I was hoping to leave the generated stuff untouched since we would be constantly reimplementing any tweaks/fixes each time we need to regenenerate a service wrapper.

       

      Am I missing something?  Is there another way to wrap web services in a Flex app without having to essentially write a bunch of roll-your-own wrappers?

       

      Thanks,
      Ken

        • 1. Re: Question on wrapping web services in Flex 4
          Radhakrishna Bhat Level 3

          Hello,

           

          1) Please file an enhancement request in https://bugs.adobe.com/flex/ on how you want to pass wsdl url to service. As a parameter to service constructor?. The 'wsdl' variable of WebServiceWrapper can be overridden in subclass ( SessionManagerService) in which case the new url will be loaded again.

           

          2) Member variables like _serviceControl (Actual WebService instance) and wsdl are accessible in subclass SessionManagerService. Use _serviceControl to override endpointURI or port.

           

          3) The Wrapper classes are part of fiber.swc, not part of Opensource SDK.

           

          4) Override (copy paste and modify) Logout method in subclass generated (SessionManagerService). Import model_internal namespace from com.adobe.fiber.core.model_internal. Use _serviceControl.addHeader or _serviceControl.addSimpleHeader to add headers.

           

          Only _Super_SessionManagerService will be regenerated when any change happens.

           

          -Radhakrishna

          • 2. Re: Question on wrapping web services in Flex 4
            kpaul_rc Level 1

            Hi Radhakrishna,

             

            Thanks kindly for responding to my question.  My apologies for taking so long to reply - priorities shifted and my attention was elsewhere...

             

            It appears that I was a bit hasty in my conclusions about FB4 - I made most of my judgements on the inaccessibility of the wrapper class and didn't read the error messages closely enough.  As a friend likes to say regarding things like this:  "Read *all* the words..."

             

            I did get the app successfully calling my secure services with a little fiddling - a *lot* less fiddling than FB3 requires.

             

            Again, many thanks.

             

            Ken

            • 3. Re: Question on wrapping web services in Flex 4
              jemiller0

              I don't even see how to set the event handlers for the different

              web service methods. In FB 3, using the generated classes, there were methods for this. It would be great if Adobe provided example code

              . FB 3's web service support was largely brain dead and broken. It seemed to work alright with .NET web services, but, not Java web services. I found that it had particular problems dealing with collections. I honestly don't know how Adobe could release code with this kind of crappy quality. I found that if the client had a problem parsing the incoming SOAP message, it would simply stop processing. However, it wouldn't throw an exception. i.e. it would just continue along it's merry way letting you think everything worked the way it was supposed to. This is programming 101. If an error occurs, it should NOT just continue along it's merry way. It should throw and exception and let you know there was a problem. The web service support when working with a JAX-WS web service was pretty much unusable under FB 3. I'll cross my fingers on 4. I found one other posting where it looked like the person was having to copy the returned values from a web service method into the value objects manually. Is this by design? Also, I agree on the hard coding of the variable containing the URL, but, it doesn't surprise me given how screwed up the web services support has been historically.