~ lift+jQuery first prototype
authorAlexandre Bertails <bertails@w3.org>
Sun, 01 May 2011 19:37:10 -0400
changeset 368 fff24385e340
parent 367 d88b17289aae
child 369 b06800284060
~ lift+jQuery first prototype
.hgignore
directmapping-webapp/src/main/resources/.keep
directmapping-webapp/src/main/resources/props/default.props
directmapping-webapp/src/main/resources/toserve/typewatch.js
directmapping-webapp/src/main/scala/Test.scala
directmapping-webapp/src/main/scala/bootstrap/liftweb/Boot.scala
directmapping-webapp/src/main/scala/code/comet/.keep
directmapping-webapp/src/main/scala/code/lib/DependencyFactory.scala
directmapping-webapp/src/main/scala/code/model/.keep
directmapping-webapp/src/main/scala/code/snippet/AutoComplete.scala
directmapping-webapp/src/main/scala/code/snippet/HelloWorld.scala
directmapping-webapp/src/main/scala/code/snippet/Servlet.scala
directmapping-webapp/src/main/scala/code/view/.keep
directmapping-webapp/src/main/webapp/WEB-INF/web.xml
directmapping-webapp/src/main/webapp/images/ajax-loader.gif
directmapping-webapp/src/main/webapp/index.html
directmapping-webapp/src/main/webapp/static/index.html
directmapping-webapp/src/main/webapp/templates-hidden/default.html
directmapping-webapp/src/main/webapp/templates-hidden/wizard-all.html
project/build/RDB2RDF.scala
--- a/.hgignore	Tue Mar 22 11:06:48 2011 -0400
+++ b/.hgignore	Sun May 01 19:37:10 2011 -0400
@@ -16,3 +16,4 @@
 ^\.emacs\.desktop\.lock$
 ^\.emacs\.desktop$
 build.properties
