6.031 — Software Construction
Spring 2017

WebNorn Specification (Phase 2)

Phase 1

All the requirements of the phase 1 specification still apply to phase 2. If there is any conflict between the phase 1 spec and the phase 2 spec, then the phase 2 spec takes precedence.

Usernames

In an email address username@domain, the username may be a nonempty case-insensitive string of letters, digits, underscores, dashes, periods, and plus signs. So bitdiddle+nospam@mit.edu is a valid email address.

Domain names and list names still follow the same spec as phase 1.

Editing list definitions

For greater usability and consistency with other mailing list systems, named lists should have the following behavior:

Lists that depend on each other can be created in any order. So these two expressions should have the same result:

suite=room1,room2; room1=alice@mit.edu; room2=bob@mit.edu; suite
room1=alice@mit.edu; room2=bob@mit.edu; suite=room1,room2; suite

Undefined lists are empty. If a list name is evaluated without being previously defined, it represents the empty set of recipients, rather than producing an error.

A list can be edited, that is, redefined using its previous definition. For example, room1=alice@mit.edu; room1=room1,eve@mit.edu; room1 should evaluate to the recipients alice@mit.edu,eve@mit.edu. Generally, in a name definition listname=e, any previous definition for listname should be substituted wherever listname occurs in e. If listname has no previous definition, then the empty expression (i.e., no recipients) should be substituted for listname.

Dependent lists should see the edits. The edits to a list should be reflected in other lists that depend on it. For example, room1=alice@mit.edu; room2=bob@mit.edu; suite=room1,room2; room1=eve@mit.edu; suite should evaluate to the recipients eve@mit.edu,bob@mit.edu. Note that this means that for a name definition listname=e, no list names other than listname should be substituted into e until listname is actually used.

Mail loops are not allowed. Mutually-recursive list definitions like a=b;b=a should produce an error with an informative error message. Note that the rules above already prevent mail loops involving a single list, because a=a is not a recursive definition, but instead an edit to list a that makes simply makes no changes to a. But mail loops can arise when multiple lists depend on each other, so the system must detect and prevent those loops.

This example demonstrates editing mailing lists:

These are example outputs, not fully determined outputs. Your system’s output may vary within the bounds of the spec. Examples of variation include whitespace, capitalization, and order.

> fellowship = frodo@shire, sam@shire, merry@shire, pippin@shire
frodo@shire, sam@shire, merry@shire, pippin@shire

> fellowship = fellowship, strider
frodo@shire, sam@shire, merry@shire, pippin@shire

> strider = aragorn@arnor
aragorn@arnor

> fellowship
frodo@shire, sam@shire, merry@shire, pippin@shire, aragorn@arnor

> fellowship = fellowship, gandalf@cosmos, gimli@erebor, legolas@mirkwood, boromir@gondor
frodo@shire, sam@shire, merry@shire, pippin@shire, aragorn@arnor, gandalf@cosmos, gimli@erebor, legolas@mirkwood, boromir@gondor

> fellowship = fellowship !gandalf@cosmos !boromir@gondor
frodo@shire, sam@shire, merry@shire, pippin@shire, aragorn@arnor, gimli@erebor, legolas@mirkwood

> fellowship = 


> fellowship


Fully-closed list expressions

Every operator that has a list expression as a subexpression must accept any list expression. So for these operators:

  • union e,f
  • difference e!f
  • intersection e*f
  • definition listname=e
  • sequence e;f
  • grouping (e)

… the subexpressions e and f may be any valid list expression.

This is a change from phase 1, in which sequences and definitions could not appear as subexpressions of union, difference, and intersection operators.

The precedence of the operators, including sequences and definitions, was defined in the phase 1 spec.

Binary operators should be evaluated from left to right, so that list definitions in the left-hand side expression e must be substituted into the right-hand side expression f. For example, the meaning of (room=alice@mit.edu)*room should be alice@mit.edu.

The behavior of list definitions nested inside other list definitions, like a=(b=c), is not explicitly specified. The system should do something reasonable and self-consistent.

Loading and saving

The console interface should provide !save and !load commands that save and load all currently-defined named lists to a user-provided filename:

These are example outputs, not fully determined outputs. Your system’s output may vary within the bounds of the spec. Examples of variation include whitespace, capitalization, and order.

> hobbits = bilbo@shire, frodo@shire, sam@shire, merry@shire, pippin@shire
bilbo@shire, frodo@shire, sam@shire, merry@shire, pippin@shire

