AWACS is written in Java, using the Play! framework. A few notes on Play! based applications:
- Java files are compiled on the fly — you can edit and change files without starting/stopping or recompiling the application.
- The "app" directory of the application or its modules contains executed code.
- Modules are basically miniature Play! applications which can be transparently grafted into a another application: they can have their own 'app', 'lib', etc and those paths are simply searched after the main application's paths when loading files.
A few notes on the dashboard application:
- The app uses its database to store WidgetInstances which are a specific configurations of a Widget
- A Dashboard is a collection of WidgetInstances, arranged in columns, optionally with parameters specific to that dashboard (stored as an Assignment).
- Bundles of widgets are packaged as Play! modules so that company-specific widgets are kept separate from distributed widgets.
- The main app has a few "raw" widgets builtin for rendering HTML or Images.
- A Widget is Java class which implements the Widget interface, contained within a package in the widgets package of the application or an added module.
- A Widget can include CSS and JS files in its package directory, to be linked in the
<head>of any pages which include an instance of it.
- A Widget controls rendering of its HTML and can setup AJAX/JSON end-points to do server-side processing.
Use your package manager or see Play! documentation for more up-to-date examples, but as of writing, this was one option:
curl -O "http://download.playframework.org/releases/play-18.104.22.168.zip" unzip play-22.214.171.124.zip sudo cp -r play-126.96.36.199 /usr/local/play rm play-188.8.131.52.zip echo "export PATH=\$PATH:/usr/local/play" >> ~/.profile source ~/.profile play
http://localhost:9000/widgets displays a gallery of installed widgets as well configured instances, along with links to the sandbox to play with them.
?repair=all to gallery will delete orphaned instances who's providing widget code is no longer available.
?rescan=all to the gallery will freshen the widget cache.
Checkout widget module(s) and add to the application. For example:
cd ~/dashboard git clone <path-to-awacs-widgets-local> echo "module.awacs-widgets-local=`pwd`/awacs-widgets-local" >> awacs/conf/application.conf
mkdir sandbox && cd sandbox /path/to/awacs/examples/widget.sh cp -r <package> <widget bundle>/app/widgets/<package>
When developing a widget, a simple action is available to render a specific widget for testing without needing to create a WidgetInstance or add it to a Dashboard:
When rendering a widget, the dashboard will call the
rendermethod of the widget to generate HTML.
BaseWidget's implementation will search first for a .html file with the same name as the widget class, then for
widget.html, in the widget's package. In the example widget
mywidget.SomeClasswill both render from
mywidget.OtherClasswith render from
JS and CSS resources
The dashboard will check every widget on a given dashboard for
styles.cssbefore rendering a dashboard. If found, these are linked in the
<head>tag, and are served using
/scripts/<WidgetPackageName>.js. In the example widget
endpoint(endpointName, params)of a widget is invoked by the dashboard to reply to requests made to
Objectit returns is rendered to the client as JSON using
Gson().toJson(). In the example, an a request to
/endpoint/mywidget.MyClass/getDataPointswhich would result in a call to
mywidget.MyClass("getDataPoints", params). See the Play! docs for details on the
paramsargument, but it exposes request parameters.
Dashboard.register(somethingToRun): Drop this in a widget's HTML, and somethingToRun's
start()method will be called after everything has loaded. The Dashboard will start widgets gradually to maintain performance.
Dashboard.warn(message): displays message to the user briefly (i.e. an ajax call timed out).
Dashboard.fatal(message): displays message and reloads the dashboard. Use this only when recovery from an error is not likely (i.e. malformed JSON indicates potential version change).
app/ widgets/ mywidget/ behavior.js MyClass.java OtherClass.html OtherClass.java SomeClass.java styles.css widget.html myOtherWidget/ OtherWidget.java widget.html