hello web from ada

I decided to mess around with some Ada.  This is an old school compiled language, that is popular with the Department of Defense and almost nobody else.  Except me.  Mainly because I like the name.  It’s pretty.

So here’s what you do:

1) Download the GPL version of GNAT from AdaCore.  Make sure you grab AWS also.

2) If you are using Windows, you will need to have a Unix shell prompt available to you.  You can get this using Cygwin or MINGW.

3) Install GNAT.

4) Unzip the AWS source code.  In a moment, we will build this library.  For some reason, on my machine, it didn’t auto-detect the install directory of GNAT properly, so first edit makefile.conf and update the prefix line to point to that directory you installed GNAT into.

5) Run “make setup build install” to install AWS libraries so your projects can find them. 

6) Go into the templates_parser subdirectory and edit makefile.setup to change your installation directory and run “make install”. 

There is no standard way to install libraries so you have to actually read the README and INSTALL files.

7) Use GPS (which comes with GNAT) or install GNATBench (Eclipse plugin) to set up a new Ada project.  Declare the main source file to be “Server.adb”.

8) Create “Server.adb”:

Server.adb:

with GNAT.IO; use GNAT.IO;
with AWS.Default;
with AWS.Server;
with ServerCallback;

procedure Server is
WS : AWS.Server.HTTP;
begin
AWS.Server.Start (WS, "Hello World",
Max_Connection => 1,
Callback => ServerCallback.Echo'Access);
AWS.Server.Wait (AWS.Server.Q_Key_Pressed);
AWS.Server.Shutdown (WS);
end Server;

This sets up a new web server and declares that the method Echo in the file ServerCallback.adb will handle our HTTP requests.  The .EXE will run until you hit the Q key.  It will listen, by default, on port 8080.

9) Define the server callback files “ServerCallback.adb” and “ServerCallback.ads”.

ServerCallback.adb:

with Templates_Parser; use Templates_Parser;
with Templates_Parser.Utils; use Templates_Parser.Utils;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;

package body ServerCallback is
function Echo (Request : AWS.Status.Data) return AWS.Response.Data is
pragma Unreferenced (Request);
URI : constant String := AWS.Status.URI (Request);
Params : constant Translate_Table := (1 => Assoc("URI", URI));
Response : Unbounded_String;
begin
Response := Parse (Utils.Get_Program_Directory & ".." & Directory_Separator& "site.thtml", Params);
return AWS.Response.Build ("text/html", Response);
end Echo;
end ServerCallback;

ServerCallback.ads:

with AWS.Response;
with AWS.Status;

package ServerCallback is
function Echo (Request : AWS.Status.Data) return AWS.Response.Data;
end ServerCallback;

This loads a template file called site.thtml and passes in a parameter URI which gets resolves to the request URI.  The parameters are passed to the template_parser using TranslateTable or TranslateSet (I used TranslateTable because I knew in advance how many parameters I would have.)

The actual template itself I put in the root folder of the project (“..” from the obj_debug folder that server.exe gets deposited in.)  It’s basically html with tag declarations that the template_parser replaces with the parameters you supplied above.

site.thtml:

<html>
<body>
Hello from @_URI_@.
</body>
</html>

Now you can hit http://localhost:8080/whatever and you should see the response echo the URI you provided.

You might be wondering how the same program would look in Ruby. Well, like this (assuming you have Ruby and the Sintra gem installed):

require 'rubygems'
require 'sinatra'

get '*' do
"Hello from #{params[:splat]}"
end

But that’s nowhere near as fun.

(Of course, Ada isn’t really a language intended for web programming.  And I don’t think I would feel comfortable in an airplane where the fly-by-wire controls were powered by the Ruby VM and the software cobbled together by splicing together features from a half dozen open source gems.)