scala for scripting

37
1 Scala for Scripting Implementing an OSGi enabled, JSR-223 compliant scripting engine for Scala http://people.apache.org/~mduerig/scala4scripting/ Michael Dürig [email protected] Day Software AG http://www.day.com/ Scala Days 2010 April 15th

Upload: day

Post on 18-May-2015

2.167 views

Category:

Technology


2 download

TRANSCRIPT

Page 1: Scala for scripting

1

Scala for Scripting

Implementing an OSGi enabled, JSR-223 compliant scripting engine for Scalahttp://people.apache.org/~mduerig/scala4scripting/

Michael Dürig [email protected]

Day Software AG http://www.day.com/

Scala Days 2010April 15th

Page 2: Scala for scripting

2

Agenda■ Introduction– Scripting with Scala– Scala for Apache Sling

■Requirements and goals

■Challenges and solutions■Conclusion

Page 3: Scala for scripting

3

Scripting with Scala■ (Illusion of) executing source code

■Concise and versatile*

■DSL capabilities

■ Type safe

*) Adapted from: Programming in Scala, Martin Odersky, Lex Spoon, Bill Venners. Artima, 2008.

var capitals = Map("Switzerland" -> "Bern", "Spain" -> "Madrid") capitals += ("France" -> "Paris")

val c = capitals.find(_._1 == "France") .map(_._2) .getOrElse("NIL")

Page 4: Scala for scripting

Scripting with Scala (cont.)

■ XML literals: type safe templating

4

<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>

Page 5: Scala for scripting

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

Page 6: Scala for scripting

Sling URL decomposition

X

GET /forum/scala4sling.html HTTP/1.1

Page 7: Scala for scripting

Sling URL decomposition

X

GET /forum/scala4sling.html HTTP/1.1

Page 8: Scala for scripting

Sling URL decomposition

X

GET /forum/scala4sling.html HTTP/1.1

Repository path

Page 9: Scala for scripting

Sling URL decomposition

X

GET /forum/scala4sling.html HTTP/1.1

Repository path

Application selection

Page 10: Scala for scripting

Sling URL decomposition

X

GET /forum/scala4sling.html HTTP/1.1

Repository path

Application selection

Script selection

Page 11: Scala for scripting

6

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> } }

Page 12: Scala for scripting

6

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> } }

Import bindings

Page 13: Scala for scripting

6

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> } }

Use arguments

Import bindings

Page 14: Scala for scripting

7

Agenda■ Introduction

■Requirements and goals – JSR-223 compliance– OSGi tolerant– Further design goals

■Challenges and solutions

■Conclusion

Page 15: Scala for scripting

8

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

Page 16: Scala for scripting

9

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)

Page 17: Scala for scripting

10

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

Page 18: Scala for scripting

11

Further design goals■ Leverage existing tools– Compilers– IDEs– Test suites– Documentation and reporting tools

■ Independent from Sling and OSGi– Versatile– Configurable – Embeddable

Page 19: Scala for scripting

12

Agenda■ Introduction

■Requirements and goals

■Challenges and solutions– Leverage existing tools– Passing arguments to scripts– Scalac and OSGi– Performance

■Conclusion

Page 20: Scala for scripting

13

Leverage existing tools■ Scripts are valid Scala source entities

■ Tradeoff – ceremony

■ Advantages–Write, refactor and debug with Scala IDEs– Compile with Scala compiler– Unit testing

package forum

class html(args: htmlArgs) { import args._ // ... }

Page 21: Scala for scripting

14

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> } }

Page 22: Scala for scripting

14

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> } }

class htmlArgs { val node = new { def apply(name: String) = "Scala scripting" } val request = new { /* ... */ } }

new html(new htmlArgs)

Page 23: Scala for scripting

14

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> } }

class htmlArgs { val node = new { def apply(name: String) = "Scala scripting" } val request = new { /* ... */ } }

new html(new htmlArgs)

<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>

Page 24: Scala for scripting

15

Passing arguments to Scripts

bindings.put("output", getResetableOutputStream) engine.eval(script, bindings)

class html(args: htmlArgs) { import args._

output.write(‘c’) output.reset() }

class ResettableOutStream extends OutputStream implements Resettable { public void write(int b) throws IOException { /* ... */ } public void reset() { /* ... */ } } OutputStream getResetableOutputStream() { /* ... */ }

Page 25: Scala for scripting

15

Passing arguments to Scripts

bindings.put("output", getResetableOutputStream) engine.eval(script, bindings)

class html(args: htmlArgs) { import args._

output.write(‘c’) output.reset() }

Where are the types?

class ResettableOutStream extends OutputStream implements Resettable { public void write(int b) throws IOException { /* ... */ } public void reset() { /* ... */ } } OutputStream getResetableOutputStream() { /* ... */ }

Page 26: Scala for scripting

15

Passing arguments to Scripts

bindings.put("output", getResetableOutputStream) engine.eval(script, bindings)

class html(args: htmlArgs) { import args._

output.write(‘c’) output.reset() }

Where are the types?

Bindings wrapper provides static types

class ResettableOutStream extends OutputStream implements Resettable { public void write(int b) throws IOException { /* ... */ } public void reset() { /* ... */ } } OutputStream getResetableOutputStream() { /* ... */ }

Page 27: Scala for scripting

16

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.

Page 28: Scala for scripting

17

Bindings wrapper (cont.)

bindings.put("output", new ResettableOutStream) engine.eval(script, bindings)

class ResettableOutStream extends OutputStream implements Resettable { public void write(int b) throws IOException { /* ... */ } public void reset() { /* ... */ } } OutputStream getResetableOutputStream() { /* ... */ }

Page 29: Scala for scripting

17

Bindings wrapper (cont.)

Bindings wrapper

bindings.put("output", new ResettableOutStream) engine.eval(script, bindings)

class htmlArgs(bindings: Bindings) { lazy val output = bindings.getValue("output").asInstanceOf[OutputStream] implicit def outputStream2Resettable(x: OutputStream): Resettable = x.asInstanceOf[Resettable] }

class ResettableOutStream extends OutputStream implements Resettable { public void write(int b) throws IOException { /* ... */ } public void reset() { /* ... */ } } OutputStream getResetableOutputStream() { /* ... */ }

Page 30: Scala for scripting

17

Bindings wrapper (cont.)

Bindings wrapper

bindings.put("output", new ResettableOutStream) engine.eval(script, bindings)

class htmlArgs(bindings: Bindings) { lazy val output = bindings.getValue("output").asInstanceOf[OutputStream] implicit def outputStream2Resettable(x: OutputStream): Resettable = x.asInstanceOf[Resettable] }

class ResettableOutStream extends OutputStream implements Resettable { public void write(int b) throws IOException { /* ... */ } public void reset() { /* ... */ } } OutputStream getResetableOutputStream() { /* ... */ }

Page 31: Scala for scripting

18

Bindings wrapper (cont.)

■ Limitations– Scala’s visibility modifiers not exposed through reflection– Not yet working with parametrized types– Ambiguities in generated implicit conversion

Page 32: Scala for scripting

19

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

Page 33: Scala for scripting

X

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

Page 34: Scala for scripting

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

X

Page 35: Scala for scripting

20

Performance■On the fly compilation is slow– Cache pre compiled scripts– Dependency on bindings: include bindings wrapper–Work in progress

Page 36: Scala for scripting

21

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

Page 37: Scala for scripting

22

References■ Scala for Scripting

http://people.apache.org/~mduerig/scala4scripting/

■ Apache Slinghttp://sling.apache.org/

■Michael Dü[email protected]■Day Software AG

http://www.day.com/