我正在使用Scala模板引擎(Scalate)在OSGi环境(Scala 2.9.1)中的运行时编译模板。这些模板是动态构建的,因此无法预编译。

为了使其工作,Scala编译器需要在OSGi环境中运行。但是,由于Scala编译器无法将类加载器作为输入,因此无法立即使用。

根据我的研究,似乎有两种通用的解决方法:

1)一个scala编译器插件(there is one started here,但自2009年以来没有被使用过,messages on the scala list in 2009表示尚未准备好用于生产。

2)在bundle上下文之上创建一个虚拟文件系统,然后Scala编译器可以使用它。显然,Apache Sling伙计们successfully在较旧的Scala版本上使用了这种方法。

有没有人得到Scalate,Scala 2.9.1和OSGi一起工作以动态地编译模板?

最佳答案

我的团队现在可以在OSGi中为Scalate进行Scala编译和执行。

通常,应为ScalaCompiler设置提供一组与相关OSGi软件包相对应的AbstractFile对象。 @michid引用的Guggla支持此功能。但是,尽管Guggla提供了AbstractFile层,但仍未提供任何示例或代码来说明如何在OSGi环境中创建AbstractFile实例。可以在Sling项目(Guggla本身的起源)以及Scalate项目(请参见ScalaCompiler,但请注意下面对我们所做的更改)中找到用于完成后者的示例代码。

我们从ServiceMix项目中选择了OSGi标准化的scala捆绑包(compilerlibrary)。请参阅scala-compiler软件包上的issue SMX-1048 (with patch)

我们最初的目的是使它在Scalate中工作,因此其余的答案专门针对该项目。

Scalate代码已经具有在OSGi环境中工作所需的大多数逻辑,包括虚拟AbstractFile层以及设置编译器类路径。但是,我们需要修补Scalate(https://github.com/scalate/scalate/pull/16)才能使其正常工作:

1)ScalaCompiler类的OsgiCompiler覆盖未正确启用,因此未将包的束检测为编译器的类路径输入,并且

2)模板执行(运行时)类加载器被设置为scalate-core捆绑软件的类加载器,导致CNFE在运行时出现。

上面的pull请求在OSGi环境中将Scalate配置为在运行时默认为线程上下文类加载器。这似乎是获得对调用方的类加载器的引用的最简单方法,而无需调用方必须显式注入它(例如,导出模板服务的Spring-DM osgi:service声明可以使用context-class-loader="service-provider"属性来自动设置此设置)这也使Scalate OSGi的运行时行为与已经使用TCCL的现有编译时行为相对应。

因此,Scalate的调用者应将TCCL设置为其自己的类加载器,或将所需的类加载器显式注入模板引擎,例如templateEngine.classLoader = ...在执行模板之前。

2012年8月31日更新:现在,Scalate Master包含本文中提到的所有补丁。

2013年4月10日更新:具有通过Scala编译器进行运行时模板编译的Scalate 1.6.1与OSGi兼容。 Scala 2.10及更高版本也是有效的OSGi软件包,已发布。

08-04 21:50