Author: reto
Date: Fri Nov 19 18:05:01 2010
New Revision: 1036963

URL: http://svn.apache.org/viewvc?rev=1036963&view=rev
Log:
faster compiler service with shared compiler, using it in ScriptEngineFactory

Modified:
    
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/resources/OSGI-INF/serviceComponents.xml
    
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/CompilerService.scala
    
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/ScriptEngineFactory.scala
    
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/TrackingCompiler.scala
    
incubator/clerezza/trunk/scala-scripting/tests/src/test/scala/org/apache/clerezza/scala/tests/CompilerServiceTest.scala

Modified: 
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/resources/OSGI-INF/serviceComponents.xml
URL: 
http://svn.apache.org/viewvc/incubator/clerezza/trunk/scala-scripting/script-engine/src/main/resources/OSGI-INF/serviceComponents.xml?rev=1036963&r1=1036962&r2=1036963&view=diff
==============================================================================
--- 
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/resources/OSGI-INF/serviceComponents.xml
 (original)
+++ 
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/resources/OSGI-INF/serviceComponents.xml
 Fri Nov 19 18:05:01 2010
@@ -29,6 +29,10 @@
                                
interface="org.apache.clerezza.scala.scripting.InterpreterFactory"
                                cardinality="1..1"
                                bind="bindInterpreterFactory" 
unbind="unbindInterpreterFactory"/>
+               <reference name="CompilerService"
+                               
interface="org.apache.clerezza.scala.scripting.CompilerService"
+                               cardinality="1..1"
+                               bind="bindCompilerService" 
unbind="unbindCompilerService"/>
     </scr:component>
        <!-- <scr:component enabled="true" immediate="true" 
name="org.apache.clerezza.scala.scripting.Launcher">
         <implementation class="org.apache.clerezza.scala.scripting.Launcher"/>

Modified: 
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/CompilerService.scala
URL: 
http://svn.apache.org/viewvc/incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/CompilerService.scala?rev=1036963&r1=1036962&r2=1036963&view=diff
==============================================================================
--- 
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/CompilerService.scala
 (original)
+++ 
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/CompilerService.scala
 Fri Nov 19 18:05:01 2010
@@ -25,6 +25,8 @@ import org.apache.clerezza.scala.scripti
 import org.apache.clerezza.scala.scripting.util.GenericFileWrapperTrait
 import org.apache.clerezza.scala.scripting.util.VirtualDirectoryWrapper
 import org.osgi.framework.BundleContext
+import org.osgi.framework.BundleEvent
+import org.osgi.framework.BundleListener
 import org.osgi.service.component.ComponentContext;
 import scala.tools.nsc._;
 import scala.tools.nsc.interpreter._;
@@ -34,21 +36,55 @@ import scala.tools.nsc.reporters.Console
 import scala.tools.nsc.util._
 import java.io.ByteArrayOutputStream
 import java.io.File
+import java.io.IOException
+import java.io.OutputStream
 import java.io.PrintWriter
 import java.io.Reader
 import java.net._
 
