Web Interface - UBOdin/mimir GitHub Wiki

The Play Framework

Mimir's web interface is built on top of the Play Framework. This framework has a built-in web-server. There is no need to mess around with installing and maintaining a separate server process. Calling sbt run in the application starts up the embedded server.

The current interface

As of this writing, Mimir is a single page web application. The main page contains a navigation bar and a query box. The last part of the page can either be textual status messages or tabular query output. Only state information that is kept is the current working database, and that is maintained through a hidden field. Dynamic content such as query explanations are handled through AJAX. An asynchronous request is made to the server and the server responds with JSON content.

Adding functionality

Adding new functionality could mean adding a new page or new services that can be accessed through AJAX requests.

  • If the new functionality is a service, add JavaScript to call the appropriate service and render the response in /public/javascripts/main.js or a new file in that folder.
  • Add an entry to the /conf/routes file, specifying the URI and an Action to be called that would handle requests for that URI. The URI could be GET, POST or other HTTP methods.
  • Define the Action in /app/controllers/Application.scala. GET Actions accept query string parameters as method arguments. Responses can be HTML specified in /views, JSON or XML. Play provides utilities to convert data objects into JSON/XML and vice versa.
  • Use existing methods in the mimircore/src/main/scala/mimir/WebAPI.scala to call into the core mimir code or add new methods if necessary.

Debugging

In Play code changes are auto-reloaded. There is no need to restart the server for most code changes to be reflected. However, changing application configurations does require a restart. This includes modifying the routes file. Debug paths do not cross process lines. Each line of code from the incoming request to sending out the response can be stepped through and inspected, including request headers. The only code path that is separate from this is the client JavaScript that generates AJAX requests. In case a new service does not work as intended, the first step would be to inspect the request headers, to ensure that the client JavaScript generated the correct request.

Unit tests can be specified using specs2 and are contained within the /test folder.

A note on synchronization

All Actions are asynchronous, which means there can be multiple Actions executing at the same time. The bulk of the debugging in Mimir happens on the SQLite database, which does not support multiple connections to the same database file. Therefore, opening and closing connections to the backend need to be synchronized. At present, a semaphore like solution is implemented in /mimircore/src/main/scala/mimir/sql/JDBCBackend.scala to deal with this issue.

Future work

  • Add support for connecting to databases backed by backends other than SQLite.
  • Possibly, add user sessions and maintain state information. This could lead to a more elegant solution to the synchronization problem with SQLite. Backend connections would be opened and closed in session scope instead of per query.