Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set up classpath for the Scala interpreter in a managed environment?

I am working on an extension for the Apache Wicket web framework, which lets the user execute code in several programming languages at runtime from the browser. One of these languages is Scala, but I am having trouble when it is bundled as a WAR file and deployed to a container such as Tomcat.

When the Scala interpreter is invoked, it refuses to run the code with the following message:

Failed to initialize compiler: object scala not found.
** Note that as of 2.8 scala does not assume use of the java classpath.
** For the old behavior pass -usejavacp to scala, or if using a Settings
** object programatically, settings.usejavacp.value = true.

After setting up usejavacp on the Scala settings, it still didn't work in a managed environment. The problem seems to be that the Scala interpreter cannot find the Scala library jars on the Java class path.

Searching the web, I found a proposal, which proposes the use of two classpath resouces named 'boot.class.path' and 'app.class.path', which should include the needed classpath declarations. I tried this and it seemed to work. My problem with this solution, though, is that my extension is meant to get bundled into a WAR file and to be run in different environments, so it would be necessary for the user to modifiy these resources with respect to the environment it runs in. Also it would be a lot of work to include every single jar's path into the file.

Maybe I don't understand fully the proposal. Does anybody know of a solution for this?

like image 758
cretzel Avatar asked Jul 27 '11 05:07

cretzel


2 Answers

I have managed to embed scala 2.9.1 within a war running in tomcat.

This is how I did it.

val code = """println("Hi");""";

val settings = new Settings
val compilerPath = java.lang.Class.forName("scala.tools.nsc.Interpreter").getProtectionDomain.getCodeSource.getLocation
val libPath = java.lang.Class.forName("scala.Some").getProtectionDomain.getCodeSource.getLocation

println("compilerPath=" + compilerPath);
println("settings.bootclasspath.value=" + settings.bootclasspath.value);

settings.bootclasspath.value = List(settings.bootclasspath.value, compilerPath, libPath) mkString java.io.File.pathSeparator    
settings.usejavacp.value = true
val interpreter = new IMain(settings)

interpreter.interpret(code);

Just for the search engines. These were my exceptions before it worked.

    Failed to initialize compiler: object scala not found.
    ** Note that as of 2.8 scala does not assume use of the java classpath.
    ** For the old behavior pass -usejavacp to scala, or if using a Settings
    ** object programatically, settings.usejavacp.value = true.

and

    Exception in thread "Thread-26" java.lang.Error: typeConstructor inapplicable for <none>
            at scala.tools.nsc.symtab.SymbolTable.abort(SymbolTable.scala:34)
            at scala.tools.nsc.symtab.Symbols$Symbol.typeConstructor(Symbols.scala:877)
            at scala.tools.nsc.symtab.Definitions$definitions$.scala$tools$nsc$symtab$Definitions$definitions$$booltype(Definitions.scala:157)
            at scala.tools.nsc.symtab.Definitions$definitions$.init(Definitions.scala:814)
            at scala.tools.nsc.Global$Run.<init>(Global.scala:697)
            at scala.tools.nsc.interpreter.IMain.scala$tools$nsc$interpreter$IMain$$_initialize(IMain.scala:114)
            at scala.tools.nsc.interpreter.IMain$$anonfun$initialize$1.apply$mcZ$sp(IMain.scala:127)
            at scala.tools.nsc.interpreter.IMain$$anonfun$initialize$2.apply(IMain.scala:126)
            at scala.tools.nsc.interpreter.IMain$$anonfun$initialize$2.apply(IMain.scala:126)
            at scala.concurrent.ThreadRunner$$anon$2$$anonfun$run$2.apply(ThreadRunner.scala:45)
            at scala.concurrent.ThreadRunner.scala$concurrent$ThreadRunner$$tryCatch(ThreadRunner.scala:31)
            at scala.concurrent.ThreadRunner$$anon$2.run(ThreadRunner.scala:45)
            at java.lang.Thread.run(Thread.java:662)
like image 130
Peter Henderson Avatar answered Oct 13 '22 07:10

Peter Henderson


You could try to build and set the classpath manually:

val setting = new scala.tools.nsc.settings.MutableSettings(println(_))
settings.classpath.append("my/path")

and pass this Settings instance to the Scala compiler.

like image 31
michid Avatar answered Oct 13 '22 09:10

michid