+class CompileErrorsException(message: String) extends Exception(message) {
+       def this() = this(null)
+}
+
+class CompilerService() extends BundleListener  {
 
-class CompilerService() {
-       
        protected var bundleContext : BundleContext = null;
+       protected val sharedVirtualDirectory = new VirtualDirectory("(memory)", 
None)
+       protected var currentSharedCompilerOutputStream: OutputStream = null
+       protected val splipptingOutputStream = new OutputStream() {
+               def write(b: Int) {
+                       if (currentSharedCompilerOutputStream == null) {
+                               throw new IOException("no 
currentSharedCompilerOutputStream set")
+                       }
+                       currentSharedCompilerOutputStream.write(b)
+               }
+       }
+       protected val splittingPrintWriter = new 
PrintWriter(splipptingOutputStream, true)
+
+       protected var currentSharedCompiler: TrackingCompiler = null;
+       protected def sharedCompiler = {
+               if (currentSharedCompiler == null) {
+                       synchronized {
+                               if (currentSharedCompiler == null) {
+                                       currentSharedCompiler = 
createCompiler(splittingPrintWriter, sharedVirtualDirectory)
+                               }
+                       }
+               }
+               currentSharedCompiler
+       }
 
        def activate(componentContext: ComponentContext)= {
                bundleContext = componentContext.getBundleContext
+               bundleContext.addBundleListener(this)
        }
 
        def deactivate(componentContext: ComponentContext) = {
-               bundleContext = null
+               currentSharedCompiler = null
+               bundleContext.removeBundleListener(this)
+       }
+
+       def bundleChanged(event: BundleEvent) = {
+               currentSharedCompiler = null
        }
 
        def createCompiler(out: PrintWriter, outputSirectory: AbstractFile) : 
TrackingCompiler = {
@@ -56,15 +92,39 @@ class CompilerService() {
        }
 
        def compile(sources: List[Array[Char]]): List[Class[_]] = {
+               sharedCompiler.synchronized {
+                       val baos = new ByteArrayOutputStream
+                       currentSharedCompilerOutputStream = baos
+                       try {
+                               sharedCompiler.compile(sources)
+                       } catch {
+                               case c: CompileErrorsException => throw new 
CompileErrorsException(
+                                               new String(baos.toByteArray, 
"utf-8"))
+                               case e => throw e
+                       } finally {
+                               currentSharedCompilerOutputStream = null
+                       }
+               }
+       }
+
+       /**
+        * compiles a set of sources with a dedicated compiler
+        */
+       def compileIsolated(sources: List[Array[Char]]): List[Class[_]] = {
                val virtualDirectory = new VirtualDirectory("(memory)", None)
-               compile(sources, virtualDirectory)
+               compileIsolated(sources, virtualDirectory)
        }
 
-       def compile(sources: List[Array[Char]], outputDirectory: AbstractFile): 
List[Class[_]] = {
+       def compileIsolated(sources: List[Array[Char]], outputDirectory: 
AbstractFile): List[Class[_]] = {
                val out = new ByteArrayOutputStream
                val printWriter = new PrintWriter(out)
                val compiler = createCompiler(printWriter, outputDirectory)
-               compiler.compile(sources)
+               try {
+                       compiler.compile(sources)
+               } catch {
+                       case c: CompileErrorsException => throw new 
CompileErrorsException(new String(out.toByteArray, "utf-8"))
+                       case e => throw e
+               }
        }
 
        

Modified: 
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/ScriptEngineFactory.scala
URL: 
http://svn.apache.org/viewvc/incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/ScriptEngineFactory.scala?rev=1036963&r1=1036962&r2=1036963&view=diff
==============================================================================
--- 
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/ScriptEngineFactory.scala
 (original)
+++ 
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/ScriptEngineFactory.scala
 Fri Nov 19 18:05:01 2010
@@ -43,8 +43,6 @@ import scala.tools.nsc.interpreter._;
 import scala.tools.nsc.util._
 import scala.tools.nsc.io.VirtualDirectory
 import scala.tools.nsc.reporters.ConsoleReporter
-import scala.tools.nsc.reporters.ConsoleReporter
-import scala.tools.nsc.reporters.ConsoleReporter
 import scala.actors.Actor
 import scala.actors.Actor._
 
@@ -55,7 +53,8 @@ class ScriptEngineFactory() extends  Jav
                MyScriptEngine.interpreterAction ! 
ScriptEngineFactory.RefreshInterpreter
        }
 
-       var factory: InterpreterFactory = null
+       private var factory: InterpreterFactory = null
+       private var compilerService: CompilerService = null
        var _interpreter : Interpreter = null;
        private var bundleContext: BundleContext = null
        def interpreter = {
@@ -115,6 +114,14 @@ class ScriptEngineFactory() extends  Jav
                factory = null
                _interpreter = null
        }
+
+       def bindCompilerService(s: CompilerService) = {
+               compilerService  = s
+       }
+
+       def unbindCompilerService(s: CompilerService) = {
+               compilerService  = null
+       }
        /** Inner object as it accesse interpreter
         */
        object MyScriptEngine extends AbstractScriptEngine() with Compilable {
@@ -202,75 +209,48 @@ class ScriptEngineFactory() extends  Jav
                val virtualDirectory = new VirtualDirectory("(memory)", None)
                var msgWriter = new StringWriter
 
-               val classLoader = new AbstractFileClassLoader(virtualDirectory, 
this.getClass.getClassLoader())
 
-               //var classLoader = createClassLoader
-
-               lazy val compiler = {
-                       AccessController.doPrivileged(new 
PrivilegedAction[BundleContextScalaCompiler]() {
-                               override def run() =  {
-                                       val settings = new Settings     
-                                       settings.outputDirs setSingleOutput 
virtualDirectory
-                                       val out = new PrintWriter(System.out)
-                                       new 
BundleContextScalaCompiler(bundleContext, settings,                             
                                               
-                                               new ConsoleReporter(settings, 
null, out) {
-                                                       override def 
printMessage(msg: String) {
-                                                               msgWriter write 
msg
-                                                               //out.flush()
-                                                       }
-                                               })
-                               }
-                       })
-               }
                
                override def compile(script: String): CompiledScript = {
                        try {
                                AccessController.doPrivileged(new 
PrivilegedAction[CompiledScript]() {
-                               override def run() =  {
+                                       override def run() =  {
+                                               val objectName = 
"CompiledScript"+classCounter
+                                               classCounter += 1
+                                               val classCode = "class " + 
objectName + """ {
+                                                       |       def run($: 
Map[String, Object]) = {
+                                                       |""".stripMargin + 
script +"""
+                                                       |       }
+                                                       |}""".stripMargin
+                                                       val sources: 
List[Array[Char]] = List(classCode.toCharArray)
+                                               val clazz = try {
+                                                       
compilerService.compile(sources)(0)
+                                               } catch {
+                                                       case e: 
CompileErrorsException => throw new ScriptException(e.getMessage, "script", -1);
+                                                       case e => throw e
+                                               }
+                                               val scriptObject = 
clazz.newInstance()
 
-                                               //inefficient but thread safe
-                                               compiler.synchronized {
-                                                       val objectName = 
"CompiledScript"+classCounter
-                                                       classCounter += 1
-                                                       val classCode = "class 
" + objectName + """ {
-                                                               |       def 
run($: Map[String, Object]) = {
-                                                               
|""".stripMargin + script +"""
-                                                               |       }
-                                                               
|}""".stripMargin
-                                                       val sources: 
List[SourceFile] = List(new BatchSourceFile("<script>", classCode))
-                                                       (new 
compiler.Run).compileSources(sources)
-                                                       if 
(compiler.reporter.hasErrors) {
-                                                               
compiler.reporter.reset
-                                                               val msg = 
msgWriter.toString
-                                                               msgWriter = new 
StringWriter
-                                                               throw new 
ScriptException(msg, "script", -1);
-                                                       }
-                                                       //val classBytes = 
virtualDirectory.fileNamed(objectName+".class").toCharArray
-                                                       val clazz = 
classLoader.loadClass(objectName)
-                                                       val scriptObject = 
clazz.newInstance()
-
-                                                       new CompiledScript() {
-
-                                                               override def 
eval(context: ScriptContext) = {
-       
-                                                                       var map 
= Map[String, Object]()
-                                                                       import 
_root_.scala.collection.JavaConversions._
-                                                                       for (   
scope <- context.getScopes;
-                                                                               
        if (context.getBindings(scope.intValue) != null);
-                                                                               
        entry <- context.getBindings(scope.intValue)) {
-                                                                               
map = map + (entry._1 -> entry._2)
-                                                                       }
-                                                                       val 
runMethod = clazz.getMethod("run", classOf[Map[String, Object]])
-                                                                       try {
-                                                                               
runMethod.invoke(scriptObject, map)
-                                                                       } catch 
{
-                                                                               
case e: InvocationTargetException => {
-                                                                               
        throw e.getCause
-                                                                               
}
+                                               new CompiledScript() {
+                                                       override def 
eval(context: ScriptContext) = {
+
+                                                               var map = 
Map[String, Object]()
+                                                               import 
_root_.scala.collection.JavaConversions._
+                                                               for (   scope 
<- context.getScopes;
+                                                                               
if (context.getBindings(scope.intValue) != null);
+                                                                               
entry <- context.getBindings(scope.intValue)) {
+                                                                       map = 
map + (entry._1 -> entry._2)
+                                                               }
+                                                               val runMethod = 
clazz.getMethod("run", classOf[Map[String, Object]])
+                                                               try {
+                                                                       
runMethod.invoke(scriptObject, map)
+                                                               } catch {
+                                                                       case e: 
InvocationTargetException => {
+                                                                               
throw e.getCause
                                                                        }
                                                                }
-                                                               override def 
getEngine = MyScriptEngine.this
                                                        }
+                                                       override def getEngine 
= MyScriptEngine.this
                                                }
                                        }
                                })

Modified: 
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/TrackingCompiler.scala
URL: 
http://svn.apache.org/viewvc/incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/TrackingCompiler.scala?rev=1036963&r1=1036962&r2=1036963&view=diff
==============================================================================
--- 
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/TrackingCompiler.scala
 (original)
+++ 
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/TrackingCompiler.scala
 Fri Nov 19 18:05:01 2010
@@ -35,6 +35,7 @@ import java.io.ByteArrayOutputStream
 import java.io.PrintWriter
 import java.net._
 
+
 /** a compiler that keeps track of classes added to the directory
  */
 class TrackingCompiler private (bundleContext : BundleContext,
@@ -47,13 +48,14 @@ class TrackingCompiler private (bundleCo
        /**
         * compiles a list of class sources returning a list of compiled classes
         */
+       @throws(classOf[CompileErrorsException])
        def compile(sources: List[Array[Char]]): List[Class[_]] = {
                writtenClasses.clear()
                val sourceFiles: List[SourceFile] = for(chars <- sources) yield 
new BatchSourceFile("<script>", chars)
                (new Run).compileSources(sourceFiles)
                if (reporter.hasErrors) {
                        reporter.reset
-                       throw new RuntimeException("compile errors, see 
output");
+                       throw new CompileErrorsException;
                } 
                val classLoader = new AbstractFileClassLoader(outputDirectory, 
this.getClass.getClassLoader())
                val result: List[Class[_]] = for (classFile <- 
writtenClasses.toList;
@@ -101,7 +103,7 @@ object TrackingCompiler {
                        }
                new TrackingCompiler(bundleContext,
                         settings,
-                        new ConsoleReporter(null, null, out) {
+                        new ConsoleReporter(settings, null, out) {
                                override def printMessage(msg: String) {
                                        out write msg
                                        out.flush()

Modified: 
incubator/clerezza/trunk/scala-scripting/tests/src/test/scala/org/apache/clerezza/scala/tests/CompilerServiceTest.scala
URL: 
http://svn.apache.org/viewvc/incubator/clerezza/trunk/scala-scripting/tests/src/test/scala/org/apache/clerezza/scala/tests/CompilerServiceTest.scala?rev=1036963&r1=1036962&r2=1036963&view=diff
==============================================================================
--- 
incubator/clerezza/trunk/scala-scripting/tests/src/test/scala/org/apache/clerezza/scala/tests/CompilerServiceTest.scala
 (original)
+++ 
incubator/clerezza/trunk/scala-scripting/tests/src/test/scala/org/apache/clerezza/scala/tests/CompilerServiceTest.scala
 Fri Nov 19 18:05:01 2010
@@ -33,8 +33,6 @@ import org.junit.Before;
 import org.junit.Test;
 import org.ops4j.pax.exam.Inject;
 import org.osgi.framework.BundleContext;
-import java.io.Reader
-import java.io.StringReader
 import org.osgi.util.tracker.ServiceTracker
 import scala.actors.Actor
 import scala.math.random
@@ -73,27 +71,47 @@ class CompilerServiceTest {
 
        @Test
        def checkEngine(): Unit =  {
-
-               Assert.assertNotNull(service)
-               val s = """
-               package foo {
-                       class TestClass() {
-                               println("constructing TestClass");
+               Assert.assertNotNull(service);
+               //do it once
+               {
+                       val s = """
+                       package foo {
+                               class TestClass() {
+                                       println("constructing TestClass");
+                               }
+                               object TestClass {
+                                       println("constructing TestClass 
Object");
+                                       val msg = "Hello"
+                               }
                        }
-                       object TestClass {
-                               println("constructing TestClass Object");
-                               val msg = "Hello"
+                       """
+                       val compileResult = service.compile(List(s.toCharArray))
+                       println("finished compiling")
+                       Assert.assertEquals(1, compileResult.size)
+                       val testClassClass: Class[_] = compileResult(0)
+                       Assert.assertEquals("foo.TestClass", 
testClassClass.getName)
+                       val method = testClassClass.getMethod("msg")
+                       Assert.assertEquals("Hello", method.invoke(null))
+               }
+               //compile different class with same name
+               {
+                       val s = """
+                       package foo {
+                               class TestClass() {
+                                       println("constructing a different 
TestClass");
+                               }
+                               object TestClass {
+                                       println("constructing TestClass 
Object");
+                                       val msg = "Hello2"
+                               }
                        }
+                       """
+                       val compileResult = service.compile(List(s.toCharArray))
+                       val testClassClass: Class[_] = compileResult(0)
+                       Assert.assertEquals("foo.TestClass", 
testClassClass.getName)
+                       val method = testClassClass.getMethod("msg")
+                       Assert.assertEquals("Hello2", method.invoke(null))
                }
-               """
-               println("now compiling")
-               val compileResult = service.compile(List(s.toCharArray))
-               println("finished compiling")
-               Assert.assertEquals(1, compileResult.size)
-               val testClassClass: Class[_] = compileResult(0)
-               Assert.assertEquals("foo.TestClass", testClassClass.getName)
-               val method = testClassClass.getMethod("msg")
-               Assert.assertEquals("Hello", method.invoke(null))
        }
 
        @Test
@@ -108,8 +126,9 @@ class CompilerServiceTest {
                                def act() {
                                        try {
                                                for (i <- 1 to iterationsCount) 
{
-                                                       val objectName = 
"C"+(for (i <-1 to 12) yield 
((random*('z'-'a'+1))+'a').asInstanceOf[Char]).mkString
-                                                       val message = "Hello 
from "+objectName
+                                                       val uniqueToken = (for 
(i <-1 to 12) yield ((random*('z'-'a'+1))+'a').asInstanceOf[Char]).mkString
+                                                       val objectName = 
"MyClass"
+                                                       val message = "Hello 
from "+uniqueToken
 
                                                        val source = """
 object """+objectName+""" {


Reply via email to