Thursday, March 11, 2010

Using Jarc with App Engine

I've written a sample Jarc web app for Google App Engine.

Overview of the code

src/wine.sml

(Wine
  id Long
  description String
  rating String
  created Date
)
This uses SML format to define the JDO object to persist in App Engine. The script src/mkjdo.arc converts this into a Java class.

war/winerecord.arc

(use 'jtml)

(def /home (req res)
  (html
    (head
      (title "WineRecord - What wines did I like?")
      (link rel "stylesheet" src "winerecord.css")
      (script src "http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js")
      (script "$(document).ready(function() { $(\"input:text:first\").focus(); });"))
    (body
      (div
        (with-open db (getPersistenceManager pmf*)
          (form action "/add" method "POST"
            (tab
              (let wines (execute (newQuery db "select from wine.Wine order by created desc range 0,500"))
                (tr (th "Buy Again?") (th "Wine") (th "Date Added") (th))
                (each wine wines
                  (tr (td wine!description)
                      (td wine!rating)
                      (td wine!created)
                      (td (a href (string "/edit?id=" wine!id) "Edit")))))
              (tr (td (text name "description" size 56))
                  (td (select name "rating"
                              (option "yes")
                              (option "no")
                              (option "maybe")))
                  (td (submit value "Add Wine"))
                  (td)))))
        (a href "/export" "Export Wines") " "
        (a href "/import" "Import Wines")))))

The above is just an excerpt. You can also view the complete winerecord.arc

No, it doesn't use the standard arc html package. I think it would be difficult to make that work since it would require serializing closures to make them available in multiple web servers.

The jtml package uses SML format which has a direct mapping to XHTML. So the tag names should be familiar to anyone familiar with HTML. The only additions to HTML in jtml are abbreviations for input tags based on the type, for instance you can do:

(text name "name" value "foo")
instead of requiring
(input type "text" name "name" value "foo")
Although the latter works also.

Given my rant about the advantages of saving one token you might wonder why I didn't abbreviate the html tags to within and inch of their lives. Well, in this case, I think leveraging compatibility with HTML is more valuable. And you can create your own macros to abbreviate it however you like. It doesn't have to be part of the Jarc language, unlike the Java access syntax which does have to be part of the language.

HttpRequest

Jarc has it's own HttpRequest class which supports lookup using apply, so the code can do:

   ... req!rating ...
Instead of
   ... (getParameterValue req "rating") ...

JDO

The JDO class created from src/wine.sml is Wine.java in package "wine". See build.xml where mkjdo is called (around like 32). The second argument to mkjdo is the Java package name to use. I couldn't get App Engine to work if the JDO object was in the default package.

Features of the JDO Wine class

  • Supports lookup using apply - wine!created
  • Supports sref - (= wine!created ...)
  • Has a constructor that takes a map to init the object - (new wine.Wine (getParameterMap req))
  • Has a putAll method to update the object - (putAll wine (getParameterMap req))
So if the HTML form has the same names as the JDO object it is easy to create or update the JDO object from a form.

Source code and Running App

You can download the entire source from http://bitbucket.org/jazzdev/winerecord/ and you can play with the running app at http://winerecord.appspot.com

4 comments:

  1. I'm using Clojure now for my App Engine projects but Jarc seems very interesting. Will keep an eye on it.

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. App Engine is a distributed web server, so you can't save a closure in memory on server A and have your next request handled by server B. I believe the only options are storing the closure in the distributed memory cache (memcache) or in the distributed persistence store (datastore). In either case you need to be able to serialize the closure.
    website design southampton

    ReplyDelete
  4. They will dive a major opening in the ground, fill it with water, then clock to what extent it takes for the water to saturate the ground. In the event that the water depletes too quick, you have an excessive amount of sand. In the event that it depletes too moderate, you have an excess of mud. payday loans san-diego

    ReplyDelete