Networking and Server • 51:52
This session introduces web services, with an overview of the toolkits and frameworks available in Mac OS X. An explanation of important concepts and terminology is followed by an in-depth exploration of Apple's web service framework, a client-side framework for accessing web services from Mac OS X. Techniques for writing web services glue and adding it to Cocoa, Carbon, and AppleScript applications are also demonstrated.
Speakers: Steve Zellers, Tim Bumgarner
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Steve, good morning. I want to make sure I understand how this thing works. This is me, Steve Zelers, and I'm an engineer working on web services frameworks for Mac OS X. So, before we begin, let's talk about what a web service is, what it means to us and to developers. A web service is basically an endpoint, or a method, that you can access over the internet using standard protocols, including XML and HTTP, to either get a result or perform some action on, well, we call it an endpoint. This is usually an HTTP server.
It's heterogeneous. That means that the clients and the servers can be running on different architectures, and they're all just going to speak a lingua franca called XML. There are commercial web services, which are things that you might pay for. If you had a business that needed some piece of information, someone else could put up a web service that provided that information, and you would access it. You would access it through a web services toolkit, and you would be billed for it.
And then there are private or not commercial web services that you could also access. So, some examples that you'll see on the net. Barnes & Noble has a web service that you give it an ISBN number, it gives you the price of the book. There's also a web service that tells you the current temperature in a zip code. So, Cupertino is 95014. You would send it 95014. It would tell you that it's a balmy 68. degrees or some such.
The standards in web services are all built on acronyms. There are dozens and dozens of acronyms, and I'm only going to talk about a few of these during this presentation. XMLRPC and SOAP are both formats of web service invocations. That is, these are mutually exclusive, different ways of packaging up the data that you're sending to the web service. These are both built on top of XML, which is a standard for presenting information in a way that is reliable.
The other side is guaranteed to either understand the message or not. It's also very easy for humans to read, so that we get an understanding of what the data is that's being sent. These are both, in our case, sent on top of HTTP, which we all know is used to access web pages on the Internet and also to do HTTP posts, which web services typically are done via HTTP post. There's another acronym called WSDL, W-S-D-L, which stands for Web Service Description Language. This is an XML document that describes what services are available at an endpoint. I'll talk about that a little more later.
Here's an architectural diagram of what XMLRPC and SOAP look like sitting on top of XML. In addition, SOAP sits on top of XML schemas, which give you a very rich type system. This is a very interesting example of what XMLRPC and SOAP look like sitting on top of XML. There are actually two ways of encoding SOAP documents. The phrase you're going to hear a little later is called Section 5 encoding. In this, the XML that you're sending is typed.
It's strongly typed with a tag on the XML that says, "This element is an integer," or "This element is a string." XML schemas let you build up complex types. Again, I'll talk about those a little later on. As you can see, XML writing on top of HTTP is typically what we think of as a web service.
So, here's the state of XML web services today. XMLRPC is a spec that was developed by a company called Userland with some independent developers, with help from Microsoft and some other folks. And basically, it was published by this company and is used by them and by other vendors to implement a simple RPC mechanism on top of XML and on top of HTTP post.
It is done. The guy who owns the spec isn't moving on it. And that means you can implement the spec today, and it's pretty much guaranteed to work tomorrow. It's not a moving target. SOAP is an evolving standard, however. SOAP 1.0 was developed by Userland and Microsoft and some other folks. And it's a little different from XMLRPC.
The syntax is a little different, but fundamentally, it's trying to do the same thing. And as SOAP evolves, more and more extensions have been added onto it. So, as of today, SOAP 1.1 is... SOAP 1.2 is a W3C recommendation, the World Wide Web Consortium recommendation, which means it's basically done. It's no longer a moving target. SOAP 1.2 is a W3C note, which means it's still a moving target.
It's still being debated. The extensions to the specification aren't final yet. In addition, SOAP includes something called a header, which can contain additional information for SOAP extensions. And SOAP extensions can be anything that a platform vendor might want to add. So... SOAP is more of a moving target, but it's still being pushed very heavily by Microsoft.
So the difference between these two specifications. XMLRPC is very simple. I'm going to show you an example of what the message actually looks like in a minute. SOAP 1.1 could be as simple as SOAP, but it could also be written in a more complex way. It's kind of like Perl. You can write your Perl code any way you want, and it may look like line noise or it may look like Java, and it's up to you to make that distinction.
Both of them have basic type support for scalars, integer, string, double, and date, and binary data passed as base64. And it has support for custom types, arrays, and records. Soap enhances this by adding multi-ref support so you could have a single element in an XML document that is referenced multiple times, and it also has user types in the form of XML schemas.
In XMLRPC, there is a major flaw, or what most of us think of as a flaw, in that the string parameters must be passed as US ASCII text. If you have international text that you want to pass, you have to encode it as base64 binary. This has been a bone of contention for a lot of people, and it's just something you have to deal with in the API. XMLRPC passes parameters by position. If you have, say, a routine that adds two numbers, A and B, or, say, divides two numbers where the position is important, the XMLRPC routine has to take those parameters in order A, B.
The SOAP method takes them as named parameters. You can say element A or parameter A has a value 4, parameter B has a value 2. XMLRPC can only be transported
[Transcript missing]
So how do you access web services? Well, there are dozens and dozens of toolkits for both XMLRPC and SOAP.
And the thing to remember about these toolkits is that they bind a framework to the runtime model of your application. So if you have an application written in Java, it's probably a good bet to go with one of the established Java, SOAP, or XMLRPC implementations because they will match your object model. But it's an investment to bring one of these toolkits into your application.
If you go out on the net and grab a toolkit, then start shipping it with your application, you're going to be forced to maintain that toolkit and your customers are going to have to hear about it. Or you'll hear about it when your customers are dissatisfied with some bug or something else. So you want to choose the toolkit that best matches your runtime environment and your application frameworks.
So what did we do in Mac OS 10.1? Well, last year at the conference, we were really pushing Mac OS X and what was available then. And coming out a few months later was Mac OS 10.1, and we couldn't tell you about one of the exciting features in Mac OS 10.1, which is XMLRPC and SOAP 1.1 support baked into the Apple Event Manager. Because it was baked into the Apple Event Manager, AppleScript got support for this for free. In a few minutes, we'll have a demo of that.
This proved to be a very popular way for people on our platform to access these web services. They didn't have to go out on the net and download a toolkit and make sure their customers had it. They just had to make sure their customers had 10.1, which most everybody did, and they were able to write applications that took advantage of the support built into the system. It works by hijacking an addressing mode for an Apple event.
An Apple event, for those of you who are new to our platform, is an interprocess communication mechanism. And in 10.1, we reintroduced remote Apple events, the ability to send a binary message to another application on another computer, another Mac OS X computer. And for addressing modes that were HTTP, we treated them as a web service. We were able to do this without any API changes to the Apple Event Manager, and just by enabling some additional data types that hinted to the Apple Event Manager that the method that needed to be called was to be called using the XMLRPC or SOAP framework.
So I'm going to give the canonical XML RPC example, which is to call the method examples.getStateName on the server http://betty.userland.com/port80/rpc2. When I go to send this message, I'm going to open up an HTTP connection and do an HTTP post to that site with an XML document. And the XML document takes a single integer as a parameter and returns a string.
This is what that message is going to look like. It's XML. It has a structure to it that includes the method name and a parameter list. In this case, there's a single parameter. You can see the parameter is number 41 encased in an element tag that says i4. That's XML RPC's indicator that the element is typed as a long integer.
And in response, the server comes back by saying, "Okay, the return value from that method is the string South Dakota." Now, the server is returning, I think, basically it's got an array of 50 states, and it returns element 41 in the array in no particular order. So it's not a very interesting example, but it shows the message in response pretty well.
[Transcript missing]
So the next thing we do is create the event that we're going to send. And just like in the normal Apple Event Manager, you create the target address. In our case, it's an application URL. Type char should be on that slide. And then you give it the location that you're going to post the event to. Then you create the event with the special event class and ID of KAERPC class and the event ID of KAERPC.
Steve Zellers, Tim Bumgarner So this is what we've created. We've created an Apple event on the left-hand side of the screen, and the callouts show you basically what the contents of the Apple event look like. You've got the class, the scheme, the target address, and the direct object is broken out into a record with two fields.
The examples that get state name is the method name. The parameters is actually a list containing the number 41. Okay, so then you send the event and you deal with the reply. Apple events can be sent synchronously or asynchronously, which means that if it's an asynchronous call, you're going to receive the reply as an Apple event, as a class AEVT, ANSR. But in this case, we're just going to say, send the event, wait for the reply.
This opens up the connection to the remote site and sends the event, gets the reply, turns it back into an Apple event descriptor, and then you can pull out, out of the reply, the direct object, which in our case is a string, and then you can call printf because your Unix programmer is now, and you can call printf with impunity.
You can have more complex types in an Apple event. You can have an AE list gets turned into an array in the XML, and an AE record gets turned into a structure, which is a key-value pair. The problem with Apple event records, though, is that they have a limitation that the key for a record is a 4-byte string, or an OS type, actually. It's a 32-bit integer.
We borrow something innovated by AppleScript, which is to say you can have a list of items in a record under the key KeyASUserRecordFields, and this will be the string, and then a descriptor, and then a string, and then a descriptor. This is how you would build up a complex record in AppleScript or in the Apple Event Manager. When the Apple Event Manager sees one of these special keys, it knows that it wants to build a structure.
It knows that it wants to build a structure with a complex name, a long string name, and then some value. The value is going to be either a scalar type or a compound type. This is how you would do that. You create the list that this... The application is a simple document. You can write a code to it.
There's an alternative, which is that AppleScript basically got support for all of this for free by the addition of a simple dictionary that adds the call soap and call XML RPC methods. This is a great way to prototype and debug web services, because the Apple Event Manager sits below AppleScript, and AppleScript just builds complex Apple events like a duck in water.
It's really easy to use AppleScript to both prototype and to embed web services inside your application. There's a tech note that I'll mention at the end that can show you how to add AppleScript to your application as well. At this time, I'm going to ask Tim Bumgarner to come up and demo AppleScript Studio, which uses Apple Events to access web services.
Sound? Sound? There we go. Okay, great. Okay. First thing we need to do in our demo is actually discover what type of service we want to use. And I've got an application here called X Methods Service Finder. And this employs the services from the X Methods website to actually display all the different publishers, the service names, and a short description of all the services that are available. And I've got a nice little search area up here.
I can actually find maybe all the publishers that begins with X Methods. I'll type this and it quickly just lists the ones that are from X Methods. Let's do something a little more interesting. Let's see if we can find anything that has to do with stock. So if I, maybe I wanted a web service that would be, pull out the current value of a stock, I could use that.
For our demo actually, let's see if we can find anything about Dilbert. And actually there is one, Daily Dilbert. And it looks like it says it returns a binary stream of today's Dilbert comics. And actually what it returns is a URL to an image. So let's go ahead and build a web service built on this particular service. So I'm going to go into Project Builder.
And we're going to start right at the beginning. We're going to do this right from scratch. So I'm going to choose New Project. And in this case, I'm going to choose the AppleScript application template. And we're going to go ahead and call this Daily Dilbert. All right, click Finish.
Now I've got my project open here. And it's already given me basically a blank script to start with and pretty much just a start on our resources. If it will open-- there we go. Double-click that. We're going to go into Interface Builder. First thing we're going to do is go ahead and put together our interface. And in this case, it's going to be a fairly trivial application. We'll just make this a little smaller. I'm going to bring up the attributes. First thing I want to do is go ahead and change the title to Daily Dilbert of my window.
Since what we're going to be doing is getting an image and putting it and loading it in this view, we'll need an image view. There's one right here. Drag it over. And we'll change some of the attributes of that. We'll make it so there's no border. I can use the Aqua guidelines to make sure I get it snapped right up to the edge.
A couple other things is that we're going to automatically resize the image, this window, based on what the image that we get from the service. And so I want to just make sure that this particular view stretches. So for the most part, the UI is done. It's very simple. Now I actually want to add some AppleScript functionality. And one of the things we have to do is to name our objects so that we can refer to them by name in our scripts instead of by index. So I'm going to go to my AppleScript panel.
Anytime I want to do anything with AppleScript in Interface Builder, I go to this panel. And I'm going to name my window. Go ahead and we'll call it Dilbert. And then I also want to name my image view. And I know that I've got the image view because when I click on it, there's an NSImageView title here. And I'm going to also call this one Dilbert. Now what I want to do is I want to actually execute some AppleScript. So when this window gets loaded, or in particular this view gets loaded from the nib, I want to trigger an AppleScript.
And so there is a nib class here. And for those of you that are Cocoa programmers, this will look very familiar, awake from nib. So you can attach to any object and find out when it's been loaded. And we're going to assign it to this. One other thing is that I don't want the window to be initially visible.
So let's turn off its visibility. And then the other thing we need to do is we want to know when the app is finished launching so that we can then present the window. So again, I go back to my AppleScript. And in this case, there is a launched.
Event. And let's go ahead and then click on the edit script. Now what this does is it goes back into Project Builder, loads my script, and it determines that there weren't any handlers with those names. And so it automatically goes and adds those handlers for me. So let's go ahead, and I've got a little bit of a demo assistant here. If it's working correctly, it's going to enter the script so you don't have to watch me painfully type this. Basically, what we do is the parameter to this web service is a date. And it has to be in the format month.
So it's going to use as digits/day/year. And ironically enough, I found it was actually easier to use the shell to call date to get it in that particular format because AppleScript doesn't make it easy to get it in this specific format. You can get it -- the month comes back as the actual string of January or February. In this case, that wouldn't work. So I just found that we actually have this functionality built into AppleScript called do shell script.
And I just jump out and call the shell command date passing it the parameter, and voila, it works. So let's go ahead and continue on. Then the next thing I do is I want to get the image as this image view is being loaded. And so there's a handler here, get Dilbert image for date.
And we're going to add that in just a bit. Now continue on. And then what I do is once I've loaded the image, I go ahead and set the image of that image view. And the thing that's being awoken in essence is the image view. The object will contain that image view.
All right, so let's go down and add the rest of our handlers here. Oh, we've got one more thing here. Next thing I also want to do is once I load the image, I want to adjust the size of the window based on the size of the image itself. So I simply call size of the window.
I set its size. This is actually doing another interesting thing. It happens that at this point in version Studio 1.1, the size of an image can't be determined directly from AppleScript. This will be fixed. But I can actually call Objective-C. And this is another Studio enhancement such that call method is calling the Objective-C method called size on the object, the image.
Without any code, I can just jump off and call into Objective-C. So if Studio hasn't provided some functionality for you, we've sort of put a backdoor in with the call method. So let's go on down here and we'll see if we can put in the rest of it. Nope, and I forgot to show it. And then at the very end, we want to show that window.
And then I'm going to go through this, the getDilbertImage. So it's setting it to some known value to begin with. And then we're going to call another handler called loadImageAtUrl. And this is going to call yet another handler calling the actual web service getDailyDilbert for image at the path. And we'll finish this.
And then here's the loadImage. And I'll walk through this one here in a second. Basically, it does another call method. I cheated here again. Given the URL, there's actually a Cocoa-- I'm a Cocoa engineer. There is a-- and a string class, and there actually has one-- A category point on it, so I can actually get the last path component of that URL very simply.
So I jump out, and with call method, I pass this particular method name on the URL, and it gives me the last part of it, because that's what I'm going to use as the part of the name. And basically, we're going to stick this image that we load in slash temp, so the next time we reboot, we don't have to worry about getting rid of it. And then again, we're going to employ do shell script, because we can use the curl tool to pass it that URL, and it's going to return it to and save it for me on my disk.
And then when I'm done, I will use the load image command that's in studio to load that image and set it into that, or to pass it back in our array. All right. Then the next thing we need to read is the most interesting one as far as the web services is concerned. And this is called Daily Dilbert Image Path.
And what it does is it simply uses that URL that Steve talked about. This is the endpoint. And just like we talked to a local application, by tell application finder, we can simply talk to the web services tell application this particular URL. And then we give it the method name. And it needs also a SOAP action in this case, and the namespace for that. And the parameters we're actually passing in right here in the end parameters, and they get sort of put together. And then we ultimately call SOAP.
And this is going to do what Steve talked about. It's going to take all this data that we pass, which is really just an AppleScript record. You'll see this is an AppleScript record. Takes that, pulls it into, or takes it and converts it into XML, sends it over the wire, waits for the response.
It comes back as an XML data, and then he parses it and then gives it back to us in AppleScript so that we can use it. And that will be our image. And let's see, I think we've got everything that we need. and let's go ahead and save and run this. See how it works.
builds, compiles. There you go. So it's went off, loaded that data, loaded our image, and it looks like that's our today's daily image. And Steve, pick it back up. Oh, by the way, I forgot to tell you. It just happens to be that this application itself is a studio application. The app that I use to find the services is a studio application. And here's the code for it, if I can open it up. It's actually going to talk to mail.
And close all the windows. And here is the service detail. So here, I put this together last night. And here's the script for that. So just a little bit of script here. That whole application was written in a couple hours to actually do the services. Again, employing web services to get all the data that we needed. All right, thanks, Steve. Thank you, Tim.
So I guess the point to get out of that is that AppleScript and Apple Events, empowered with web services, really give you a way of getting to web services very quickly, and at least, if nothing else, playing with them. Okay, so what do we have for you in Jaguar? We've decided to ship something called Web Services Core. Now, what was wrong with the Apple Event Manager way of doing things? Nothing.
The Apple Event Manager way of doing things is fine, but it's at a little too high a level in the protocol stack, in the library chain of our system. So in this slide, we see that App Services has the Apple Event Manager sitting as a little bubble in it.
And then what we've done is implemented WS Core inside of Core Services. Now, this is a lower-level framework. It sits alongside of CF Network, Core Foundation, and Carbon Core. And it gives you access to the... basic runtime model for our system. It's available to all applications, plugins, daemons, tools. It doesn't have any dependency on the Windows Server or login window. You don't have to be a logged-in user. You could use it from a CGI application.
It's integrated with the system. It sits inside of core services and it leverages CFXML parser and CF network. It's thread safe, run loop safe, and friendly. It encourages you to asynchronously issue invocation requests on the run loop and receive a reply on your run loop. It's CF type based, so you have to create CF type objects for your strings and integers and records, dictionaries, and CFArrays. But if you're an Objective-C programmer, you get toll-free bridging with the Objective-C types. It's also a simple procedural API, so there's no need to have a lot of objects involved for this API. There's actually probably six calls in the API and a single object or type ref.
[Transcript missing]
So, like I said, you create one of these things using the method WS_MethodInvocationCreate. It's a CFURL or an NSURL. A method name is a CFString, and the protocol is one of these CFString constants that are in the header. The header, by the way, on the Jaguar CD is WS_MethodInvocation.h.
[Transcript missing]
So this is how you would build the dictionary and parameter order array. You call CFDictionary add value on a mutable dictionary that you've created. You've got two parameters. Param one is Steve, param two is John. You add the parameter names to the parameter name array, and then you just set the parameters onto the ref.
So, then you invoke it. And you do that with a single call, WS_MethodInvocationInvoke. The result of this call is a CFDictionary. Now, that's not the actual method result. That's a dictionary containing the actual method result, as well as optional debugging information, including the outgoing XML and the returned XML and the HTTP headers or HTTP errors, and fault information so that if there was a networking transport error, that information is going to be in there and available as keys in that dictionary as well.
So, basically, you make this invocation call, and then if you can call this method WS_MethodResultIsFault, passing up that result dictionary, then you can pull out the fault string out of the dictionary and display it to the user or do some other work, whatever you want to do. Otherwise, if it's not a fault, you look up the KWS_MethodInvocationResult.
The result of this is a CF type ref, and depending on the service you're calling, it's going to be some sort of value that's expressed in CF type lingo. So, in the example we saw earlier of XMLRPC, the result of this would be a CFString. A more complex type like the XMethods inspector that Tim showed, the result is a dictionary containing arrays of dictionaries containing arrays of dictionaries. And so you have to know upfront what the type is. Of course, you can't do a full transaction to decide what the type ID is and do something based on that.
You can also execute these asynchronously. You set on the invocation a client context. This is similar to how CF Stream works. In the old world, we used to set refcons. Nowadays, we set client context. This includes the info pointer that you want to pass to your callback, as well as some callbacks for the info pointer to allow it to be reference counted. If you're familiar with the CF API, you can see how this works.
Once you set the callback, you can schedule this invocation on one or more run loops, and as those run loops execute, the invocation will pass through its state machine, ultimately resulting in getting the data or getting a fault. Then it will call your callback during that run loop invocation, and you can process the result. We're going to do a demo now. If I could go to demo four.
We're on demo four. All right. Here we go. Google API in shiny metal. I did the demo last night, so I had the opportunity to check that checkbox and make this thing demo, make it metal. So, I'm gonna show you first what it does. If you haven't heard, Google released an API for their web service, for their search engine.
And this is relevant because if they don't change the API, which they shouldn't because APIs are supposed to be immutable, 20 years from now, I won't have to try and figure out how to scrape their web page to get their search results. I can just call this API and get the same information back. So we search for Google API, hit return, and it goes out, contacts Google through WS Core and fetches the results.
Anyway, so the result from the Google API is that the search engine is now working. So, I'm gonna show you what it does. So, I'm gonna show you what it does. So, I'm gonna show you what it does. So, I'm gonna show you what it does. So, I'm gonna show you what it does. So, I'm gonna show you what it does. So, I'm gonna show you what it does. So, I'm gonna show you what it does. So, I'm gonna show you what it does. So, I'm gonna show you what it does. So, I'm gonna show you what it does.
So, I'm gonna show you First thing we do is we create an invocation. Well, actually the first thing I guess we did was we created a URL that specified the endpoint that we wanted to send our request to, in this case, http://google.com/search/beta2. When you go to Google and you look at their API, they give you a developer kit, and it's got all the information about what the methods are available and what the APIs are, what the endpoints are, and sort of all the meta information you need in order to send the request.
So we create the URL, we create the invocation with the URL, the name of the method, and the protocol. We're specifying as SOAP 1999. It's probably not the best name, but that specifies SOAP 1.1. Then we're going to set the parameters. The Google search takes 10 parameters. They're all required in their API or in their implementation of the API, but that is something that, it's really up to them to own that.
Probably the least relevant thing that's required is the key. When you sign up for their developer program, they give you a key. The key is like a 40-digit long number, alphanumeric string. I keep it in a dot file in my home directory so that all my tools can use it.
We're going to do two things. We're going to build up an array of strings and an array of values. There's a one-to-one correspondence between the key in the string table and the value in the value table. In this case, we've got the keys, get my secret key, and the key key from my dot file. Q is the query, the F query string. This was set when you hit the search button. Magic Cocoa things happened.
I have to create an NSNumber instead of just passing the number 0 or 10 in here. There's no automatic Cocoa or Objective-C coercion from a scalar to an NSNumber. I create the number with the integers 0 and 10. There are additional parameters, which are booleans and strings that tell us what the number is.
I'm going to use the integer 0 and 10. I'm going to use the integer 0 and 10. I'm going to use the integer 0 and 10. I'm going to use the integer 0 and 10. I'm going to use the tell Google what kind of search I want to do, or whether to restrict the Google search to a particular language.
I create an array, which is the parameter order from the array that I tonsed up up front, and then a parameter values. And I have a parameter, which is a
[Transcript missing]
with, again, the string that was given to us by the Google API documentation. And then you invoke it.
So the result of the invocation is a result dictionary. So we block at this point, send the message, get the result, and then we process it in here. If the reply is a fault, then we're just going to go ahead and say an error occurred. Otherwise, we delve into the dictionary.
and we look up the magic key KWS method invocation result. This contains the actual result of the SOAP invocation, not the meta information. Google, of course, well, not of course, but Google decided to add an extra level of an indirection to that. So we then, we know the result of that invocation was a dictionary, and then we have to look up the key return, which gives us another dictionary, and then the key result elements. which is an array that lives inside that dictionary. From there, we just go off into the rest of our Cocoa class and process the results. Now, one interesting thing is So when we ran this API, AppleScript, When we ran this demo, my little progress bar didn't spin.
Why didn't it? I don't believe that. A little progress where I didn't spin because this application blocked in order to get the results. So I want to go ahead and modify it real quick. and David Levy are also represented in this session. I'm going to copy the code that sets the context to my Cocoa object and sets the callback to be a little stub that calls a method on my Cocoa object.
Then WS method invocation schedule with run loop, giving it the current run loop. And then I'm going to return from my function. So this is the function that gets hit when you call doSearch.
[Transcript missing]
Close our function, and then we need another function which gets called when the callback completes.
[Transcript missing]
There are a couple of customizations you can add to an invocation. You can override how it serializes CF types, and you do this based on the CF type IDs. So if a CFDictionary comes along that you need special control over serializing, you can say, I want to customize CFDictionary serialization, and insert your own code at that point, which will get called to write out the XML. And of course, if you return null, then the default serializer will take over.
If there's a part of an XML tree that isn't being parsed properly or to your satisfaction, you can get control of the parser at that point and replace your own CF type with what you think should be represented. And you can access the SOAP headers and put your own SOAP extensions in, or if there is a SOAP extension that you need support for that we don't support, because we don't support any in 1.0, you can add your own SOAP headers, which are XML. basically into the into the soap header that gets sent.
[Transcript missing]
So, one more demo. Back to the demo machine. And if this works, whoa. Let's get rid of all these. So I've got a new project. I'm not going to copy and paste. I'm just going to hope it works. I probably should have run it beforehand. But I'm going to show you I have, in a PB project, a new project.
An invocation of the WS Make Stubs tool. It's probably too small to read, but it takes -x, Objective-C is the language that I want emitted, and then some parameters that specify the output directory, the name of the file that I want to create, and in this case, the URL that Google supplies with their WSDL information. And I'm going to go ahead and run it or compile it while I'm actually looking at the source.
[Transcript missing]
like this. For each different method or endpoint that's available, it creates an Objective-C class which inherits from a master class that implements some of the underlying WS core behavior. DoSpellingSuggestion is one of the Google API's. Just like the other ones, it's got the key parameter and then the phrase that we want to spell check. And then the one that we were calling before, doGoogleSearch. So in order to call this API, I changed my implementation.
[Transcript missing]
and then call the set parameters method on it, giving it all the same values, but this time it's statically bound, statically typed to the Objective-C runtime. I set the callback based on the The API of the generated stubs gives you a set callback method and a schedule on run loop method.
It looks exactly the same as the other code, it's just I didn't have to do all the method namespace URI, SOAP action, and naming of parameters. That was all done by the generated stubs. Then when we ran it, It was running. It is running. So it's exactly the same thing, but the complexity of calling the API is abstracted by the generated stubs.
The source to that will be available for demo. Where are we going in the future with this API? We're going to have some SOAP extensions coming in the future. As these become formalized by the industry at large, we're going to adopt them and produce APIs to allow them to bind into WS Core. This is the core stuff. This is the stuff that we're going to build our web services architectures on.
We will have a WSDL API in the future, and better WSDL integration with CF types and CF schemas. People have ideas on how they would like to see that implemented. By all means, get in contact with us and let's work together on that. There's been some call for a UDDI API. UDDI is an acronym that I'm not even going to try and remember. But it's for locating services on the network.
It's for saying, "I'm interested in services that give me cartoons," and coming back with a list of WSDL files that specify different cartoons that you can get. It's a programmatic interface for discovery of services. A server-side API may be part of WS Core, but today, WebObjects provides a server-side web services API that's very well integrated with the WebObjects environment. Thank you.
you want to talk about the RoadMap or other sessions. Or I'll talk about them. Okay. So some other sessions that you might want to go to. CfNetwork that WS Core is built on is a very exciting framework that we're putting a lot of investment in and all the other sort of IAP and web projects that you see us doing at Apple are going to be built on CfNetwork.
XML and WebObjects is going to talk about accessing web services from WebObjects and how to integrate XML into WebObjects applications. Same with Java Web Services. Managing I/O, CFRunLoop and CfStream, if you're a low level person and you want to understand how CfNetwork works, how Web Services Core works, that's a good session to talk, to go to as well.
More Web Objects and Web Services. And then the AppleScript Studio intro. There will be a lot of good information there about how to use AppleScript to access web services.
[Transcript missing]
On the Jaguar CD, in Developer Examples Web Services, there's an XMethods Inspector app built using WSMakeStubs. It's not as nicely polished as the one Tim showed, but at least the source is there and it's easy to understand. You can find out about XMLRPC at the website of the developer, xmlrpc.com. He's got links to implementations as well as services that are available.
SOAP is a W3C thing, so that's a URL that you use to access the software. the SOAP specification. Same with WSDL and UDDI. And there's a QA, Tech Note 1111, which is how to add OSA or AppleScript to your application. So if you want to take advantage of AppleScript today, and web services in a shipping application, that would be a good place to start. There are also tech notes available on the developer public site on accessing web services through SOAP and XMLRPC. Some really good documentation is already available.