Scala for Scripting
Implementing an OSGi enabled, JSR-223 compliant scripting engine for Scala
http://people.apache.org/~m...
Agenda
■ Introduction
  – Scripting with Scala
  – Scala for Apache Sling
■ Requirements and goals
■ Challenges and soluti...
Scripting with Scala
■ (Illusion of) executing source code
■ Concise and versatile*
     var capitals = Map("Switzerland" ...
Scripting with Scala (cont.)
■ XML literals: type safe templating
  <html>
    <head>
      <link rel="stylesheet" href="/...
Apache Sling
■ Web application framework
  – Backed by a Java content repository (JSR-170/JSR-283):
    Apache Jackrabbit
...
Sling URL decomposition

  GET   /forum/scala4sling.html   HTTP/1.1




                                             6
Sling URL decomposition

  GET   /forum/scala4sling.html   HTTP/1.1




                                             6
Sling URL decomposition

    GET    /forum/scala4sling.html   HTTP/1.1

Repository path




                              ...
Sling URL decomposition

    GET    /forum/scala4sling.html   HTTP/1.1

Repository path




                  Application
...
Sling URL decomposition

    GET    /forum/scala4sling.html     HTTP/1.1

Repository path                      Script sele...
Scala for Sling
package forum


class html(args: htmlArgs) {
  import args._
    // further imports omitted


    println ...
Scala for Sling
package forum


class html(args: htmlArgs) {
  import args._                                      Import b...
Scala for Sling
package forum


class html(args: htmlArgs) {
  import args._                                      Import b...
Agenda
■ Introduction
■ Requirements and goals
  – JSR-223 compliance
  – OSGi tolerant
  – Further design goals
■ Challen...
JSR-223
■ Scripting for the Java language
  – Allow scripts access to the Java Platform
  – Scripting for Java server-side...
JSR-223: usage
val factories = ServiceRegistry.lookupProviders(classOf[ScriptEngineFactory])
val factory = factories.find(...
OSGi
■ OSGi Service Platform
  – Runtime environment for Java applications (bundles)
  – Module system
  – Life cycle mana...
Further design goals
■ Leverage existing tools
  – Compilers
  – IDEs
  – Test suites
  – Documentation and reporting tool...
Agenda
■ Introduction
■ Requirements and goals
■ Challenges and solutions
  – Leverage existing tools
  – Passing argument...
Leverage existing tools
■ Scripts are valid Scala source entities
■ Tradeoff
  – ceremony
    package forum


    class ht...
Unit testing
class html(args: htmlArgs) {
    import args._
    // further imports omitted


    println {
      <html>
  ...
Unit testing
class html(args: htmlArgs) {
    import args._                                    class htmlArgs {
    // fur...
Unit testing
class html(args: htmlArgs) {
    import args._                                    class htmlArgs {
    // fur...
Passing arguments to Scripts
class ResettableOutStream extends OutputStream implements Resettable {
  public void write(in...
Passing arguments to Scripts
class ResettableOutStream extends OutputStream implements Resettable {
  public void write(in...
Passing arguments to Scripts
class ResettableOutStream extends OutputStream implements Resettable {
  public void write(in...
Bindings wrapper
■ No type information in javax.script.Bindings
  – Generate bindings wrapper exposing static types
  – Ar...
Bindings wrapper (cont.)
class ResettableOutStream extends OutputStream implements Resettable {
  public void write(int b)...
Bindings wrapper (cont.)
class ResettableOutStream extends OutputStream implements Resettable {
  public void write(int b)...
Bindings wrapper (cont.)
class ResettableOutStream extends OutputStream implements Resettable {
  public void write(int b)...
Bindings wrapper (cont.)
■ Limitations
  – Scala’s visibility modifiers not exposed through reflection
  – Not yet working...
Scalac and OSGi
■ Scalac
  – Requires compiler class path
  – File system based
■ OSGi
  – Provides class loaders
  – Bund...
Independent through configuration
■ Abstract implementation details into configuration class
  – Default implementation fo...
Configuration
■ Scala compiler
  – Per script engine
  – scripting.scala.SettingsProvider
  – Class and output paths: scal...
Performance
■ On the fly compilation is slow
  – Cache pre compiled scripts
  – Dependency on bindings: include bindings w...
Conclusion
■ Scala is attractive for scripting
  – Concise and versatile
  – DSL capabilities
  – Type safe
  – XML litera...
References
■ Scala for Scripting
  http://people.apache.org/~mduerig/scala4scripting/
■ Apache Sling
  http://sling.apache...
Upcoming SlideShare
Loading in...5
×

Scala for scripting

3,711

Published on

Its conciseness, versatility and DSL capabilities makes Scala desirable for scripting. In this report we show how we implemented a JSR223 compliant script engine for Scala which runs inside OSGi environments.

While the Scala compiler needs a class path to load class files, OSGi only provides class loaders. To overcome this we implemented a file system abstraction on top of OSGi bundles effectively providing a class path. Furthermore, JSR223's dynamic approach for passing arguments does not play well with Scala's static types. We need to make all types of arguments visible to scripts. Our implementation generates a preamble of adequate implicit conversions which allows scripts to use statically typed variables in a manner resembling dynamic types. Finally performance constraints require caching of pre-compiled scripts.

Apache Sling, an OSGi based web application framework with a scriptable application layer, uses our implementation for type safe templating via Scala's XML support.

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
3,711
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
38
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide























  • Versatile: independent from file system (i.e. JCR), Reporting other then sysout

  • Script compilation: fail fast behavior



















  • - Private modifier: 2.7: class file attributes, 2.8 annotations
    - Ambiguity issues: robuster when using a provider class as source for implicit conversion for each binding
    - Impedance mismatch: JSR-223 provides support for dynamically typed languages, Scala is statically typed
  • - File system traversal operations somewhat problematic on top of OSGi bundles
    - Impedance mismatch: OSGi is a runtime environment, scalac a compile time utility


  • - Pick up &amp;#x2018;illusion of...&amp;#x2019; from introduction

  • Caching complicated: class files depend on generated type wrapper

  • Scala for scripting

    1. 1. Scala for Scripting Implementing an OSGi enabled, JSR-223 compliant scripting engine for Scala http://people.apache.org/~mduerig/scala4scripting/ Michael Dürig michael.duerig@day.com Day Software AG http://www.day.com/ Scala Days 2010 April 15th 1
    2. 2. Agenda ■ Introduction – Scripting with Scala – Scala for Apache Sling ■ Requirements and goals ■ Challenges and solutions ■ Conclusion 2
    3. 3. Scripting with Scala ■ (Illusion of) executing source code ■ Concise and versatile* var capitals = Map("Switzerland" -> "Bern", "Spain" -> "Madrid") capitals += ("France" -> "Paris") val c = capitals.find(_._1 == "France") .map(_._2) .getOrElse("NIL") ■ DSL capabilities ■ Type safe *) Adapted from: Programming in Scala, Martin Odersky, Lex Spoon, Bill Venners. Artima, 2008. 3
    4. 4. Scripting with Scala (cont.) ■ XML literals: type safe templating <html> <head> <link rel="stylesheet" href="/apps/forum/static/blue.css" /> </head> <body> <div id="Header"> Welcome to the { node("name") } forum { Calendar.getInstance.getTime } </div> <div id="Content"> { SearchBox.render(request) } { ThreadOverview.render(node) } </div> </body> </html> 4
    5. 5. Apache Sling ■ Web application framework – Backed by a Java content repository (JSR-170/JSR-283): Apache Jackrabbit – Based on OSGi: Apache Felix – http://sling.apache.org/ ■ RESTful – Content resolution for mapping request URLs to resources (i.e. JCR nodes) – Servlet resolution for mapping resources to request handlers (i.e. scripts) ■ Scriptable application layer – JSR-223: Scripting for the Java platform 5
    6. 6. Sling URL decomposition GET /forum/scala4sling.html HTTP/1.1 6
    7. 7. Sling URL decomposition GET /forum/scala4sling.html HTTP/1.1 6
    8. 8. Sling URL decomposition GET /forum/scala4sling.html HTTP/1.1 Repository path 6
    9. 9. Sling URL decomposition GET /forum/scala4sling.html HTTP/1.1 Repository path Application selection 6
    10. 10. Sling URL decomposition GET /forum/scala4sling.html HTTP/1.1 Repository path Script selection Application selection 6
    11. 11. Scala for Sling package forum class html(args: htmlArgs) { import args._ // further imports omitted println { <html> <body> <div id="Header"> Welcome to the { node("name") } forum { Calendar.getInstance.getTime } </div> <div id="Content"> { SearchBox.render(request) } { ThreadOverview.render(node) } </div> </body> </html> } } 7
    12. 12. Scala for Sling package forum class html(args: htmlArgs) { import args._ Import bindings // further imports omitted println { <html> <body> <div id="Header"> Welcome to the { node("name") } forum { Calendar.getInstance.getTime } </div> <div id="Content"> { SearchBox.render(request) } { ThreadOverview.render(node) } </div> </body> </html> } } 7
    13. 13. Scala for Sling package forum class html(args: htmlArgs) { import args._ Import bindings // further imports omitted println { <html> <body> <div id="Header"> Welcome to the { node("name") } forum { Calendar.getInstance.getTime } </div> Use arguments <div id="Content"> { SearchBox.render(request) } { ThreadOverview.render(node) } </div> </body> </html> } } 7
    14. 14. Agenda ■ Introduction ■ Requirements and goals – JSR-223 compliance – OSGi tolerant – Further design goals ■ Challenges and solutions ■ Conclusion 8
    15. 15. JSR-223 ■ Scripting for the Java language – Allow scripts access to the Java Platform – Scripting for Java server-side applications – Executing scripts: javax.script.{ScriptEngine, ScriptEngineFactory} – Binding application objects into scripts: javax.script.Bindings 9
    16. 16. JSR-223: usage val factories = ServiceRegistry.lookupProviders(classOf[ScriptEngineFactory]) val factory = factories.find(_.getEngineName == "Scala Scripting Engine") val engine = factory.map(_.getScriptEngine).getOrElse { throw new Error("Cannot locate Scala scripting engine") } val bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE) bindings.put("request", servletRequest) engine.eval(script, bindings) 10
    17. 17. OSGi ■ OSGi Service Platform – Runtime environment for Java applications (bundles) – Module system – Life cycle management – Service registry ■ Mostly transparent – Bundle information in manifest file – Relies on class loading 11
    18. 18. Further design goals ■ Leverage existing tools – Compilers – IDEs – Test suites – Documentation and reporting tools ■ Independent from Sling and OSGi – Versatile – Configurable – Embeddable 12
    19. 19. Agenda ■ Introduction ■ Requirements and goals ■ Challenges and solutions – Leverage existing tools – Passing arguments to scripts – Scalac and OSGi – Performance ■ Conclusion 13
    20. 20. Leverage existing tools ■ Scripts are valid Scala source entities ■ Tradeoff – ceremony package forum class html(args: htmlArgs) { import args._ // ... } ■ Advantages – Write, refactor and debug with Scala IDEs – Compile with Scala compiler – Unit testing 14
    21. 21. Unit testing class html(args: htmlArgs) { import args._ // further imports omitted println { <html> <body> <div id="Header"> Welcome to the { node("name") } forum { Calendar.getInstance.getTime } </div> <div id="Content"> { SearchBox.render(request) } { ThreadOverview.render(node) } </div> </body> </html> } } 15
    22. 22. Unit testing class html(args: htmlArgs) { import args._ class htmlArgs { // further imports omitted val node = new { println { def apply(name: String) = "Scala scripting" <html> <body> } <div id="Header"> val request = new { /* ... */ } Welcome to the { node("name") } forum { Calendar.getInstance.getTime } } </div> <div id="Content"> { SearchBox.render(request) } new html(new htmlArgs) { ThreadOverview.render(node) } </div> </body> </html> } } 15
    23. 23. Unit testing class html(args: htmlArgs) { import args._ class htmlArgs { // further imports omitted val node = new { println { def apply(name: String) = "Scala scripting" <html> <body> } <div id="Header"> val request = new { /* ... */ } Welcome to the { node("name") } forum { Calendar.getInstance.getTime } } </div> <div id="Content"> { SearchBox.render(request) } new html(new htmlArgs) { ThreadOverview.render(node) } </div> </body> </html> } <html> } <body> <div id="Header"> Welcome to the Scala scripting forum Tue Mar 16 19:46:38 CET 2010 </div> <div id="Content"> <!-- output omitted --> </div> </body> </html> 15
    24. 24. Passing arguments to Scripts class ResettableOutStream extends OutputStream implements Resettable { public void write(int b) throws IOException { /* ... */ } public void reset() { /* ... */ } } OutputStream getResetableOutputStream() { /* ... */ } bindings.put("output", getResetableOutputStream) engine.eval(script, bindings) class html(args: htmlArgs) { import args._ output.write(‘c’) output.reset() } 16
    25. 25. Passing arguments to Scripts class ResettableOutStream extends OutputStream implements Resettable { public void write(int b) throws IOException { /* ... */ } public void reset() { /* ... */ } } OutputStream getResetableOutputStream() { /* ... */ } bindings.put("output", getResetableOutputStream) engine.eval(script, bindings) Where are the types? class html(args: htmlArgs) { import args._ output.write(‘c’) output.reset() } 16
    26. 26. Passing arguments to Scripts class ResettableOutStream extends OutputStream implements Resettable { public void write(int b) throws IOException { /* ... */ } public void reset() { /* ... */ } } OutputStream getResetableOutputStream() { /* ... */ } bindings.put("output", getResetableOutputStream) engine.eval(script, bindings) Where are the types? class html(args: htmlArgs) { import args._ Bindings wrapper output.write(‘c’) provides static types output.reset() } 16
    27. 27. Bindings wrapper ■ No type information in javax.script.Bindings – Generate bindings wrapper exposing static types – Arguments appear to be of all accessible types – Implicit conversions to the rescue ■ Least accessible types – v: C, I1, ..., In – Expose v with static type D of least accessible super type of C – Expose v through implicit conversion to Ik if neither D nor any Im (m ≠ k) implements Ik. 17
    28. 28. Bindings wrapper (cont.) class ResettableOutStream extends OutputStream implements Resettable { public void write(int b) throws IOException { /* ... */ } public void reset() { /* ... */ } } OutputStream getResetableOutputStream() { /* ... */ } bindings.put("output", new ResettableOutStream) engine.eval(script, bindings) 18
    29. 29. Bindings wrapper (cont.) class ResettableOutStream extends OutputStream implements Resettable { public void write(int b) throws IOException { /* ... */ } public void reset() { /* ... */ } } OutputStream getResetableOutputStream() { /* ... */ } bindings.put("output", new ResettableOutStream) engine.eval(script, bindings) Bindings wrapper class htmlArgs(bindings: Bindings) { lazy val output = bindings.getValue("output").asInstanceOf[OutputStream] implicit def outputStream2Resettable(x: OutputStream): Resettable = x.asInstanceOf[Resettable] } 18
    30. 30. Bindings wrapper (cont.) class ResettableOutStream extends OutputStream implements Resettable { public void write(int b) throws IOException { /* ... */ } public void reset() { /* ... */ } } OutputStream getResetableOutputStream() { /* ... */ } bindings.put("output", new ResettableOutStream) engine.eval(script, bindings) Bindings wrapper class htmlArgs(bindings: Bindings) { lazy val output = bindings.getValue("output").asInstanceOf[OutputStream] implicit def outputStream2Resettable(x: OutputStream): Resettable = x.asInstanceOf[Resettable] } 18
    31. 31. Bindings wrapper (cont.) ■ Limitations – Scala’s visibility modifiers not exposed through reflection – Not yet working with parametrized types – Ambiguities in generated implicit conversion 19
    32. 32. Scalac and OSGi ■ Scalac – Requires compiler class path – File system based ■ OSGi – Provides class loaders – Bundle based ■ Bridging the gap – File system abstraction over OSGi bundles – Implement scala.tools.nsc.io.AbstractFile – Limitation: wiring probably not fully respected 20
    33. 33. Independent through configuration ■ Abstract implementation details into configuration class – Default implementation for standalone usage – Specialized implementations for Sling – Set through ScriptEngineFactory or injected via OSGi service lookup 21
    34. 34. Configuration ■ Scala compiler – Per script engine – scripting.scala.SettingsProvider – Class and output paths: scala.tools.nsc.io.AbstractFile – Settings: scala.tools.nsc.Settings – Reporting: scala.tools.nsc.reporters.Reporter ■ Script entry point – Per invocation – scripting.scala.ScriptInfo 22
    35. 35. Performance ■ On the fly compilation is slow – Cache pre compiled scripts – Dependency on bindings: include bindings wrapper – Work in progress 23
    36. 36. Conclusion ■ Scala is attractive for scripting – Concise and versatile – DSL capabilities – Type safe – XML literals for type safe templating ■ Impedance mismatches – JSR-223: dynamic vs. static typing – OSGi: runtime environment vs. compile time utility – Performance: illusion of executing source code 24
    37. 37. References ■ Scala for Scripting http://people.apache.org/~mduerig/scala4scripting/ ■ Apache Sling http://sling.apache.org/ ■ Michael Dürig michael.duerig@day.com ■ Day Software AG http://www.day.com/ 25
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×