Before we move on lets get two things out of the way:
- Make sure you have AWS installed on your system
- Git clone the article code from here
If you're having trouble getting AWS up and running, you could take a look at an article I wrote a while ago about Ada Programming on Slackware. Even if you're not using Slackware there might be some tricks in there that also apply to your favorite distro. If you're using Windows I really can't help you, as I know very little about getting Ada and AWS up and running on that line of operating systems.
What is most important though, is that you grab the latest AWS from the Git repository:
At the time of writing the latest commit in the repository was ffc79ac63f06e44100bc69de59eb4ed9b76c41ae (Date: Tue Feb 5 18:48:37 2013 +0100), so assume that you at least need an AWS that is as new as that.
From now on I'm going to assume that you've got a sufficiently new AWS working and the tutorial code cloned from my Github repository, so lets get rocking with some AWS magic.
We start by building and trying the tutorial program you cloned earlier, so we know what we're getting into:
Grab your browser and do as instructed; go to localhost:8080 and see what you get. Nice eh'? A sexy 404 message hosted by your very own Ada powered webserver. Whooooosh! If you don't like the 404, try visiting localhost:8080/helloworld for something else. When you're done being amazed click q to kill the server.
So how did this magic come to life? We zoom to the main program file
aws_tutorial.adbfor some enlightenment:
Simplicity at work eh'? Lets stroll through the code together.
witha bunch of packages:
Ada.Text_IOis for text input/output, and that is exactly what we're using it for at line 12 where we output the port and kill instructions. After that we add three AWS packages, of which the first two are dealing with the configuration of the AWS HTTP server, specifically the default settings and loading of any external configuration files. The call to
AWS.Config.Get_Currentat line 19 searches for the files
progname.ini(in our case aws_tutorial.ini) in the same location as the executable, and if any of these are found the values set here are used to configure the
Web_Serverobject that is started at line 17 by the
AWS.Server.Startcall. If you take a peek at the
exe/aws.inifile you'll see that the only value we're setting is
Reuse_Address True. What this does is allow us to start and stop the server without having to wait for the system to release the socket. The rest of the configuration is inherited from the
We'll ignore the call to
Handlers.Get_Dispatcherfor now and move further down to line 21 where we're abruptly stopped by the
AWS.Server.Wait (AWS.Server.Q_Key_Pressed)call. What is this weird contraption? Well a server needs some sort of "loop" to prevent it from terminating, and this is exactly one such loop, except it isn't really a loop. What
Waitdoes is hang until some specific event occurs, in our case it is waiting for someone to click the
qkey. As soon as
Waitregisters some action on the
qkey it returns and the program moves on to the final statement; the
AWS.Server.Shutdown (Web_Server)call. I'm guessing that it is evident what this does. It cleanly shuts down the server and when it is done, the program exits.
And that is really all that is required to add HTTP(s) support to your Ada program.
But wait, how do we generate the content? Ahh, yes now we'll take a closer look at the
Handlers.Get_Dispatchercall at line 18. What is this dispatcher thing we're getting? It's simple really. In order for the server to know what to do with all the requests coming in, we need to define some handlers. This is done in the homegrown
Handlers.Get_Dispatcherfunction that lives a groovy life in the
Handlerspackage found in the
src/handlers.ad[sb]files. Lets take a peek at the specification file first:
Not much happening here. We define the
Get_Dispatcherfunction which return a
AWS.Services.Dispatchers.URI.Handler. The name of the returned type should give away that we're dispatching HTTP request based on the URI of the requested resource. There are a bunch of other dispatchers available in AWS, but for now we'll stick to the basic URI stuff.
The body is a bit more interesting:
The two packages we
withcontains the code that generates our content. We need them here because this is the place where we register the resource handlers.
We declare the
Dispatcherobject as an
URI.Handlerat line 13 and then we proceed with registering two handlers: A default handler at line 15 and a specific
/helloworldhandler at line 20. Finally we return the
The default handler is the
Not_Found.Callbackfunction, which means that whenever a resource is requested that doesn't specifically match a registered URI, the
Not_Found.Callbackfunction is called. On the other hand if the
/helloworldresource is requested, the
Hello_World.Callbackfunction is called.
This is how dispatching in AWS works. But it is not the only way. It is also possible to manually dispatch based on the string URL of a request, but that is very clumsy and ugly. You really should use the dispatcher model if you're working with AWS as it offers both convenience and some nice tools to build and maintain your resource->handler structure.
Moving on lets take a peek at the
Not_Foundpackage where we handle the 404's:
Here we see the
Callbackfunction that we registered in the
Handlers.Get_Dispatcherfunction. And that is really all we make available to the world in the specification of this package. Lets check out the body:
Ahh, this is far more interesting. Starting with the
Callbackfunction we see that all it does is return an
AWS.Dispatchers.Callback.Handler. This is done using the
Createfunction which takes an
AWS.Response.Callbackas its single parameter. The signature of the
And that is exactly the signature of the
Generate_Contentfunction. It's marvelous how these things just come together like hand in glove. In
Generate_Contentwe build the response sent to clients requesting unknown resources. This is all done in the
AWS.Response.Buildcall. We define the
Content_Typeas text/html, we generate the actual content and finally we set the
Pay special attention to line 32 where we grab the requested URI from the
Requestobject. There's a lot of interesting data in this object. Take a peek at the
AWS.Statuspackage for more on how to entice this object to give up its secrets.
For the sake of completeness lets also take a peek at the
As you can see this is very similar to
Not_Found, which is only natural since both packages do nearly the same thing: Deliver some very simple HTML. Note that we grab the user agent from the
Requestobject instead of the URI we used in the
And that is it. I hope that by now it is clear that adding HTTP support to your Ada program is very easy. Of course there's a lot more that can be done with AWS, and I will deal with that in coming articles. For example building the content using strings is rather lame, so in the next article I will turn my attention to using the AWS templating system for the content (Templates_Parser).
Oh and on a final note let me just mention the GPR file for this tutorial program, especially the very first line that says
with "aws";. Yes, that is all you need to add to your project file for
gnatmaketo know that you want it to pull in AWS when compiling your project. It's wonderfully simple. Enjoy!