+*egp*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/directmapping-webapp/src/main/resources/toserve/typewatch.js	Sun May 01 19:37:10 2011 -0400
@@ -0,0 +1,90 @@
+/*
+ *	TypeWatch 3.0
+ *	
+ *	Original by Denny Ferrassoli
+ *	Refactored by Charles Christolini
+ *	Revised by Kai Schlamp
+ *
+ *	Examples/Docs: www.dennydotnet.com
+ *	
+ *  Copyright(c) 2007 Denny Ferrassoli - DennyDotNet.com
+ *  Copyright(c) 2008 Charles Christolini - BinaryPie.com
+ *  Copyright(c) 2010 Kai Schlamp - medihack.org
+ *  
+ *  Dual licensed under the MIT and GPL licenses:
+ *  http://www.opensource.org/licenses/mit-license.php
+ *  http://www.gnu.org/licenses/gpl.html
+*/
+
+(function(jQuery) {
+	jQuery.fn.typeWatch = function(o){
+		// Options
+		var options = jQuery.extend({
+			wait : 500,
+			callback : function() { },
+			highlight : true,
+			captureLength : 2
+		}, o);
+		
+		function checkElement(timer, override) {
+			var elTxt = jQuery(timer.el).val();
+		
+			if ((elTxt.length >= options.captureLength && elTxt.toUpperCase() != timer.text)
+			|| (override && elTxt.length >= options.captureLength)) {
+				timer.text = elTxt.toUpperCase();
+				timer.cb(elTxt);
+			}
+		}
+		
+		function watchElement(elem) {			
+			// Must be text or textarea
+			if (elem.type.toUpperCase() == "TEXT" || elem.nodeName.toUpperCase() == "TEXTAREA") {
+
+				// Allocate timer element
+				var timer = {
+					timer : null, 
+					text : jQuery(elem).val().toUpperCase(),
+					cb : options.callback, 
+					el : elem, 
+					wait : options.wait
+				};
+
+				// Set focus action (highlight)
+				if (options.highlight) {
+					jQuery(elem).focus(
+						function() {
+							this.select();
+						});
+				}
+
+				// Key watcher / clear and reset the timer
+				var startWatch = function(evt) {
+					var timerWait = timer.wait;
+					var overrideBool = false;
+
+                    // If enter is pressed then diretly execute the callback
+					if (evt.keyCode == 13 && this.type.toUpperCase() == "TEXT") {
+						timerWait = 1;
+						overrideBool = true;
+					}
+					
+					var timerCallbackFx = function()
+					{
+						checkElement(timer, overrideBool)
+					}
+					
+					// Clear timer					
+					clearTimeout(timer.timer);
+					timer.timer = setTimeout(timerCallbackFx, timerWait);									
+				};
+				
+				jQuery(elem).keyup(startWatch);
+			}
+		}
+		
+		// Watch Each Element
+		return this.each(function(index){
+			watchElement(this);
+		});
+	};
+})(jQuery);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/directmapping-webapp/src/main/scala/Test.scala	Sun May 01 19:37:10 2011 -0400
@@ -0,0 +1,44 @@
+case class Movie(val name: String, val director: String)
+
+trait MovieFinderComponent {
+
+  def movieFinder:MovieFinder
+
+  trait MovieFinder {
+    def findAll: List[Movie]
+  }
+}
+
+trait MovieLister {
+  self: MovieFinderComponent =>
+
+  def moviesDirectedBy(director: String): List[Movie] = {
+    movieFinder.findAll.filter(movie => movie.director == director)
+  }
+}
+
+trait MyMovieFinderComponent extends MovieFinderComponent {
+  // finds movies from a file
+  val filename: String
+
+  val movieFinder = new ColonDelimitedMovieFinder
+
+  class ColonDelimitedMovieFinder extends MovieFinder {
+    def findAll = {
+      println("Pretending to read movies from file: " + filename)
+      List(Movie("Sicko", "Michael Moore"), Movie("Inception", "Christopher Nolan"),
+           Movie("Memento", "Christopher Nolan"), Movie("The Prestige", "Christopher Nolan"));
+    }
+  }
+}
+
+
+
+object Cake extends Application {
+// wiring:
+  object MyMovieLister extends MovieLister with MyMovieFinderComponent {
+    val filename = "movies1.txt"
+  }
+
+  MyMovieLister.moviesDirectedBy("Christopher Nolan").foreach(movie => println(movie))
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/directmapping-webapp/src/main/scala/bootstrap/liftweb/Boot.scala	Sun May 01 19:37:10 2011 -0400
@@ -0,0 +1,60 @@
+package bootstrap.liftweb
+
+import net.liftweb._
+import util._
+import Helpers._
+
+import common._
+import http._
+import sitemap._
+import Loc._
+
+import net.liftweb.http.js.jquery.JQuery14Artifacts
+import net.liftweb.widgets.autocomplete.AutoComplete
+
+
+/**
+ * A class that's instantiated early and run.  It allows the application
+ * to modify lift's environment
+ */
+class Boot {
+  def boot {
+    // where to search snippet
+    LiftRules.addToPackages("code")
+
+    // Build SiteMap
+    val entries = List(
+      Menu.i("Home") / "index", // the simple way to declare a menu
+
+      // more complex because this menu allows anything in the
+      // /static path to be visible
+      Menu(Loc("Static", Link(List("static"), true, "/static/index"), 
+	       "Static Content")))
+
+    AutoComplete.init
+
+    // set the sitemap.  Note if you don't want access control for
+    // each page, just comment this line out.
+    LiftRules.setSiteMap(SiteMap(entries:_*))
+
+    //Show the spinny image when an Ajax call starts
+    LiftRules.ajaxStart =
+      Full(() => LiftRules.jsArtifacts.show("ajax-loader").cmd)
+    
+    // Make the spinny image go away when it ends
+    LiftRules.ajaxEnd =
+      Full(() => LiftRules.jsArtifacts.hide("ajax-loader").cmd)
+
+    // Force the request to be UTF-8
+    LiftRules.early.append(_.setCharacterEncoding("UTF-8"))
+
+    LiftRules.statelessDispatchTable.append(code.snippet.Services)
+
+    import net.liftweb.http.ResourceServer
+    ResourceServer.allow {
+      case "typewatch.js" :: Nil => true
+    }
+
+
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/directmapping-webapp/src/main/scala/code/lib/DependencyFactory.scala	Sun May 01 19:37:10 2011 -0400
@@ -0,0 +1,57 @@
+package code {
+package lib {
+
+import net.liftweb._
+import http._
+import util._
+import common._
+import _root_.java.util.Date
+
+/**
+ * A factory for generating new instances of Date.  You can create
+ * factories for each kind of thing you want to vend in your application.
+ * An example is a payment gateway.  You can change the default implementation,
+ * or override the default implementation on a session, request or current call
+ * stack basis.
+ */
+object DependencyFactory extends Factory {
+  implicit object time extends FactoryMaker(Helpers.now _)
+
+  /**
+   * objects in Scala are lazily created.  The init()
+   * method creates a List of all the objects.  This
+   * results in all the objects getting initialized and
+   * registering their types with the dependency injector
+   */
+  private def init() {
+    List(time)
+  }
+  init()
+}
+
+/*
+/**
+ * Examples of changing the implementation
+ */
+sealed abstract class Changer {
+  def changeDefaultImplementation() {
+    DependencyFactory.time.default.set(() => new Date())
+  }
+
+  def changeSessionImplementation() {
+    DependencyFactory.time.session.set(() => new Date())
+  }
+
+  def changeRequestImplementation() {
+    DependencyFactory.time.request.set(() => new Date())
+  }
+
+  def changeJustForCall(d: Date) {
+    DependencyFactory.time.doWith(d) {
+      // perform some calculations here
+    }
+  }
+}
+*/
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/directmapping-webapp/src/main/scala/code/snippet/AutoComplete.scala	Sun May 01 19:37:10 2011 -0400
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2007-2010 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.w3 {
+
+package net.liftweb {
+package widgets {
+package autocomplete {
+
+import _root_.scala.xml.{NodeSeq, Node, Elem, PCData, Text}
+import _root_.net.liftweb.common._
+import _root_.net.liftweb.util._
+import _root_.net.liftweb.http._
+import _root_.net.liftweb.http.js._
+import JsCmds._
+import JE._
+import S._
+import SHtml._
+import Helpers._
+
+object AutoComplete {
+  
+  def apply(start: String, 
+            options: (String, Int) => Seq[String],
+            jsCmd: JsCmd,
+            attrs: (String, String)*) = new AutoComplete().render(start, options, jsCmd, attrs:_*)    
+    
+  /**
+   * register the resources with lift (typically in boot)
+   */
+  def init() {
+    import _root_.net.liftweb.http.ResourceServer
+
+    ResourceServer.allow({
+        case "autocomplete" :: _ => true
+     })
+  }
+
+}
+
+class AutoComplete {
+  
+  /**
+   * Render a text field with Ajax autocomplete support
+   * 
+   * @param start - the initial input string
+   * @param option - the function to be called when user is typing text. The text and th options limit is provided to this functions
+   * @param attrs - the attributes that can be added to the input text field 
+   * @param jsonOptions - a list of pairs that will be send along to the jQuery().AutoComplete call (for customization purposes)
+   */
+   def render(start: String, 
+              options: (String, Int) => Seq[String], 
+              jsCmd: JsCmd, 
+              attrs: (String, String)*): Elem = {
+    
+    val f = (ignore: String) => {
+      val q = S.param("q").openOr("")
+      val limit = S.param("limit").flatMap(asInt).openOr(10)
+      PlainTextResponse(options(q, limit).map(s => s+"|"+s).mkString("\n"))
+    }
+
+
+    fmapFunc(SFuncHolder(f)){ func =>
+      val what: String = encodeURL(S.contextPath + "/" + LiftRules.ajaxPath+"?"+func+"=foo")
+
+      val id = Helpers.nextFuncName
+
+     /* merge the options that the user wants */
+      val jqOptions =  ("minChars","0") ::
+                       ("matchContains","true") ::
+                       Nil
+      val json = jqOptions.map(t => t._1 + ":" + t._2).mkString("{", ",", "}")
+      val autocompleteOptions = JsRaw(json)
+    
+      val onLoad = JsRaw("""
+      jQuery(document).ready(function(){
+        var data = """+what.encJs+""";
+        jQuery("#"""+id+"""").autocomplete(data, """+autocompleteOptions.toJsCmd+""").result(function(event, dt, formatted) {
+          jQuery("#"""+id+"""").val(formatted);
+      """+jsCmd.toJsCmd+"""
+        });
+      });""")
+
+      <span>
+        <head>
+          <link rel="stylesheet" href={"/" + LiftRules.resourceServerPath +"/autocomplete/jquery.autocomplete.css"} type="text/css" />
+          <script type="text/javascript" src={"/" + LiftRules.resourceServerPath +"/autocomplete/jquery.autocomplete.js"} />
+          {Script(onLoad)}
+        </head>
+        {
+          <input type="text" id={id} value={start} />
+        }
+      </span>
+
+   }
+  }
+}
+
+}
+}
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/directmapping-webapp/src/main/scala/code/snippet/HelloWorld.scala	Sun May 01 19:37:10 2011 -0400
@@ -0,0 +1,109 @@
+package code {
+package snippet {
+
+import _root_.scala.xml.{NodeSeq, Text}
+import _root_.net.liftweb.util._
+import _root_.net.liftweb.common._
+import _root_.java.util.Date
+import code.lib._
+import Helpers._
+import _root_.net.liftweb.http._
+import net.liftweb.json.JsonAST._
+import net.liftweb.http.js.JsCmds._
+import net.liftweb.http.js.JE.{JsRaw, AnonFunc}
+
+import _root_.org.w3.net.liftweb.widgets.autocomplete._
+
+import org.w3.directmapping.servlet._
+
+
+
+import org.w3.rdf._
+import org.w3.rdb.RDB._
+import org.w3.sql
+import org.w3.rdf.turtle.TurtleModule
+import org.w3.directmapping.DirectMappingModule
+import org.w3.rdf.jena._
+
+
+
+import net.liftweb.http.rest.RestHelper
+
+object Services extends RestHelper {
+  serve {
+    case "ddl" :: ddl :: Nil Get _ => JsonResponse(JsRaw(QueryManager.getQueries(ddl)))
+    case "ddls" :: Nil Get _ => {
+      val current = S.param("q").openOr("")
+      val limit = S.param("limit").flatMap(asInt).openOr(10)
+      PlainTextResponse(QueryManager.getQueries.keys filter { _ contains current } take limit map (s => s+"|"+s) mkString "\n")
+    }
+    case "parse-ddl" :: Nil Post _ => {
+      try {
+        val SQLParser = sql.SqlParser()
+        val db = SQLParser.toDB(S.param("ddl").openOr(""))
+        PlainTextResponse("DDL successfully parsed")
+      } catch {
+        case e => PlainTextResponse(e.toString)
+      }
+    }
+  }
+}
+
+
+
+class DirectMapping extends JenaModel with DirectMappingModule with TurtleModule {
+
+  import DirectMapping._
+
+  val SQLParser = sql.SqlParser()
+
+  val turtleParser = new TurtleParser { }
+
+  def jenaSerializer(g:Graph):String = {
+    val m = com.hp.hpl.jena.rdf.model.ModelFactory.createModelForGraph(g.jenaGraph)
+    val s = new java.io.StringWriter
+    m.write(s, "TURTLE")
+    s.toString
+  }
+
+  def getSQL = Run("""jQuery.get('/sql/'+formatted, function(data) { jQuery("#sql-query").val(data); });""")
+
+  def queryArea = {
+    ".query *" #> QueryManager.getQueries("defaultSQL") &
+    ".load-query" #> SHtml.ajaxButton(Text("load"), () => SetHtml("sql-query", Text(QueryManager.getQueries("")))) &
+    ".query-box *" #> AutoComplete("", buildQuery _, getSQL)
+  }
+
+
+  private def buildQuery(current: String, limit: Int): Seq[String] = {
+    QueryManager.getQueries.keys.toSeq filter { _ contains current } take limit
+  }
+
+
+  private var sqlValue = QueryManager.getQueries("defaultSQL")
+
+  // private val resultValue = sqlValue.lift { (s:String) => {
+  //   try {
+  //     val db = SQLParser.toDB(s)
+  //     DirectMapping.MinEncode = false
+  //     val computedGraph:Graph = databaseSemantics(db)
+  //     jenaSerializer(computedGraph)
+  //   } catch {
+  //     case e => e.getMessage
+  //   }
+  // }}
+
+  def sqlAjaxTextArea = {
+    "#sql" #> SHtml.ajaxTextarea(
+      sqlValue,
+      v => { println("new v"); sqlValue = v; Noop })
+  }
+
+
+
+}
+
+
+
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/directmapping-webapp/src/main/scala/code/snippet/Servlet.scala	Sun May 01 19:37:10 2011 -0400
@@ -0,0 +1,214 @@
+package org.w3.directmapping.servlet
+
+import javax.servlet.http.{HttpServlet, HttpServletRequest, HttpServletResponse} 
+import scala.xml.XML
+import scala.xml.dtd.{DocType, PublicID}
+
+import org.w3.rdf._
+import org.w3.rdb.RDB._
+import org.w3.sql
+import org.w3.rdf.turtle.TurtleModule
+import org.w3.directmapping.DirectMappingModule
+import java.io.File
+
+import org.w3.rdf.jena._
+
+import java.util.regex._ 
+
+object DirectMappingWebapp {
+
+  val defaultSQL = QueryManager.getQueries("defaultSQL")
+
+  val encoding = "utf-8"
+
+  val Style = """
+    #sql { background-color: #e7e7ff; float:left; bordeHer: thin solid #888888; padding: 1em; }
+    #result { background-color: #eee; float:left; border: thin solid #888888; padding: 1em; }
+    .clear { clear:both; }
+    input { margin-bottom: -1em; }
+"""
+
+  def format(varr:String, sql:String):String = {
+    val formattedSQL = sql.replaceAll("\n+$", "").replaceAll("\n", "\\\\n\\\\\n")
+    "var " + varr + " = '" + formattedSQL + "';"
+  }
+
+  def validJSvar(varr:String) = {
+    if ("^[0-9]".r.findFirstIn(varr).isDefined)
+      "_" + varr
+    else
+      varr
+  }
+
+  val Script:String = QueryManager.getQueries map { case (varr, sql) => format(validJSvar(varr), sql) } mkString "\n\n"
+
+
+
+  def renderVar(varr:String) = 
+    <p><input value={ varr } type="button" onclick={ "document.getElementById('sql').value = " + validJSvar(varr) + ";" } /></p>
+
+}
+
+import DirectMappingWebapp._
+
+class DirectMappingWebapp extends HttpServlet with JenaModel with DirectMappingModule with TurtleModule {
+
+  import DirectMapping._
+
+  val SQLParser = sql.SqlParser()
+
+  val turtleParser = new TurtleParser { }
+
+  def jenaSerializer(g:Graph):String = {
+    val m = com.hp.hpl.jena.rdf.model.ModelFactory.createModelForGraph(g.jenaGraph)
+    val s = new java.io.StringWriter
+    m.write(s, "TURTLE")
+    s.toString
+//     m.write(s, "N-TRIPLE")
+//     val r = s.toString
+// println("r: " + r)
+// val p = Pattern.compile("\\\\u([0-9A-F]{4})").matcher(r)
+// val sb = new StringBuffer(r.size) ; val rsb = new StringBuffer(4)
+
+// while (p.find) { rsb.replace(0, rsb.length, p.group(1)) ; p.appendReplacement(sb, Character(rsb)) }
+// p.appendTail(sb)
+//     sb.toString
+  }
+
+  def minEncodeElement (minEncode:Boolean):scala.xml.Elem =
+    if (minEncode) <input name="minEncode" checked="on" type="checkbox" />
+    else <input name="minEncode" type="checkbox" />
+
+  override def doPost(request:HttpServletRequest, response:HttpServletResponse) = {
+    val minEncode = request.getParameter("minEncode") == "on"
+    request.getParameter("sql") match {
+      case null | "" => processIndex(request, response, minEncode)
+      case sql       => processSQL(request, response, sql, minEncode)
+    }
+  }
+
+  override def doGet(request:HttpServletRequest, response:HttpServletResponse) = doPost(request, response)
+
+  val xhtmlDoctype = DocType("html",
+                             PublicID("-//W3C//DTD XHTML 1.0 Strict//EN",
+                                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"),
+                             Nil)
+
+  def render(sql:String, minEncode:Boolean, result:Option[String]) =
+    <html xmlns="http://www.w3.org/1999/xhtml">
+      <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+        <title>Direct Mapping Demo</title>
+      <style type="text/css" media="print, screen and (min-width: 481px)">{ Style }
+      </style>
+      <script type="text/javascript">{ Script }
+      </script>
+      </head>
+      <body>
+        <h1>Direct Mapping Demo</h1>
+	<p>Input some DDL/SQL and see the resulting <a href="http://www.w3.org/2001/sw/rdb2rdf/directMapping/">Direct Graph</a>. This interface uses GET (vs. POST) so the length of the input SQL will be limited on servers which impose a limit on the URL length.</p>
+	<p>Please send bug reports to <a href="mailto:public-rdb2rdf-comments@w3.org">public-rdb2rdf-comments@w3.org</a>.</p>
+        <form method="get" action="/">
+          <p><textarea rows="15" cols="80" name="sql" id="sql">{ sql }</textarea></p>
+	  <div style="float:right;">
+	  <div style="float:left;">
+            { List("emp_addr", "hier_tabl_proto", "hier_table", "multi_key", "ref_no_pk") map renderVar }
+	  </div>
+	  <div style="float:left;">
+            { List("1table0rows", "1table1row", "1table2columns1row", "1table3columns1row", "2duplicates0nulls", "varchar_varchar_1row", "1table1compositeprimarykey3columns1row", "1table1primarykey1column1row", "2tables1primarykey1foreingkey") map renderVar }
+	  </div>
+	  </div>
+	  <p>{ minEncodeElement(minEncode) }Minimally encode IRI components (just encode [%&lt;+ /=#&gt;])</p>
+	  <p><input value="clear" type="button" onclick="document.getElementById('sql').value = '';" /></p>
+	  <p><input id="submit" value="submit SQL" type="submit" /></p>
+        </form>
+	<div class="clear"/>
+        { if (result isDefined) <pre name="result" id="result">{ result.get }</pre> }
+        <hr class="clear" />
+        <address>
+          <a href="http://www.w3.org/People/Eric/">Eric Prud'hommeaux</a>, <a href="http://www.w3.org/People/Bertails/">Alexandre Bertails</a>, Feb 2011
+        </address>
+      </body>
+    </html>
+
+  def processSQL(request:HttpServletRequest, response:HttpServletResponse, sql:String, minEncode:Boolean) {
+
+    val result:String =
+      try {
+        val db = SQLParser.toDB(sql)
+        DirectMapping.MinEncode = minEncode
+        val computedGraph:Graph = databaseSemantics(db)
+        jenaSerializer(computedGraph)
+      } catch {
+        case e => e.getMessage
+      }
+
+    val html = render(sql, minEncode, Some(result))
+
+    response.setContentType("application/xml; charset='" + encoding + "'")
+
+    XML.write(response.getWriter, html, encoding, false, xhtmlDoctype) 
+
+  }
+
+  def processIndex(request:HttpServletRequest, response:HttpServletResponse, minEncode:Boolean) {
+
+    val index = render(defaultSQL, minEncode, None)
+
+    response.setContentType("application/xml; charset='" + encoding + "'")
+
+    XML.write(response.getWriter, index, encoding, false, xhtmlDoctype)
+
+  }
+
+}
+
+object QueryManager {
+
+  import java.net._
+  import java.io._
+  import java.util.jar._
+  import scala.collection.JavaConversions._
+  import scala.io.Source
+
+  /** http://www.uofr.net/~greg/java/get-resource-listing.html */
+  def getResourceListing(path:String):List[String] = {
+    val clazz:Class[_] = this.getClass
+    var dirURL:URL = clazz.getClassLoader().getResource(path)
+    if (dirURL != null && dirURL.getProtocol == "file") {
+      /* A file path: easy enough */
+      new File(dirURL.toURI).list.toList
+    } else {
+      if (dirURL == null) {
+        val me = clazz.getName().replace(".", "/")+".class"
+        dirURL = clazz.getClassLoader().getResource(me)
+      }
+      if (dirURL.getProtocol == "jar") {
+        val jarPath = dirURL.getPath.substring(5, dirURL.getPath().indexOf("!"))
+        val jar:JarFile = new JarFile(URLDecoder.decode(jarPath, "UTF-8"))
+        val entries = jar.entries filter { _.getName startsWith path } map { e => {
+          var entry = e.getName substring path.length
+          val checkSubdir = entry indexOf "/"
+          if (checkSubdir >= 0) entry = entry.substring(0, checkSubdir)
+          entry
+        } }
+        
+        entries
+      }    
+      error("Cannot list files for URL "+dirURL);
+    }
+  }
+
+  lazy val getQueries:Map[String, String] = {
+    val classloader = this.getClass.getClassLoader
+    val entries = getResourceListing("queries/")
+    val queries = entries map { entry => {
+      val url = classloader.getResource("queries/" + entry)
+      val query = Source.fromURL(url, "UTF-8").getLines.mkString("\n")
+      (entry, query)
+    } } toMap
+
+    queries
+  }
+
+}
--- a/directmapping-webapp/src/main/webapp/WEB-INF/web.xml	Tue Mar 22 11:06:48 2011 -0400
+++ b/directmapping-webapp/src/main/webapp/WEB-INF/web.xml	Sun May 01 19:37:10 2011 -0400
@@ -1,10 +1,21 @@
-<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
-  <servlet>
-    <servlet-name>directmapping-webapp</servlet-name>
-    <servlet-class>org.w3.directmapping.servlet.DirectMappingWebapp</servlet-class>
-  </servlet>
-  <servlet-mapping>
-    <servlet-name>directmapping-webapp</servlet-name>
-    <url-pattern>/*</url-pattern>
-  </servlet-mapping>
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<!DOCTYPE web-app
+PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+"http://java.sun.com/dtd/web-app_2_3.dtd">
+
+<web-app>
+<filter>
+  <filter-name>LiftFilter</filter-name>
+  <display-name>Lift Filter</display-name>
+  <description>The Filter that intercepts lift calls</description>
+  <filter-class>net.liftweb.http.LiftFilter</filter-class>
+</filter>
+  	
+
+<filter-mapping>
+  <filter-name>LiftFilter</filter-name>
+  <url-pattern>/*</url-pattern>
+</filter-mapping>
+
 </web-app>
Binary file directmapping-webapp/src/main/webapp/images/ajax-loader.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/directmapping-webapp/src/main/webapp/index.html	Sun May 01 19:37:10 2011 -0400
@@ -0,0 +1,98 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
+    <title>Direct Mapping Demo</title>
+    <script type="text/javascript" src="/classpath/jquery.js"></script>
+    <script type="text/javascript" src="/classpath/typewatch.js"></script>
+    <style type="text/css" media="print, screen and (min-width: 481px)">
+    div.area {position:relative; min-width:600px; zoom:0}
+    textarea.query {display:block; width:60%; height:150px; min-height:150px; resize:vertical}
+    .interaction-area {position:absolute; top:0; right:0; width:39%; height:100%}
+    .query-box input[type=text] {width:100%; margin:0; padding:2px}
+    div.message {width:100%; position:absolute; top:1.6em; bottom:6px}
+    div.message textarea {width:100%; height:100%; resize:none; margin:0; padding:2px}
+    </style>
+
+<script type="text/javascript">
+// <![CDATA[
+jQuery(document).ready(function() {
+
+  jQuery("#ddl-name").autocomplete("/ddls", {minChars:0,matchContains:true}).result(function(event, dt, ddlname) {
+    jQuery("#ddl-name").val(ddlname);
+    jQuery.ajax({url: '/ddl/'+ddlname,
+                 success: function(data) { jQuery("#ddl").val(data); jQuery("#ddl-message").val("DDL successfully loaded") }
+                });
+  });
+
+  jQuery("#ddl").typeWatch({
+    callback: function() {
+      jQuery.ajax({type: "POST",
+                   url: '/parse-ddl',
+                   data: 'ddl='+$('#ddl').val(),
+                   success: function(data) { jQuery("#ddl-message").val(data); }
+                  })
+    },
+    wait: 1000,
+    highlight: false,
+    captureLength: 1
+  });
+
+});;
+// ]]>
+</script>
+
+  </head>
+  <body>
+    <h1>Direct Mapping Demo</h1>
+    <p>This webapp lets you play with the Direct Mapping: give it some
+    DDL/SQL, tweak the
+    resulting <a href="http://www.w3.org/2001/sw/rdb2rdf/directMapping/">Direct
+    Graph</a> using SPARQL and observe the result.</p>
+    <p>Please send bug reports to <a
+    href="mailto:public-rdb2rdf-comments@w3.org">public-rdb2rdf-comments@w3.org</a>.</p>
+    
+    <h2>DDL/SQL</h2>
+
+    <div class="area">
+      <textarea rows="15" cols="80" id="ddl" class="query">Here goes the DDL</textarea>
+      <div class="interaction-area">
+        <div class="query-management">
+          <div class="query-box" >
+            <input type="text" value="" id="ddl-name" autocomplete="off" class="ac_input"/>
+          </div>
+          <div class="message">
+            <textarea id="ddl-message" rows="5" cols="40" disabled="disabled">Nothing here</textarea>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <h2>SPARQL</h2>
+
+    If empty, this will be ignored.
+
+    <div id="sparql-area" class="lift:DirectMapping.queryArea area">
+      <textarea rows="15" cols="80" id="sparql-query" class="query">Here goes the SPARQL query</textarea>
+      <div class="interaction-area">
+        <div class="query-management">
+          <div class="query-box" >
+            <textarea rows="1" cols="16" class="area"></textarea>
+          </div>
+          <div id="sparql-message" class="message">
+            <textarea rows="5" cols="40" disabled="disabled">Nothing here</textarea>
+          </div>
+        </div>
+      </div>
+    </div>
+    
+    <h2>Direct Mapping + SPARQL</h2>
+
+    <hr ></hr>
+    <address>
+      <a href="http://www.w3.org/People/Eric/">Eric Prud'hommeaux</a>, <a href="http://www.w3.org/People/Bertails/">Alexandre Bertails</a>, Apr 2011<br />
+      Contributors: <a href="mailto:bvillazon@fi.upm.es">Boris Villazon-Terrazas</a>, <a href="mailto:tgambet@w3.org">Thomas Gambet</a>
+    </address>
+    
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/directmapping-webapp/src/main/webapp/static/index.html	Sun May 01 19:37:10 2011 -0400
@@ -0,0 +1,11 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head><meta content="text/html; charset=UTF-8" http-equiv="content-type" /><title>Home</title></head>
+  <body class="lift:content_id=main">
+    <div id="main" class="lift:surround?with=default;at=content">
+      Static content... everything you put in the /static
+      directory will be served without additions to SiteMap
+    </div>
+  </body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/directmapping-webapp/src/main/webapp/templates-hidden/default.html	Sun May 01 19:37:10 2011 -0400
@@ -0,0 +1,22 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:lift="http://liftweb.net/">
+  <head>
+    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+    <meta name="description" content="" />
+    <meta name="keywords" content="" />
+    <title><span class="lift:Menu.title">code:app:0.1-SNAPSHOT</span></title>
+    <script id="jquery" src="/classpath/jquery.js" type="text/javascript"/>
+  </head>
+  <body>
+    <div class="lift:Menu.builder"/>
+    <div class="lift:Msgs?showAll=true"/>
+
+    <lift:bind name="content" />
+
+    <hr />
+    <h4>
+      <a href="http://www.liftweb.net"><i>Lift</i></a> 
+      is Copyright 2007-2010 WorldWide Conferencing, LLC.
+      Distributed under an Apache 2.0 License.
+    </h4>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/directmapping-webapp/src/main/webapp/templates-hidden/wizard-all.html	Sun May 01 19:37:10 2011 -0400
@@ -0,0 +1,23 @@
+<div>
+  <wizard:screen_info><div>Page <wizard:screen_number/> of <wizard:total_screens/></div></wizard:screen_info>
+  <wizard:wizard_top> <div> <wizard:bind/> </div> </wizard:wizard_top>
+  <wizard:screen_top> <div> <wizard:bind/> </div> </wizard:screen_top>
+  <wizard:errors> <div> <ul> <wizard:item> <li> <wizard:bind/> </li> </wizard:item> </ul> </div> </wizard:errors>
+  <div> <wizard:fields>
+      <table>
+        <wizard:line>
+          <tr>
+            <td>
+              <wizard:label><label wizard:for=""><wizard:bind/></label></wizard:label>
+	      <wizard:help><span><wizard:bind/></span></wizard:help>
+	      <wizard:field_errors> <ul> <wizard:error> <li> <wizard:bind/> </li> </wizard:error> </ul> </wizard:field_errors>
+          </td>
+          <td> <wizard:form/> </td>
+          </tr>
+        </wizard:line>
+      </table>
+    </wizard:fields> </div>
+  <div> <table> <tr> <td> <wizard:prev/> </td> <td> <wizard:cancel/> </td> <td> <wizard:next/> </td> </tr> </table> </div>
+  <wizard:screen_bottom> <div> <wizard:bind/> </div> </wizard:screen_bottom>
+  <wizard:wizard_bottom> <div> <wizard:bind/> </div> </wizard:wizard_bottom>
+</div>
--- a/project/build/RDB2RDF.scala	Tue Mar 22 11:06:48 2011 -0400
+++ b/project/build/RDB2RDF.scala	Sun May 01 19:37:10 2011 -0400
@@ -85,8 +85,25 @@
   class DirectMapping(info: ProjectInfo) extends DefaultProject(info) with Common
 
   class DirectMappingWebapp(info: ProjectInfo) extends DefaultWebProject(info) with Common {
+    val liftVersion = "2.3-RC5"
+    override def libraryDependencies = Set(
+      "net.liftweb" %% "lift-widgets" % liftVersion % "compile",
+//     "net.liftweb" %% "lift-webkit" % liftVersion % "compile",
+//     "net.liftweb" %% "lift-mapper" % liftVersion % "compile",
+//     "com.h2database" % "h2" % "1.2.138",
+// 
+      "net.liftweb" %% "lift-webkit" % liftVersion % "compile->default",
+      // "org.mortbay.jetty" % "jetty" % "6.1.22" % "test->default",
+      "org.mortbay.jetty" % "jetty" % "6.1.22" % "compile,jetty",
+      // "org.eclipse.jetty" % "jetty-webapp" % "7.0.2.v20100331" % "compile,jetty",
+      // "org.eclipse.jetty" % "jetty-webapp" % "7.3.1.v20110307" % "compile,jetty",
+      "junit" % "junit" % "4.5" % "test->default",
+      "ch.qos.logback" % "logback-classic" % "0.9.26",
+      "org.scala-tools.testing" %% "specs" % "1.6.6" % "test->default"
+    ) ++ super.libraryDependencies
+
     val jettyConf = config("jetty")
-    val jettyDep = "org.eclipse.jetty" % "jetty-webapp" % "7.0.2.v20100331" % "compile,jetty"
+    // val jettyDep = "org.eclipse.jetty" % "jetty-webapp" % "7.0.2.v20100331" % "compile,jetty"
     override def jettyClasspath = managedClasspath(jettyConf)
   }
 
@@ -99,15 +116,15 @@
   class SPARQL2SPARQL(info: ProjectInfo) extends DefaultProject(info) with Common
 
   class SPARQL2SQLEndPoint(info: ProjectInfo) extends DefaultWebProject(info) with Common with BSBMPlugin {
-    val jettyConf = config("jetty")
-    /* http://repo1.maven.org/maven2 */
-    val jettyDep = "org.eclipse.jetty" % "jetty-webapp" % "7.0.2.v20100331" % "compile,jetty"
-    override def jettyClasspath = managedClasspath(jettyConf)
-    val mysql = "mysql" % "mysql-connector-java" % "5.1.13"
-    val postgresql = "postgresql" % "postgresql" % "9.0-801.jdbc4"
-    val codaRepo = "Coda Hale's Repository" at "http://repo.codahale.com/"
-    val fig = "com.codahale" %% "fig" % "1.0.7" withSources()
-    override def webappUnmanaged = super.webappUnmanaged +++ ("src" / "main" / "resources" / "database.properties")
+//    val jettyConf = config("jetty")
+//    /* http://repo1.maven.org/maven2 */
+//    val jettyDep = "org.eclipse.jetty" % "jetty-webapp" % "7.0.2.v20100331" % "compile,jetty"
+//    override def jettyClasspath = managedClasspath(jettyConf)
+//    val mysql = "mysql" % "mysql-connector-java" % "5.1.13"
+//    val postgresql = "postgresql" % "postgresql" % "9.0-801.jdbc4"
+//    val codaRepo = "Coda Hale's Repository" at "http://repo.codahale.com/"
+//    val fig = "com.codahale" %% "fig" % "1.0.7" withSources()
+//    override def webappUnmanaged = super.webappUnmanaged +++ ("src" / "main" / "resources" / "database.properties")
   }
 
   class SPARQL2SPARQL2SQL(info: ProjectInfo) extends DefaultProject(info) with Common