> !save LOTR.txt

> hobbits =


> !load LOTR.txt

> hobbits
bilbo@shire, frodo@shire, sam@shire, merry@shire, pippin@shire

The contents of the file should be a single valid list expression – specifically, a sequence of list definitions. The behavior of the load command should be as if that list expression were provided as input to the console UI.

The save command should store list definitions in such a way that when reloaded they can still be edited as described above.

If !load is used on a filename that does not contain a valid list expression, or if !save is used on a filename that cannot be opened for writing (e.g. because the name contains illegal characters or refers to a folder that doesn’t exist), the system should print an informative human-readable error message.

Filenames cannot contain newlines but are not otherwise constrained by this spec.

Command-line arguments

The system’s main() method should accept any number of filenames as command-line arguments, and load them in the order given before displaying its first prompt.

If attempting to load any of the files encounters an error, the system should display a human-readable error, but it is left unspecified whether the error causes the program to exit or continue.

There are several ways to run a Java program with command-line arguments.

Web user interface

In order to be more usable, the system should also be a web server, offering a web interface served from port 5021.

The protocol should be standard HTTP, which means every communication is a client request with a server response. Client requests are GET requests, and the server response is a simple HTML page.

The only request the system must support is evaluating a list expression:

GET /eval/list-expression

where list-expression is a list expression as defined above, but with all whitespace omitted. The result of this GET request should be an HTML page that, when viewed in a web browser, provides two user interface features:

  • displays the set of recipients represented by list-expression, so that the user can copy and paste them
  • presents a mailto: hyperlink containing those recipients, so that the user can click on it and start an email message if their web browser is configured to handle mailto: links

The exact form of the user interface is up to you, as long as it at least enables these two user actions. If list-expression is not a valid list expression, the system’s HTML response should show an informative human-readable error message.

For example, when the user on the same machine types this into their web browser:

http://localhost:5021/eval/bagginses=bilbo@shire,frodo@shire;bagginses

the web server might respond with the following simple HTML:

This is an example output, not fully determined. Your system’s output may vary within the bounds of the spec. Examples of variation include HTML formatting, whitespace, capitalization, and order.

<a href="mailto:bilbo@shire,frodo@shire">email these recipients</a>
<br>
bilbo@shire, frodo@shire

which appears in the web browser like this:

email these recipients
bilbo@shire, frodo@shire

The system must be designed to be safe for use by a console user and multiple web users at the same time. All users should share the same set of list definitions. If one user defines or redefines a list, all users should subsequently see that edit.

To implement the web server, we strongly recommend using the com.sun.net.httpserver HTTP server library provided as part of the official implementation of Java 8.

Note that the output of the web server should have content type text/html so that the web browser will interpret the HTML formatting, not text/plain as used in the code from class 25.

In addition to that code, see: an example of testing an HTTP server.

Going Further

If you want to go beyond the spec, you might extend the list expression language with new features, e.g.:

  • user-written comments, like // this is a comment
  • regular expressions that expand into a set of list names, like /6.\d+-students/
  • macro definitions, like {1}-minus-fascists = {1} !all-faculty

You might extend the console user interface with additional commands, e.g.:

  • showing the definition of a list instead of evaluating it, e.g. !show hobbits
  • seeing all currently-defined list names, e.g. !showall
  • debugging an expression by showing how each of its subexpressions evaluate, e.g. !debug hobbits

You might extend the web interface with GET requests for other console commands. For example, the web interface as specified doesn’t support loading and saving, because !load and !save are not list expressions.

You might also improve the formatting or usability of the HTML output, e.g.:

  • format the output so that it’s aesthetically pleasing to look at
  • add hyperlinks for all named lists in the system, e.g. pointing to /eval/listname
  • automatically select the recipient list for easy copying (see a Constellation page for an example)
  • color-code each recipient in the output according to which list name it came from
  • separately display in the output the recipients that were omitted by ! or * operators

You might also improve the system’s security, because the web interface as specified is not secure. Assuming your machine’s network firewall allows it, any user on the Internet can visit the server and access or even redefine lists. If you add security features, like user accounts and passwords, please ensure that access through localhost doesn’t require authentication, so that your TA does not need to create an account in order to try your system on their own computer.

None of these features are required. Optional features make your system more powerful and interesting, but your grade will be based on whether your code is safe from bugs, easy to understand, and ready for change, not by how many extra features it has.