<Getting Started Tutorial>

[ Basics | Intermediate | Advanced ]


<bigwig> is a high-level programming language for developing interactive Web services. Complete specifications are compiled into a conglomerate of lower-level standard technologies such as CGI-scripts, HTML, JavaScript, and HTTP Authentication.

The aim of <bigwig> is to allow simple and inexpensive construction of advanced Web services. We are only concerned with specifying the behavior of the service; the graphical layout of the pages is left to other tools.

<bigwig> is committed to run on the lowest common denominator of the Web, that is, no special software is required for the browser or the server. Consequently, our services are CGI-based, use plain HTML for communication, and exploit only the subset of JavaScript that is common to the standard browsers.

The <bigwig> language is really a collection of individual domain-specific languages focusing on different aspects of interactive Web services. To minimize the syntactic burdens, these contributing languages are held together by a C-like skeleton language. Thus, <bigwig> has the look and feel of C-programs with special data- and control-structures.

This tutorial will introduce the underlying runtime model, which in a sense constitutes the conceptual foundation of <bigwig>. This model builds upon a session concept, which allows sequential sessions with multiple interactions with the browser to be specified in ordinary programming notation.


Basics


Service structure

service {
  session S() {
    /* no statements */
  }
}

A <bigwig> program (a.k.a. service) starts with the keyword service, followed by the service specification enclosed in "{ ... }" braces. Sessions are the entry points to the service, much like the main routine in a C or Java program. However, unlike a C or Java program, a <bigwig> program may have more than one session. All sessions have associated URLs that when referenced (by a browser) cause an instance of the session to run, executing the code specified within the session's brackets. This service has one session named "S" with no statements in its body. When referenced, an instance of this session will immediately ``falls off the end'' of the code, produces a default termination message onto the client's browser, and terminate.


Shortest Hello World

service {
  session Hello() {
    exit <html>Hello World!</html>;
  }
}

This service has one session named "Hello" that when run executes a single exit statement, that sends an html document containing the text "Hello World!" onto the client's browser and terminates. A session thread is invoked by a client issuing a "GET" or "POST" CGI request using the URL mentioned in the getting started compiler page.


Local declarations

service {
  session Add1() {
    int n; // int's are pr. default initially zero

    /* n has the value 0 */
    n++;
    /* n has the value 1 */
    exit (html) n;
  }
}

The session Add1 has a (local) variable integer called n. By local (as opposed to shared) we mean that a session thread will (at runtime) have its own local (or private) variable accessible and visible to this session thread only. Variables in <bigwig> are automatically initialized (integers are initially zero). See the Initial Values section in the reference manual for more information. The first statement in this example increases the variable to the value one and the second (and last) statement exits this value onto the clients browser. Here, the information is exited by casting the value held in the variable n to an html expression. We shall see in the dynamic document tutorial how to present information to the client in a much nicer way. But to avoid getting into these details in this part of the tutorial, we shall for now present all information to the client in this way.


Shared declarations

service {
  session Counter() {
    shared int n;

    /* n has some value */
    n++;
    /* n has a higher value */
    exit (html) n;
  }
}

This service is reminiscent of the previous one but with one important difference. The variable n declared in this example is prefixed with the type modifier shared. Shared variables are shared among all session threads. Thus, when one session thread updates it, subsequent reads in other sessions will get this latest written value. All <bigwig> services have their own (internal) database where shared variables are stored. (We are currently looking into integrating external databases).


Two independent sessions

service {
  session Counter() {
    shared int n;

    n++;
    exit (html) n;
  }

  session Hello() {
    exit <html>Hello World!</html>;
  }
}

This service has not one but two sessions, Counter and Hello. These two sessions are completely unrelated and could as well have been two entirely different services. Sessions are different starting points or ways of interacting with a service. A <bigwig> service can have any number of sessions. Typically a service has one or more sessions for the users and one for the administrators.


Two collaborating sessions

service {
  shared int n;

  session Counter() {
    n++;
    exit (html) n;
  }

  session Reset() {
    n = 0;
    exit <html>Reset!</html>;
  }
}

