Scala4sling

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    Favorites, Groups & Events

    Scala4sling - Presentation Transcript

    1. Scala for Sling Building RESTful Web Applications with Scala for Sling http://people.apache.org/~mduerig/scala4sling/ Michael Dürig Day Software AG 10080 LOGO SPEAKER‘S COMPANY
    2. 2 AGENDA > Introduction > What is Apache Sling? > What is Scala? > Scala for Sling > Summary and questions
    3. 3 Introduction > Michael Dürig – Developer for Day Software – http://michid.wordpress.com/ > Michael Marth – Technology Evangelist for Day Software – http://dev.day.com/
    4. 4 Overview > What to expect – Proof of concept – Experimental code > What not to expect – Product showcase, tutorial – Live coding (demo code available from http://people.apache.org/~mduerig/scala4sling/) > Prerequisites – Basic understanding of Java content repositories (JCR) – Prior exposure to Scala a plus
    5. 5 AGENDA > Introduction > What is Apache Sling? > What is Scala? > Scala for Sling > Summary and questions
    6. 6 Sling builds on JCR > Web application framework for JCR – JCR (JSR-170/JSR-283): Apache Jackrabbit – OSGi-based: Apache Felix – http://incubator.apache.org/sling/ > Scriptable application layer for JCR – JSR-223: Scripting for the Java platform > REST over JCR – Content resolution for mapping request URLs to JCR nodes – Servlet resolution for mapping JCR nodes to request handlers (i.e. scripts)
    7. 7 URL decomposition GET /forum/scala4sling.thread.html
    8. 8 URL decomposition GET /forum/scala4sling.thread.html Repository
    9. 9 URL decomposition GET /forum/scala4sling.thread.html Repository Repository path
    10. 10 URL decomposition GET /forum/scala4sling.thread.html Repository Repository path Application selection
    11. 11 URL decomposition GET /forum/scala4sling.thread.html Repository Repository path Script selection Application selection
    12. 12 AGENDA > Introduction > What is Apache Sling? > What is Scala? > Scala for Sling > Summary and questions
    13. 13 Scala builds on the JVM > Multi-paradigm language for the JVM – Conceived by Martin Odersky and his group (EPFL, Lausanne) – Fully interoperable with Java – IDE plugins for Eclipse and IntelliJ IDEA – http://www.scala-lang.org/ > Concise, elegant, and type safe – Touch and feel of a genuine scripting language – Smoothly integrates object oriented and functional features – Great for creating DSLs
    14. 14 Type inference: the scripting touch > Values val x = 42 // x has type Int val s = x.toString // s has type String val q = s.substring(s) // type mismatch; found String, required Int > Type parameters class Pair[S, T](s: S, t: T) def makePair[S, T](s: S, t: T) = new Pair(s, t) val p = makePair(42.0, "Scala") // p has type Pair[Double, String]
    15. 15 Type inference: the scripting touch > Values val x = 42 // x has type Int val s = x.toString // s has type String val q = s.substring(s) // class Pair<S, T> type mismatch; found String, required Int { public final S s; public final T t; > Type parameters public Pair(S s, T t) { super(); class Pair[S, T](s: S, t: =T) this.s s; def makePair[S, T](s: S, t: t; = new Pair(s, t) this.t = T) } val p = makePair(42.0, "Scala") // p has type Pair[Double, String] } public <S, T> Pair<S, T> makePair(S s, T t) { return new Pair<S, T>(s, t); } public final Pair<Double, String> p = makePair(42.0, "Scala");
    16. 16 XML <pre>literals</pre> > HTML? Scala! val title = "Hello Jazoon 09" println { <html> <body> <h1>{ title }</h1> { (for (c <- title) yield c) .mkString(" ") } </body> </html> }
    17. 17 XML <pre>literals</pre> > HTML? Scala! val title = "Hello Jazoon 09" println { <html> println { <body> Elem(null, "html", Null, TopScope, <h1>{ title }</h1> "body", Null, TopScope, Elem(null, { Elem(null, "h1", Null, TopScope, (for (c <- title) yield c) Text(title) .mkString(" ") ), } Text( </body> (for (c <- title) yield c) </html> .mkString(" ") } ) ) ) }
    18. 18 XML <pre>literals</pre> > HTML? Scala! val title = "Hello Jazoon 09" println { <html> <body> <h1>{ title }</h1> { (for (c <- title) yield c) .mkString(" ") } </body> <html> </html> <body> } <h1>Hello Jazoon 09</h1> H e l l o J a z o o n 0 9 </body> </html>
    19. 19 Implicits: pimp my library > Implicit conversion implicit def translate(s: String) = new { def toGerman = s match { case "Example" => "Beispiel" // ... case _ => throw new Exception("No translation for " + s) } } val german = "Example".toGerman > Déjà vu? – Similar to extension methods in C# – Similar to conversion constructors in C++ – Equivalent to type classes in Haskell
    20. 20 Objects are functions are objects… > Object as function object Twice { def apply(n: Int) = 2*n } println(Twice(21)) // prints 42 > Function as object def twice(n: Int) = 2*n val doubler = twice(_) println(doubler(21)) // prints 42
    21. 21 AGENDA > Introduction > What is Apache Sling? > What is Scala? > Scala for Sling > Summary and questions
    22. 22 Demo application: Forum
    23. 23 Forum: html.scala package forum { object html { import html_Bindings._ // ... println { <html> <body> Welcome to the { currentNode("name") } forum &mdash; { Calendar.getInstance.getTime } { ThreadNewForm.render } { ThreadOverview.render(currentNode) } </body> </html> } }
    24. 24 Forum: html.scala GET /forum.html package forum { object html { import html_Bindings._ // ... println { <html> <body> Welcome to the { currentNode("name") } forum &mdash; { Calendar.getInstance.getTime } { ThreadNewForm.render } { ThreadOverview.render(currentNode) } </body> </html> } }
    25. 25 Forum: html.scala package forum { object html { Put Sling variables into scope import html_Bindings._ (currentNode, request, response, etc.) // ... println { <html> <body> Welcome to the { currentNode("name") } forum &mdash; { Calendar.getInstance.getTime } { ThreadNewForm.render } { ThreadOverview.render(currentNode) } </body> </html> } }
    26. 26 Forum: html.scala package forum { object html { /** import html_Bindings._ // ... * Print out an object followed by a new line character. * @param x the object to print. */ println { def println(x: Any): Unit = out.println(x) <html> <body> Welcome to the { currentNode("name") } forum &mdash; { Calendar.getInstance.getTime } { ThreadNewForm.render } { ThreadOverview.render(currentNode) } </body> </html> } }
    27. 27 Forum: html.scala package forum { object html { /** import html_Bindings._ // ... * Print out an object followed by a new line character. * @param x the object to print. */ println { def println(x: Any): Unit = out.println(x) <html> <body> Welcome to the { currentNode("name") } forum &mdash; { Calendar.getInstance.getTime } { ThreadNewForm.render } { ThreadOverview.render(currentNode) } </body> </html> } }
    28. 28 Forum: html.scala package forum { object html { import html_Bindings._ // implicit def rich(node: Node) = new { ... def apply(property: String) = node.getProperty(property).getString ... println { } <html> <body> Welcome to the { currentNode("name") } forum &mdash; { Calendar.getInstance.getTime } { ThreadNewForm.render } { ThreadOverview.render(currentNode) } </body> </html> } }
    29. 29 Forum: thread overview object ThreadOverview { // imports omitted def render(node: Node) = emptyUnless(node.hasNodes) { <h1>threads</h1> <ul>{ node.nodes map toListItem }</ul> } private def toListItem(node: Node) = { <li> { node("subject") } (<a href={ node.path + ".thread.html"}>show thread</a>) </li> } }
    30. 30 Forum: thread overview object ThreadOverview { def emptyUnless(condition: Boolean)(block: => NodeSeq) = // imports omitted if (condition) block else Empty def render(node: Node) = emptyUnless(node.hasNodes) { <h1>threads</h1> <ul>{ node.nodes map toListItem }</ul> } private def toListItem(node: Node) = { <li> { node("subject") } (<a href={ node.path + ".thread.html"}>show thread</a>) </li> } }
    31. 31 Forum: form data object ThreadNewForm { def render = { <h1>start a new thread</h1> <form action="/content/forum/*" method="POST" enctype="multipart/form-data"> subject <input name="subject" type="text" /> <textarea name="body"></textarea> logo <input name="logo“ type="file" /> <input type="submit" value="save" /> <input name=":redirect" value="/content/forum.html" type="hidden" /> </form> } }
    32. 32 Forum: form data object ThreadNewForm { def render = { <h1>start a new thread</h1> <form action="/content/forum/*" method="POST" enctype="multipart/form-data"> subject <input name="subject" type="text" /> <textarea name="body"></textarea> logo <input name="logo“ type="file" /> <input type="submit" value="save" /> <input name=":redirect" value="/content/forum.html" type="hidden" /> </form> } }
    33. 33 Forum: form data object ThreadNewForm { def render = { POST should add new child node to /content/forum/ <h1>start a new thread</h1> <form action="/content/forum/*" method="POST" enctype="multipart/form-data"> subject <input name="subject" type="text" /> <textarea name="body"></textarea> logo <input name="logo“ type="file" /> <input type="submit" value="save" /> <input name=":redirect" value="/content/forum.html" type="hidden" /> </form> } }
    34. 34 Forum: form data object ThreadNewForm { def render = { POST should add new child node to /content/forum/ <h1>start a new thread</h1> <form action="/content/forum/*" with properties subject and body ... method="POST" of enctype="multipart/form-data"> type String, subject <input name="subject" type="text" /> <textarea name="body"></textarea> logo <input name="logo“ type="file" /> <input type="submit" value="save" /> <input name=":redirect" value="/content/forum.html" type="hidden" /> </form> } }
    35. 35 Forum: form data object ThreadNewForm { def render = { POST should add new child node to /content/forum/ <h1>start a new thread</h1> <form action="/content/forum/*" with properties subject and body ... method="POST" of enctype="multipart/form-data"> type String, subject <input name="subject" and a child node logo of type nt:file. ... type="text" /> <textarea name="body"></textarea> logo <input name="logo“ type="file" /> <input type="submit" value="save" /> <input name=":redirect" value="/content/forum.html" type="hidden" /> </form> } }
    36. 36 Forum: form data object ThreadNewForm { def render = { <h1>start a new thread</h1> <form action="/content/forum/*" method="POST" enctype="multipart/form-data"> subject <input name="subject" type="text" /> <textarea name="body"></textarea> logo <input name="logo“ type="file" /> <input type="submit" value="save" /> <input name=":redirect" value="/content/forum.html" type="hidden" /> </form> } Redirect to forum.html on success }
    37. 37 Extracting form fields > Sling post servlet – No action required: used by default – Creates nodes and properties for form fields – Tweaked with hidden form fields – Sensible defaults > Custom POST request handler – Write a script POST.scala – Process form fields in code – Full control over request processing
    38. 38 Forum: custom POST request handler package forum { object POST { import POST_Bindings._ // ... val node = addNodes(session.root, newPath) node.setProperty("body", request("body")) node.setProperty(“subject", request(“subject")) if (request("logo") != "") { val logoNode = node.addNode("logo", "nt:file") val contentNode = logoNode.addNode("jcr:content", "nt:resource") val logo = request.getRequestParameter("logo") contentNode.setProperty("jcr:lastModified", Calendar.getInstance) contentNode.setProperty("jcr:mimeType", logo.getContentType) contentNode.setProperty("jcr:data", logo.getInputStream) } session.save response.sendRedirect(request(":redirect")) } }
    39. 39 Forum: custom POST request handler package forum { POST /forum.html object POST { import POST_Bindings._ // ... val node = addNodes(session.root, newPath) node.setProperty("body", request("body")) node.setProperty(“subject", request(“subject")) if (request("logo") != "") { val logoNode = node.addNode("logo", "nt:file") val contentNode = logoNode.addNode("jcr:content", "nt:resource") val logo = request.getRequestParameter("logo") contentNode.setProperty("jcr:lastModified", Calendar.getInstance) contentNode.setProperty("jcr:mimeType", logo.getContentType) contentNode.setProperty("jcr:data", logo.getInputStream) } session.save response.sendRedirect(request(":redirect")) } }
    40. 40 Forum: custom POST request handler package forum { object POST { import POST_Bindings._ // ... Add node for this post val node = addNodes(session.root, newPath) node.setProperty("body", request("body")) node.setProperty(“subject", request(“subject")) if (request("logo") != "") { val logoNode = node.addNode("logo", "nt:file") val contentNode = logoNode.addNode("jcr:content", "nt:resource") val logo = request.getRequestParameter("logo") contentNode.setProperty("jcr:lastModified", Calendar.getInstance) contentNode.setProperty("jcr:mimeType", logo.getContentType) contentNode.setProperty("jcr:data", logo.getInputStream) } session.save response.sendRedirect(request(":redirect")) } }
    41. 41 Forum: custom POST request handler package forum { object POST { import POST_Bindings._ // ... Set properties for body and subject val node = addNodes(session.root, newPath) node.setProperty("body", request("body")) node.setProperty(“subject", request(“subject")) if (request("logo") != "") { val logoNode = node.addNode("logo", "nt:file") val contentNode = logoNode.addNode("jcr:content", "nt:resource") val logo = request.getRequestParameter("logo") contentNode.setProperty("jcr:lastModified", Calendar.getInstance) contentNode.setProperty("jcr:mimeType", logo.getContentType) contentNode.setProperty("jcr:data", logo.getInputStream) } session.save response.sendRedirect(request(":redirect")) } }
    42. 42 Forum: custom POST request handler package forum { object POST { import POST_Bindings._ // ... val node = addNodes(session.root, newPath) If the request contains a logo node.setProperty("body", request("body")) node.setProperty(“subject", request(“subject")) if (request("logo") != "") { val logoNode = node.addNode("logo", "nt:file") val contentNode = logoNode.addNode("jcr:content", "nt:resource") val logo = request.getRequestParameter("logo") contentNode.setProperty("jcr:lastModified", Calendar.getInstance) contentNode.setProperty("jcr:mimeType", logo.getContentType) contentNode.setProperty("jcr:data", logo.getInputStream) } session.save response.sendRedirect(request(":redirect")) } }
    43. 43 Forum: custom POST request handler package forum { object POST { import POST_Bindings._ // ... val node = addNodes(session.root, newPath) If the request contains a logo node.setProperty("body", request("body")) node.setProperty(“subject", request(“subject")) ... add a child node logo of type nt:file if (request("logo") != "") { val logoNode = node.addNode("logo", "nt:file") val contentNode = logoNode.addNode("jcr:content", "nt:resource") val logo = request.getRequestParameter("logo") contentNode.setProperty("jcr:lastModified", Calendar.getInstance) contentNode.setProperty("jcr:mimeType", logo.getContentType) contentNode.setProperty("jcr:data", logo.getInputStream) } session.save response.sendRedirect(request(":redirect")) } }
    44. 44 Forum: custom POST request handler package forum { object POST { import POST_Bindings._ // ... val node = addNodes(session.root, newPath) If the request contains a logo node.setProperty("body", request("body")) node.setProperty(“subject", request(“subject")) ... add a child node logo of type nt:file if (request("logo") != "") { val logoNode = node.addNode("logo", set properties jcr:lastModified, ... and "nt:file") val contentNode = logoNode.addNode("jcr:content", "nt:resource") jcr:mimeType and jcr:data val logo = request.getRequestParameter("logo") contentNode.setProperty("jcr:lastModified", Calendar.getInstance) contentNode.setProperty("jcr:mimeType", logo.getContentType) contentNode.setProperty("jcr:data", logo.getInputStream) } session.save response.sendRedirect(request(":redirect")) } }
    45. 45 Forum: custom POST request handler package forum { object POST { import POST_Bindings._ // ... val node = addNodes(session.root, newPath) node.setProperty("body", request("body")) node.setProperty(“subject", request(“subject")) if (request("logo") != "") { val logoNode = node.addNode("logo", "nt:file") val contentNode = logoNode.addNode("jcr:content", "nt:resource") val logo = request.getRequestParameter("logo") contentNode.setProperty("jcr:lastModified", Calendar.getInstance) contentNode.setProperty("jcr:mimeType", logo.getContentType) contentNode.setProperty("jcr:data", logo.getInputStream) Save changes and send redirect } session.save response.sendRedirect(request(":redirect")) } }
    46. 46 Forum: unit testing object html_Bindings extends MockBindings { override def currentNode = new MockNode with MockItem override def request = new MockSlingHttpServletRequest with MockHttpServletRequest with MockServletRequest } object Test extends Application { forum.html }
    47. 47 Forum: unit testing object html_Bindings extends MockBindings { override def currentNode = new MockNode with MockItem override def request = new MockSlingHttpServletRequest with MockHttpServletRequest with MockServletRequest } object Test extends Application { forum.html }
    48. 48 Forum: unit testing object html_Bindings extends MockBindings { override def currentNode = new MockNode with MockItem override def request = new MockSlingHttpServletRequest with MockHttpServletRequest with MockServletRequest } object Test extends Application { forum.html }
    49. 49 Forum: unit testing <html> <head> <link href="/apps/forum/static/blue.css" rel="stylesheet"></link> object html_Bindings extends MockBindings { </head> <body> override def currentNode = new MockNode <div id="Header"> Welcome to the forum with MockItem &mdash; Wed Jun 17 17:12:48 CEST 2009 </div> <div id="Menu"> override def <p>search all threads: request = new MockSlingHttpServletRequest <form action="/content/forum.search.html" with MockHttpServletRequest enctype="multipart/form-data" method="GET"> <input value="" type="text" size="10" name="query"></input> with MockServletRequest <input value="search" type="submit"></input> } </form> </p> </div> <div id="Content"> object Test extends Application { <h1>start a new thread</h1> <span id="inp"> forum.html <form action="/content/forum/*" enctype="multipart/form-data" method="POST"> } <p>subject</p> <p><input type="text" name="subject"></input></p> <p><textarea name="body"></textarea></p> <p>logo</p> <p><input type="file" name="logo"></input></p> <p><input value="save" type="submit"></input></p> <input value="/content/forum.html" type="hidden" name=":redirect"></input> </form> </span> </div> </body> </html>
    50. 50 AGENDA > Introduction > What is Apache Sling? > What is Scala? > Scala for Sling > Summary and questions
    51. 51 Conclusion > Advantages – Scala! – No language boundary – Tool support (i.e. IDE, ScalaDoc, safe refactoring, unit testing) > Disadvantages – IDE support shaky, improves quickly though – Not much refactoring support as of today
    52. 52 Conclusion > Advantages – Scala! – No language boundary – Tool support (i.e. IDE, ScalaDoc, safe refactoring, unit testing) > Disadvantages – IDE support shaky, improves quickly though – Not much refactoring support as of today
    53. 53 Conclusion > Advantages – Scala! <p>Welcome to { currentNode("name") } forum</p> – No language boundary &mdash; { Calendar.getInstance.getTime } { ThreadNewForm.render } – Tool support (i.e. IDE, ScalaDoc, { ThreadOverview.render(currentNode) } safe refactoring, unit testing) > Disadvantages – IDE support shaky, improves quickly though – Not much refactoring support as of today
    54. 54 Conclusion > Advantages – Scala! – No language boundary – Tool support (i.e. IDE, ScalaDoc, safe refactoring, unit testing) > Disadvantages – IDE support shaky, improves quickly though – Not much refactoring support as of today
    55. 55 Conclusion > Advantages – Scala! – No language boundary – Tool support (i.e. IDE, ScalaDoc, safe refactoring, unit testing) > Disadvantages – IDE support shaky, improves quickly though – Not much refactoring support as of today
    56. 56 Conclusion > Advantages – Scala! – No language boundary object html_Bindings { – Tool support (i.e. IDE, ScalaDoc, def currentNode = new MockNode safe refactoring, unit testing) ... } object Test extends Application { > Disadvantages forum.html } – IDE support shaky, improves quickly though – Not much refactoring support as of today
    57. 57 Conclusion > Advantages – Scala! – No language boundary – Tool support (i.e. IDE, ScalaDoc, safe refactoring, unit testing) > Disadvantages – IDE support shaky, improves quickly though – Not much refactoring support as of today
    58. 58 Summary > Apache Sling – Great for building RESTful web applications – Pluggable scripting support (JSR-223) > Scala – Great for scripting – Supports «on the fly» templates through XML literals – Easy unit testing
    59. Michael Dürig michael.duerig@day.com Michael Marth michael.marth@day.com Day Software AG http://www.day.com/ References: • Scala for Sling: http://people.apache.org/~mduerig/scala4sling/ • The Scala programming language: http://www.scala-lang.org/ • Apache Sling: http://incubator.apache.org/sling/ LOGO SPEAKER‘S COMPANY

    + dayday, 5 months ago

    custom

    327 views, 0 favs, 1 embeds more stats

    More info about this document

    © All Rights Reserved

    Go to text version

    • Total Views 327
      • 246 on SlideShare
      • 81 from embeds
    • Comments 0
    • Favorites 0
    • Downloads 4
    Most viewed embeds
    • 81 views on http://dev.day.com

    more

    All embeds
    • 81 views on http://dev.day.com

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories