Added: sling/trunk/contrib/scripting/scala/script/src/main/scala/org/apache/sling/scripting/scala/interpreter/ScalaInterpreter.scala URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/scala/script/src/main/scala/org/apache/sling/scripting/scala/interpreter/ScalaInterpreter.scala?rev=905388&view=auto ============================================================================== --- sling/trunk/contrib/scripting/scala/script/src/main/scala/org/apache/sling/scripting/scala/interpreter/ScalaInterpreter.scala (added) +++ sling/trunk/contrib/scripting/scala/script/src/main/scala/org/apache/sling/scripting/scala/interpreter/ScalaInterpreter.scala Mon Feb 1 19:37:24 2010 @@ -0,0 +1,374 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +import scala.tools.nsc.{Settings, Global} +import scala.tools.nsc.interpreter.AbstractFileClassLoader +import scala.tools.nsc.io.AbstractFile +import scala.tools.nsc.reporters.Reporter +import scala.tools.nsc.util.{SourceFile, BatchSourceFile} +import java.net.URLClassLoader +import java.io.{File, InputStream, OutputStream} +import org.apache.sling.scripting.scala.Utils.{option} + +package org.apache.sling.scripting.scala.interpreter { + +/** + * An interpreter for Scala scripts. Interpretation of scripts proceeds in the following steps: + * <ol> + * <li>Pre-compilation: The source script is {...@link #preProcess} wrapped into a wrapper which + * contains variable definitions of the approproate types for the passed {...@link Bindings bindings}.</li> + * <li>Compilation: The resulting source code is {...@link #compile compiled} by the Scala compiler. </li> + * <li>Execution: The class file is {...@link #execute loaded} and its main method called.</li> + * </ol> + * @param settings compiler settings + * @param reporter reporter for compilation + * @param classes additional classes for the classpath + * @param outDir ourput directory for the compiler + */ +class ScalaInterpreter(settings: Settings, reporter: Reporter, classes: Array[AbstractFile], + outDir: AbstractFile) { + + /** + * Same as <code>ScalaInterpreter(settings, reporter, classes, null)</code>. + * @param settings + * @param reporter + * @param classes + * @return + */ + def this(settings: Settings, reporter: Reporter, classes: Array[AbstractFile]) = + this(settings, reporter, classes, null) + + /** + * Same as <code>ScalaInterpreter(settings, reporter, null, outDir)</code>. + * @param settings + * @param reporter + * @param outDir + * @return + */ + def this(settings: Settings, reporter: Reporter, outDir: AbstractFile) = + this(settings, reporter, null, outDir) + + /** + * Same as <code>ScalaInterpreter(settings, reporter, null, null)</code>. + * @param settings + * @param reporter + * @return + */ + def this(settings: Settings, reporter: Reporter) = + this(settings, reporter, null, null) + + /** + * The parent class loader used for execution + */ + protected val parentClassLoader: ClassLoader = getClass.getClassLoader + + /** + * The Scala compiler used for compilation + */ + protected val compiler: Global = { + val c = new ScalaCompiler(settings, reporter, classes) + if (outDir != null) c.genJVM.outputDir = outDir + c + } + + /** + * Generates a wrapper which contains variables declarations and implicit conversions + * to make the bindings visible on all accessible types. + * @param name name of the script. Used for generating the class name of the wrapper. + * @param code source code of the script + * @param bindings bindings to be passed to the script + * @return a valid Scala source + * @throws InterpreterException + */ + @throws(classOf[InterpreterException]) + protected def preProcess(name: String, code: String, bindings: Bindings): String = { + val NL: String = System.getProperty("line.separator") + + def packetize(name: String): List[String] = name.split('.').toList + def mangle(name: String) = packetize(name).mkString("_") + + def bind(arg: (String, AnyRef)) = { + val views = bindings.getViews(arg._2.getClass) + val className = views.head.getName + val implicits = + for { + view <- views.tail + intfName = view.getName + methName = mangle(className) + "2" + mangle(intfName) + } + yield + " implicit def " + methName + "(x: " + className + "): " + intfName + " = x.asInstanceOf[" + intfName + "]" + + " lazy val " + arg._1 + " = bindings.getValue(\"" + arg._1 + "\").asInstanceOf[" + className + "]" + NL + + implicits.mkString(NL) + } + + val compounds = packetize(name) + val className = compounds.last + + def packageDeclaration = + if (compounds.size > 1) compounds.init.mkString("package ", ".", "") + NL + else throw new InterpreterException("Default package not allowed: " + name) + + code + NL + + packageDeclaration + " {" + NL + + " class " + className + "Vars(bindings: org.apache.sling.scripting.scala.interpreter.Bindings) { " + NL + + bindings.map(bind).mkString(NL) + NL + + " } " + NL + + " object " + className + "Runner {" + NL + + " def main(bindings: org.apache.sling.scripting.scala.interpreter.Bindings," + NL + + " stdIn: java.io.InputStream," + NL + + " stdOut: java.io.OutputStream) {" + NL + + " Console.withIn(stdIn) {" + NL + + " Console.withOut(stdOut) {" + NL + + " new " + className + "(new " + className + "Vars(bindings))" + NL + + " stdOut.flush" + NL + + " }" + NL + + " }" + NL + + " }" + NL + + " }" + NL + + "}" + NL + } + + /** + * Compiles a list of source files. No pre-processing takes place. + * @param sources source files + * @return result of compilation + */ + protected def compile(sources: List[SourceFile]): Reporter = { + reporter.reset + val run = new compiler.Run + if (reporter.hasErrors) + reporter + else { + run.compileSources(sources) + reporter + } + } + + /** + * Compiles a single source file. No pre-processing takes place. + * @param name name of the script + * @param code source code + * @return result of compilation + */ + def compile(name: String, code: String): Reporter = + compile(List(new BatchSourceFile(name, code.toCharArray))) + + /** + * Pre-processes and compiles a single source file. + * @param name name of the script + * @param code source code + * @param bindings variable bindings to pass to the script + * @return result of compilation + */ + def compile(name: String, code: String, bindings: Bindings): Reporter = + compile(name, preProcess(name, code, bindings)) + + /** + * Compiles a single source file. No pre-processing takes place. + * @param sources source file + * @return result of compilation + */ + def compile(source: AbstractFile): Reporter = { + compile(List(new BatchSourceFile(source))) + } + + /** + * Pre-processes and compiles a single source file. + * @param name name of the script + * @param source source file + * @param bindings variable bindings to pass to the script + * @return result of compilation + */ + def compile(name: String, source: AbstractFile, bindings: Bindings): Reporter = { + val code = new String(source.toByteArray) + compile(name, preProcess(name, code, bindings)) + } + + /** + * Interprete a script + * @param name name of the script + * @param code source code + * @param bindings variable bindings to pass to the script + * @param in stdIn for the script execution + * @param out stdOut for the script execution + * @return result of execution + * @throws InterpreterException + */ + @throws(classOf[InterpreterException]) + def interprete(name: String, code: String, bindings: Bindings, in: Option[InputStream], + out: Option[OutputStream]): Reporter = { + compile(name, code, bindings) + if (reporter.hasErrors) + reporter + else { + execute(name, bindings, in, out) + } + } + + /** + * Same as <code>interprete(name, code, bindings, None, None)</code>. + * @param name name of the script + * @param code source code + * @param bindings variable bindings to pass to the script + * @return result of execution + * @throws InterpreterException + */ + @throws(classOf[InterpreterException]) + def interprete(name: String, code: String, bindings: Bindings): Reporter = + interprete(name, code, bindings, None, None) + + /** + * Same as <code>interprete(name, code, bindings, Some(in), Some(out))</code>. + * @param name name of the script + * @param code source code + * @param bindings variable bindings to pass to the script + * @param in stdIn for the script execution + * @param out stdOut for the script execution + * @return result of execution + * @throws InterpreterException + */ + @throws(classOf[InterpreterException]) + def interprete(name: String, code: String, bindings: Bindings, in: InputStream, + out: OutputStream): Reporter = + interprete(name, code, bindings, option(in), option(out)) + + /** + * Interprete a script + * @param name name of the script + * @param source source file + * @param bindings variable bindings to pass to the script + * @param in stdIn for the script execution + * @param out stdOut for the script execution + * @return result of execution + * @throws InterpreterException + */ + @throws(classOf[InterpreterException]) + def interprete(name: String, source: AbstractFile, bindings: Bindings, in: Option[InputStream], + out: Option[OutputStream]): Reporter = { + compile(name, source, bindings) + if (reporter.hasErrors) + reporter + else { + execute(name, bindings, in, out) + } + } + + /** + * Same as <code>interprete(name, code, bindings, None, None)</code>. + * @param name name of the script + * @param source source file + * @param bindings variable bindings to pass to the script + * @return result of execution + * @throws InterpreterException + */ + @throws(classOf[InterpreterException]) + def interprete(name: String, source: AbstractFile, bindings: Bindings): Reporter = + interprete(name, source, bindings, None, None) + + /** + * Same as <code>interprete(name, code, bindings, Some(in), Some(out))</code>. + * @param name name of the script + * @param source source file + * @param bindings variable bindings to pass to the script + * @param in stdIn for the script execution + * @param out stdOut for the script execution + * @return result of execution + * @throws InterpreterException + */ + @throws(classOf[InterpreterException]) + def interprete(name: String, source: AbstractFile, bindings: Bindings, in: InputStream, + out: OutputStream): Reporter = + interprete(name, source, bindings, option(in), option(out)) + + /** + * Looks up the class file for a compiled script + * @param name script name + * @return the class file or null if not found + */ + def getClassFile(name: String): AbstractFile = { + var file: AbstractFile = compiler.genJVM.outputDir + val pathParts = name.split("[./]").toList + for (dirPart <- pathParts.init) { + file = file.lookupName(dirPart, true) + if (file == null) { + return null + } + } + file.lookupName(pathParts.last + ".class", false) + } + + /** + * Executes a compiled script + * @param name name of the script + * @param bindings variable bindings to pass to the script + * @param in stdIn for the script execution + * @param out stdOut for the script execution + * @return result of execution + * @throws InterpreterException when class files cannot be accessed or nor entry point is found + */ + @throws(classOf[InterpreterException]) + def execute(name: String, bindings: Bindings, in: Option[InputStream], out: Option[OutputStream]): Reporter = { + try { + val classLoader = new AbstractFileClassLoader(compiler.genJVM.outputDir, parentClassLoader) + val script = Class.forName(name + "Runner", true, classLoader) + val initMethod = (script + .getDeclaredMethods + .toList + .find(method => method.getName == "main") + .get) + + initMethod.invoke(null, Array(bindings, in.getOrElse(java.lang.System.in), + out.getOrElse(java.lang.System.out)): _*) + reporter + } + catch { + case e: java.lang.reflect.InvocationTargetException => + throw new InterpreterException("Error executing " + name, e.getTargetException) + case e: Exception => + throw new InterpreterException("Error executing " + name, e) + } + } + + /** + * Same as <code>execute(name, bindings, None, None)</code>. + * @param name name of the script + * @param bindings variable bindings to pass to the script + * @return result of execution + * @throws InterpreterException when class files cannot be accessed or nor entry point is found + */ + @throws(classOf[InterpreterException]) + def execute(name: String, bindings: Bindings): Reporter = + execute(name, bindings, None, None) + + /** + * Same as <code>execute(name, bindings, Some(in), Some(out))</code>. + * @param name name of the script + * @param bindings variable bindings to pass to the script + * @param in stdIn for the script execution + * @param out stdOut for the script execution + * @return result of execution + * @throws InterpreterException when class files cannot be accessed or nor entry point is found + */ + @throws(classOf[InterpreterException]) + def execute(name: String, bindings: Bindings, in: InputStream, out: OutputStream): Reporter = + execute(name, bindings, option(in), option(out)) + +} + + +} \ No newline at end of file
Added: sling/trunk/contrib/scripting/scala/script/src/main/scala/org/apache/sling/scripting/scala/interpreter/ScalaSettings.scala URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/scala/script/src/main/scala/org/apache/sling/scripting/scala/interpreter/ScalaSettings.scala?rev=905388&view=auto ============================================================================== --- sling/trunk/contrib/scripting/scala/script/src/main/scala/org/apache/sling/scripting/scala/interpreter/ScalaSettings.scala (added) +++ sling/trunk/contrib/scripting/scala/script/src/main/scala/org/apache/sling/scripting/scala/interpreter/ScalaSettings.scala Mon Feb 1 19:37:24 2010 @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +import scala.tools.nsc.Settings + +package org.apache.sling.scripting.scala.interpreter { + +/** + * Utility to parse Scala compiler settings from a string. This class + * can be used from Java instead of Settings. Settings is not accessible + * from Java since scala.Nothing is not visible exposed. + * See https://lampsvn.epfl.ch/trac/scala/ticket/1254 + */ +class ScalaSettings(error: String => Unit) extends Settings(error) { + def this() = this(Console.println) + + def parse(line: String) = { + def error(s: String): Nothing = throw new InterpreterException(s) + parseParams(line, error) + } + +} + +} Added: sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/JcrFSTest.scala URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/JcrFSTest.scala?rev=905388&view=auto ============================================================================== --- sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/JcrFSTest.scala (added) +++ sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/JcrFSTest.scala Mon Feb 1 19:37:24 2010 @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +import java.io.{PrintWriter, InputStreamReader} +import javax.jcr.{Session, Repository, Node, SimpleCredentials} +import junit.framework.TestCase +import junit.framework.Assert.{assertEquals, assertTrue, assertFalse} +import org.apache.sling.scripting.scala.JcrFS.{JcrNode, JcrFile, JcrFolder} +import org.apache.jackrabbit.core.{TransientRepository} + +package org.apache.sling.scripting.scala { + +class JcrFSTest extends TestCase { + var session: Session = null + var repository: Repository = null + var testRoot: Node = null + + override def setUp() { + super.setUp() + repository = new TransientRepository + session = repository.login(new SimpleCredentials("admin", "admin".toCharArray)) + testRoot = session.getRootNode.addNode("testRoot", "nt:folder") + session.save() + } + + override def tearDown() { + testRoot.remove() + testRoot = null + session.save() + session.logout() + session = null + repository = null + super.tearDown() + } + + def testTraverse: Unit = { + def traverse(entry: JcrNode): String = { + (for (entry <- entry.elements) yield {entry match { + case file: JcrFile => file.path + case folder: JcrFolder => folder.path + traverse(folder) + }}) + .mkString("(", ",", ")") + } + + var _id = 0 + def id() = { + _id += 1 + _id + } + + def addChildren(folder: Node) = { + folder.addNode("file" + id(), "nt:file") + folder.addNode("file" + id(), "nt:file") + (folder.addNode("folder" + id(), "nt:folder"), folder.addNode("folder" + id(), "nt:folder")) + } + + val (f1, f2) = addChildren(testRoot) + val (f3, f4) = addChildren(f1) + addChildren(f2) + addChildren(f3) + addChildren(f4) + val actual = traverse(JcrFS.create(testRoot)) + val expected = + "(/testRoot/file1,/testRoot/file2,/testRoot/folder3(/testRoot/folder3/file5,/testRoot/folder3/file6," + + "/testRoot/folder3/folder7(/testRoot/folder3/folder7/file13,/testRoot/folder3/folder7/file14," + + "/testRoot/folder3/folder7/folder15(),/testRoot/folder3/folder7/folder16())," + + "/testRoot/folder3/folder8(/testRoot/folder3/folder8/file17,/testRoot/folder3/folder8/file18," + + "/testRoot/folder3/folder8/folder19(),/testRoot/folder3/folder8/folder20()))," + + "/testRoot/folder4(/testRoot/folder4/file9,/testRoot/folder4/file10,/testRoot/folder4/folder11()," + + "/testRoot/folder4/folder12()))" + assertEquals(expected, actual) + } + + def testCreateFile { + val root = JcrFS.create(testRoot) + val file = root.fileNamed("file") + val fileNode = testRoot.getNode("file") + assertFalse(file.isDirectory) + assertEquals("nt:file", fileNode.getPrimaryNodeType.getName) + assertEquals("file", file.name) + assertEquals("/testRoot/file", file.path) + assertEquals(fileNode.getProperty("jcr:content/jcr:lastModified").getLong, file.lastModified) + assertEquals(fileNode.getProperty("jcr:content/jcr:data").getLength, file.sizeOption.get.toLong) + + val contentNode = fileNode.getNode("jcr:content") + assertEquals("nt:resource", contentNode.getPrimaryNodeType.getName) + + val input = file.input + assertEquals(0, input.available) + assertEquals(-1, input.read) + } + + def testCreateFolder { + val root = JcrFS.create(testRoot) + val folder = root.subdirectoryNamed("folder") + val folderNode = testRoot.getNode("folder") + assertTrue(folder.isDirectory) + assertEquals(0L, folder.lastModified) + assertEquals("nt:folder", folderNode.getPrimaryNodeType.getName) + assertEquals("folder", folder.name) + assertEquals("/testRoot/folder", folder.path) + } + + def testParent { + val root = JcrFS.create(testRoot) + val folder = root.subdirectoryNamed("folder") + val file = folder.fileNamed("file") + assertEquals(folder, file.container) + } + + def testReadWriteContent { + val root = JcrFS.create(testRoot) + val file = root.fileNamed("file") + val contentNode = testRoot.getNode("file/jcr:content") + + val writer = new PrintWriter(file.output) + writer.print("Hello world") + writer.close + assertEquals("Hello world", contentNode.getProperty("jcr:data").getString) + assertEquals(11, file.sizeOption.get) + + val reader = new InputStreamReader(file.input) + val c = new Array[char](32) + reader.read(c) + assertEquals("Hello world", new String(c, 0, 11)) + } + +} + +} Added: sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/ScalaScriptEngineFactoryTest.scala URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/ScalaScriptEngineFactoryTest.scala?rev=905388&view=auto ============================================================================== --- sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/ScalaScriptEngineFactoryTest.scala (added) +++ sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/ScalaScriptEngineFactoryTest.scala Mon Feb 1 19:37:24 2010 @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +import javax.script.{ + ScriptEngine, + ScriptEngineFactory} + +import junit.framework.TestCase +import junit.framework.Assert._ + +package org.apache.sling.scripting.scala { + +class ScalaScriptEngineFactoryTest extends TestCase { + + def testScriptEngineFactoryInit() { + val scalaEngineFactory = new ScalaScriptEngineFactory + assertNotNull(scalaEngineFactory) + } + + def testScriptEngineFactoryEngine() { + try { + val scriptEngine = (new ScalaScriptEngineFactory).getScriptEngine + assertNotNull(scriptEngine) + } + catch { + case e: IllegalStateException => // expected + } + } + + def testScriptEngineFactoryLanguage() { + val language = (new ScalaScriptEngineFactory).getLanguageName + assertEquals("Scala", language) + } + + def testScriptEngineFactoryLanguageVersion() { + val version = (new ScalaScriptEngineFactory).getLanguageVersion() + assertEquals("2.7.7", version) + } + +} + +} \ No newline at end of file Added: sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/interpreter/InterpreterHelper.scala URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/interpreter/InterpreterHelper.scala?rev=905388&view=auto ============================================================================== --- sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/interpreter/InterpreterHelper.scala (added) +++ sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/interpreter/InterpreterHelper.scala Mon Feb 1 19:37:24 2010 @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +import java.io.{ByteArrayOutputStream, IOException, BufferedReader, FileReader, File} +import java.net.URISyntaxException + +import javax.script.ScriptException + +import org.apache.sling.scripting.scala.interpreter.{ScalaInterpreter, Bindings} + +import scala.tools.nsc.Settings +import scala.tools.nsc.io.AbstractFile +import scala.tools.nsc.reporters.Reporter + +package org.apache.sling.scripting.scala.interpreter { + +/** + * Helper class for evaluating Scala scripts. + */ +class InterpreterHelper(val srcDir: AbstractFile, val outDir: AbstractFile) { + require(srcDir != null) + require(outDir != null) + + val interpreter: ScalaInterpreter = createInterpreter + + private val interpreterOut = new ByteArrayOutputStream + + @throws(classOf[ScriptException]) + def eval(name: String, code: String, bindings: Bindings): String = { + try { + interpreterOut.reset + val result = interpreter.interprete(name, code, bindings, null, interpreterOut) + if (result.hasErrors) throw new ScriptException(result.toString()) + interpreterOut.toString + } + catch { + case e: Exception => throw new ScriptException(e) + } + } + + @throws(classOf[ScriptException]) + def eval(name: String, src: AbstractFile, bindings: Bindings) = { + try { + interpreterOut.reset + val result = interpreter.interprete(name, src, bindings, null, interpreterOut) + if (result.hasErrors) throw new ScriptException(result.toString()) + interpreterOut.toString + } + catch { + case e: Exception => throw new ScriptException(e) + } + } + + // -----------------------------------------------------< protected >--- + + protected def getSettings: Settings = new Settings(); + protected def getClasspath: String = System.getProperty("java.class.path") + protected def getReporter(settings: Settings): Reporter = new BacklogReporter(settings); + + protected def createInterpreter: ScalaInterpreter = { + val settings = getSettings + settings.classpath.value = getClasspath + new ScalaInterpreter(settings, getReporter(settings), outDir) + } + +} + +} \ No newline at end of file Added: sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/interpreter/InterpreterTest.scala URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/interpreter/InterpreterTest.scala?rev=905388&view=auto ============================================================================== --- sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/interpreter/InterpreterTest.scala (added) +++ sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/interpreter/InterpreterTest.scala Mon Feb 1 19:37:24 2010 @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +import java.io.File + +import junit.framework.TestCase + +import org.apache.sling.scripting.scala.Utils.valueOrElse + +import scala.tools.nsc.io.PlainFile + +package org.apache.sling.scripting.scala.interpreter { + +/** + * Standard test cases where files are read/written to/from the file system. + */ +class InterpreterTest extends TestCase with Tests { + + var interpreterHelper: InterpreterHelper = null; + + override def setUp() { + super.setUp(); + + val workDir = new PlainFile(new File("target")).subdirectoryNamed("tmp") + val srcDir = workDir.subdirectoryNamed("src") + val outDir = workDir.subdirectoryNamed("classes") + + interpreterHelper = new InterpreterHelper(srcDir, outDir) { + override def getClasspath = valueOrElse(System.getProperty("surefire.test.class.path")) { + super.getClasspath + } + } + } + + override def tearDown() { + super.tearDown() + interpreterHelper = null + } + +} + +} \ No newline at end of file Added: sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/interpreter/InterpreterWithJcrTest.scala URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/interpreter/InterpreterWithJcrTest.scala?rev=905388&view=auto ============================================================================== --- sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/interpreter/InterpreterWithJcrTest.scala (added) +++ sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/interpreter/InterpreterWithJcrTest.scala Mon Feb 1 19:37:24 2010 @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +import javax.jcr.Node +import javax.jcr.SimpleCredentials +import javax.jcr.Session + +import junit.framework.TestCase +import junit.framework.Assert.assertEquals + +import org.apache.jackrabbit.core.TransientRepository + +import org.apache.sling.scripting.scala.Utils.valueOrElse +import org.apache.sling.scripting.scala.JcrFS + +package org.apache.sling.scripting.scala.interpreter { + +/** + * JCR based test cases where files are read/written to/from a JCR repository + * (Apache Jackrabbit). + */ +class InterpreterWithJcrTest extends TestCase with Tests { + var interpreterHelper: InterpreterHelper = null + var repository: TransientRepository = null + var session: Session = null + var workNode: Node = null + + override def setUp() { + super.setUp(); + + repository = new TransientRepository + session = repository.login(new SimpleCredentials("admin", "admin".toCharArray)) + val rootNode = session.getRootNode + workNode = rootNode.addNode("scala_tests", "nt:folder"); + workNode.getSession().save(); + val workDir = JcrFS.create(workNode); + val srcDir = workDir.subdirectoryNamed("src") + val outDir = workDir.subdirectoryNamed("classes") + + interpreterHelper = new InterpreterHelper(srcDir, outDir) { + override def getClasspath = valueOrElse(System.getProperty("surefire.test.class.path")) { + super.getClasspath + } + } + } + + override def tearDown() { + interpreterHelper = null + session.logout() + repository.shutdown + repository = null + super.tearDown() + } + + def testNodeAccess() { + val code = "package a { class Testi(vars: TestiVars) { import vars._; print(n.getPath)}}" + val bindings = Bindings() + bindings.putValue("n", workNode) + assertEquals(workNode.getPath, interpreterHelper.eval("a.Testi", code, bindings)) + } + +} + +} \ No newline at end of file Added: sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/interpreter/Tests.scala URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/interpreter/Tests.scala?rev=905388&view=auto ============================================================================== --- sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/interpreter/Tests.scala (added) +++ sling/trunk/contrib/scripting/scala/script/src/test/scala/org/apache/sling/scripting/scala/interpreter/Tests.scala Mon Feb 1 19:37:24 2010 @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +import junit.framework.Assert.{assertEquals, assertFalse, fail} + +import java.io.PrintWriter + +import javax.script.ScriptException + +package org.apache.sling.scripting.scala.interpreter { + +/** + * Generic test cases. Implementors inject an InterpreterHelper instance. + */ +trait Tests { + var interpreterHelper: InterpreterHelper + + def testEvalString { + val code = "package a { class Testi(vars: TestiVars) { print(1 + 2) }}" + assertEquals("3", interpreterHelper.eval("a.Testi", code, Bindings())) + } + + def testEvalError { + val code = "syntax error" + try { + interpreterHelper.eval("a.Testi", code, Bindings()) + fail("Expecting ScriptException") + } + catch { + case _: ScriptException => // expected + } + } + + def testError { + val err = "Some error here"; + val code = "package a { class Testi(vars: TestiVars) { throw new Error(\"" + err + "\") }}" + try { + interpreterHelper.eval("a.Testi", code, Bindings()) + fail("Expecting Exception") + } + catch { + case e: ScriptException if err == e.getCause.getCause.getMessage => // expected + } + } + + def testScalaInterpreter { + val bindings = Bindings() + val time = java.util.Calendar.getInstance.getTime + bindings.putValue("msg", "Hello world") + bindings.putValue("time", time) + val code = "package a { class Testi(vars: TestiVars) {import vars._; print(msg + \": \" + time)}}" + val result = interpreterHelper.eval("a.Testi", code, bindings) + assertEquals("Hello world: " + time, result) + } + + def testCompileExecute { + val srcDir = interpreterHelper.srcDir + val interpreter = interpreterHelper.interpreter + + val bindings = Bindings() + val time = java.util.Calendar.getInstance.getTime + bindings.putValue("msg", "Hello world") + bindings.putValue("time", time) + + val code = "package a { class Testi(vars: TestiVars) {import vars._; print(msg + \": \" + time)}}" + val src = srcDir.fileNamed("Testi.scala") + val writer = new PrintWriter(src.output) + writer.print(code) + writer.close + + val out = new java.io.ByteArrayOutputStream + var result = interpreter.compile("a.Testi", src, bindings) + assertFalse(result.hasErrors) + + result = interpreter.execute("a.Testi", bindings, None, Some(out)) + assertFalse(result.hasErrors) + + assertEquals("Hello world: " + time, out.toString) + } + +} + +} \ No newline at end of file