This service also has two sessions. These two sessions, however, are clearly related. They both manipulate the same shared integer variable n. The session Counter increases it by one and displays its value when run while the session Reset not surprisingly resets its value to zero when run. One can say that the two sessions communicate through the shared variable.


Two-pass scope rules

service {
  session Counter() {
    n++;
    exit (html) n;
  }

  shared int n;
}

The scoping rules in <bigwig> are two-pass meaning that variables are available at the same scope level even before the lexical point at which they were declared. However, the scope rules for variables declared in compound statements are one-pass (as in C and Java).


Show (local state preserved)

service {
  session Show42() {
    int n = 42;
    show (html) n; 
    /* execution continues here after show
       with the entire local state as it was
       (`n' has the value 42) */
    exit (html) n;
  }
}

Instead of exiting a document to the client, one can instead show a document to the client. The semantics is that the page will be shown to the client (in the browser) and execution will resume (with the local state preserved) after the show statement when the client submits the page. If the show document does not contain a "submit" button (as is the case with the document here), a default continue submit button will automatically be provided. When execution resumes after the show statement in the example, n will (still) have the value 42. Thus, the document exited in the final statement of the session will contain "42". This show construct plays a central role in the session concept, providing a means for interaction with the client.


Show/Receive (interaction)

service {
  session Interact() {
    int n;
    html Input = <html>
      Enter a number: 
      <input type="text" name="number">
    </html>;

    show Input receive [n = number];
    /* Client's number is assigned to 'n'. */
    exit (html) n;
  }
}

The statement show-receive is fundamental in <bigwig> and provides the client-service interaction. The general pattern of a <bigwig> service (in fact, any interactive Web service) is to show a document to the client, receive some input, do something, show a reply page, receive some more data, do something, and so on). The service in this example will show a document prompting the client for a number which is received into a local variable n upon page submission. Hereafter, this entered value is exited onto the client's browser.


Session calls

service {
  shared int yes, no;

  html VoteDoc = <html>
    Do you think P=NP?
    Yes
    <input type="radio" name="answer" value="true">
    / No
    <input type="radio" name="answer" value="false">
  </html>;

  session Status() {
    exit (html) ("yes: " + yes + ", no: " + no);
  }

  session Vote() {
    bool answer;

    show VoteDoc receive [answer = answer];
    if (answer) yes++;
    else no++;
    Status(); // Call session `Status'
  }
}

This vote service has two sessions Status and Vote, the second of which ends with a call to the first. The Status session can thus either be `run' initiated by a request to it on its own or through the Vote session.


Session arguments

service {
  int fac(int n) {
    if (n==0) return 1;
    else return n * fac(n-1);
  }

  session Factorial(int n) { // Session argument.
    if (n<0) exit <html>Negative number!</html>;
    exit (html) fac(n);
  }
}

As previously mentioned, a session is invoked through a CGI "GET" or "POST" request. A session can parameterized to take (CGI) arguments as in the example above. The argument names are explicit. If `http://url_to_session' designates the url to start this session, then `http://url_to_session&n=7' starts this session with argument n equal to 7. If argument n is missing it is assumed to have the initial value (which is zero for integers).


Interacting with other services (get/post)

service {
  session TalkToGoogle() {
    string s;

    s = post("http://www.google.com/")[q = "bigwig"];
    exit (html) s;
  }
}

For interaction with other services (<bigwig> or non-<bigwig> services), <bigwig> provides the functions get and post. They make a CGI request using respectively the "GET" and "POST" request method, to the URL specified in parentheses and with the list of arguments enclosed in square brackets. This example will make a "POST" request to "www.google.com" with argument "q" (query string) equal to "bigwig" and assign the result to the string variable s. Finally, the service will exit this string (cast to an html document) onto the client's browser. As one can see, it is easy to construct ``services talking to services''.


Security

ssl service { // All communication is encrypted.
  session S() {
    ...;
  }
}

A default <bigwig> service executes at a standard security level with protection against the most naive attacks. Tighter security levels of operation can be specified in <bigwig> by prepending the service or session keywords with the security modifier ssl. This modifier will cause all communication between the client and the server to be subject to the SSL cryptographic protocol. However, it is required that the web server supports SSL. Check out the security reference manual page for other security modifiers.


Directory structure and garbage collection

service {
  session S() {
    file f;
    string filename = "foo.html";
    html H = ...;

    s = (string) H;
    f = open(dir + filename, "w");
    print(f, s);
    close(f);
    /* URL to the file: `url + filename'. */
    ...;
  }
}

When the session is started, it will have the BASEDIR appended with the service's name as its "current-directory". All files are opened relative to this directory. Each session thread is when started assigned a unique private directory that is automatically garbage collected when the session thread expires. The lifespan of a session (SPANDEFAULT) is set (in seconds) in the <bigwig> configuration file ".bigwig" (default is 48 hrs). This value can also be overridden at service, session, or individual show-level throgh the span modifier. This directory can be used to creates files of temporary nature that are automatically deleted when the session thread is expired. The expression, dir, designates a string file-system path to this directory (the expression, url, also designates this directory but as a URL).


Intermediate


Show/Receive/Timeout: (timeout clean-up)

service {
  shared bool locked; // initial value "false".

  session ExclusiveAccess() {
    string s;
    html H = ...;

    if (locked) exit (html) "Sorry, session in use!";
    locked = true;
    ...; 
    show H receive [s = blah] timeout locked = false;
    ...;
    locked = false;
  }
}

A common problem with Web services in general is that a client may for some reason decide to abandon it in the middle of a show statement (that is, not submit the page). In <bigwig>, the session thread process will thus sleep on the server until it expires. When this happens, a timeout-statement can be executed as in the example. The example shows how to ensure that only one session thread is executing a certain region. When the timeout statement finishes, the session thread terminates.

Note however that the above does not guarantee that only one thread is in the region at a time as two sessions may evaluate the condition in the if-statement at precisely the same time. We shall in the concurrency control tutorial see how <bigwig>'s concurrency control language can be used to ensure that such a requirement will never be violated.


Calling external (C-) functions from <bigwig>

---foo.wig---
service { session EscapeToC() { string s; string my(int n); // function prototype ... s = my(87); ... } }
---bar.c---
#include <stdio.h> #include <stdlib.h> #include <strings.h> char *my(int n) { return strdup("test"); }
---shell---
%> gcc -c bar.c %> bigwig bar.o foo %> foo.install

If you specify a function prototype (a function declaration with no body), the <bigwig> compiler will assume that the implementation of the function will be linked with the <bigwig> C output when compiled to binary code.

Note: Make sure only to return (non-NULL) structures that are allocated on the heap as <bigwig> will free (garbage collect) the structure when it is no longer needed. This is currently possible for the following types:

Language Type
<bigwig> bool int float char string file time
corresponding C type int int double char char* FILE* time_t

Another possibility of interacting with non-<bigwig> code is to use the built in system function.


Advanced


Flash (impatience handling)

service {
  session LongComputation() {
    html PleaseWait = <html>
      <h1>Factorizing large numbers</h1>
      This may take a while, please wait...
    </html>;

    flash PleaseWait;
    ...; // Factorize large numbers...
    exit (html) s;
  }
}

The statement flash is available for communicating information to the client when the session thread takes a long time to answer. As previously explained, each session thread is when it is started assigned a unique and private directory. This directory will contain a special file named "index.html" onto which all pages shown to the client by the session will go. If a show-statement is not executed within eight seconds after the client has submitted a request (on start-up or continuing a session), the client is automatically redirected to this page by a "connector" process. This page is automatically overwritten with a default excuse: "reply not ready yet, please wait...". The flash statement simply grants the service the possibility of asynchronously (with the connector) overriding this "index.html" reply file with a more informative excuse. Such an excuse page is always wrapped with some JavaScript causing it to reload every five seconds (the frequency is redefinable: refresh) until the ``real'' answer is produced by the service, overriding this flash'ed page. If the service produces an answer within the eight seconds, the client never sees the flashed page. The technique itself is often referred to as ``client pull''.


bigwig@brics.dk
Last updated: November 2, 2001
Valid HTML 4.01!