How to load the modified classes which has been imported to scalate without jetty-restart?

144 views
Skip to first unread message

Freewind

unread,
Mar 11, 2011, 2:57:14 AM3/11/11
to Scalate
I am using scalate as my view templates, and sbt + jrebel. But I found
if the classes imported to scalate has been modified, we have to
restart jetty, or there may be complication errors.

The code is pretty simple:

webapp/WEB-INF/web.xml

<web-app version="2.5">
<filter>
<filter-name>TemplateEngineFilter</filter-name>
<filter-
class>org.fusesource.scalate.servlet.TemplateEngineFilter</filter-
class>
</filter>
<filter-mapping>
<filter-name>TemplateEngineFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

src/main/scala/test.scala

package test

object A {
def a() = "AAA"
}


webapp/index.jade


- import test.A._
= a()

Disable jetty's auto-reload

class TestProject(info: ProjectInfo) extends
DefaultWebProject(info) {
override val scanDirectories = Nil
}

Then start jetty:

> sbt
> jetty-run
> ~prepare-webapp

Visit home page:

http://localhost:8080/

It displays correct:

AAA

Then I modify the `test.scala` as:

package test

object A {
def a() = "AAA#######"
}

Visit page again, correct:

AAA#######

Then modify the method name:

package test

object A {
def b() = "AAA#######"
}

and `index.jade` invoke `b()`:

- import test.A._
= b()

Visit again, show error:

Server Error: We're sorry, but something went wrong.
We've been notified about this issue and we'll take a look at it
shortly.

From this sample we don't know where is wrong, but in my another
project, we can see the reason: Failed compiling index.jade, value
`b()` is not found

So I have to restart jetty:

> jetty-restart

Visit again, and everything goes well.


How to fix this issue, or is there any other way to work with scalate
without restarting?

James Strachan

unread,
Mar 11, 2011, 4:51:09 AM3/11/11
to sca...@googlegroups.com
BTW if you specify scalate dev mode you get the full stack trace on
errors rather than the 'production' style message you saw. Set the
scalate.mode=dev system property (or see the system properties used in
the jetty plugin in the pom.xml files in the archetypes or samples in
scalate).

I thought JRebel should be able to reload any class if a dependent
class is reloaded? i.e. the class of the template should be
automatically reloaded by JRebel.

Maybe its because the classes for the templates are generated in a
different directory to the other classes. e.g. in the sample maven web
app projects in Scalate (e.g. scalate/samples/scalate-sample/) we
specify the scalate.workdir system property to be "target/_scalate" so
that the generated classes go into "target/_scalate/classes". I wonder
if you add that directory to the list of directories that JRebel
monitors, it'll correctly reload the class for the template if its
dependencies change?

Failing that we might need a JRebel plugin for Scalate - but I would
have hoped JRebel is capable of figuring out class changes & reloading
properly.

--
James
-------
FuseSource
Email: ja...@fusesource.com
Web: http://fusesource.com
Twitter: jstrachan
Blog: http://macstrac.blogspot.com/

Open Source Integration

Freewind

unread,
Mar 11, 2011, 10:35:41 PM3/11/11
to Scalate
I guess the reason is because normal classes are compiled by sbt(with
jrebel), but templates are compiled by scalate itself.

Maybe they use different classloaders? So scalate can't get the
modified classes without jetty-restart?

On 3月11日, 下午5时51分, James Strachan <ja...@fusesource.com> wrote:
> BTW if you specify scalate dev mode you get the full stack trace on
> errors rather than the 'production' style message you saw. Set the
> scalate.mode=dev system property (or see the system properties used in
> the jetty plugin in the pom.xml files in the archetypes or samples in
> scalate).
>
> I thought JRebel should be able to reload any class if a dependent
> class is reloaded? i.e. the class of the template should be
> automatically reloaded by JRebel.
>
> Maybe its because the classes for the templates are generated in a
> different directory to the other classes. e.g. in the sample maven web
> app projects in Scalate (e.g. scalate/samples/scalate-sample/) we
> specify the scalate.workdir system property to be "target/_scalate" so
> that the generated classes go into "target/_scalate/classes". I wonder
> if you add that directory to the list of directories that JRebel
> monitors, it'll correctly reload the class for the template if its
> dependencies change?
>
> Failing that we might need a JRebel plugin for Scalate - but I would
> have hoped JRebel is capable of figuring out class changes & reloading
> properly.
>

James Strachan

unread,
Mar 12, 2011, 3:50:25 AM3/12/11
to sca...@googlegroups.com
Scalate uses a child classloader of the same parent classloader to be
able to load the classes for the templates. My guess is JRebel is not
aware of the classloader or directory of template class files.

So we probably need a JRebel plugin for scalate. I guess there is one
for JSP already?

James Strachan

unread,
Mar 14, 2011, 7:19:04 AM3/14/11
to sca...@googlegroups.com
On 11 March 2011 09:51, James Strachan <ja...@fusesource.com> wrote:
> BTW if you specify scalate dev mode you get the full stack trace on
> errors rather than the 'production' style message you saw. Set the
> scalate.mode=dev system property (or see the system properties used in
> the jetty plugin in the pom.xml files in the archetypes or samples in
> scalate).

BTW dev mode shows the Scalate console which also has a "Clear Cache"
option to flush the template cache without restarting Jetty.
http://scalate.fusesource.org/documentation/console.html

James Strachan

unread,
Mar 14, 2011, 7:20:03 AM3/14/11
to sca...@googlegroups.com
I created an issue to track this
http://www.assembla.com/spaces/scalate/support/tickets/228

I've created a Scalate JRebel plugin in master. Just add
scalate-jrebel to your classpath then it gets notified when JRebel
reloads a class; it then flushes all the cached compiled templates so
that they are all reloaded properly.

If using the maven build in Scalate (and assuming JREBEL_HOME
environment variable points to your jrebel install), you can do

cd samples/scalate-sample
./run -Pjrebel

to run the sample in JRebel reloading mode with scalate-jrebel
enabled. If in another shell you type

cd samples/scalate-sample
mvn scala:cc

Then start hacking the scala code, you should see Scalate log that its
flushing its caches.


The current scalate-jrebel plugin is pretty pessimistic; it flushes
all compiled templates when any class reloads in JRebel.

Ideally the more optimal solution would be for JRebel to be aware of
the Scalate class loader and directory of src and classes so that only
required templates should be reloaded.

Maybe another more optimal solution could be to detect which Scalate
templates are affected by JRebel class changes using JRebel APIs?
However at least the basics should work; if you change some code and
JRebel reloads it, you won't have to restart Jetty.


On 11 March 2011 09:51, James Strachan <ja...@fusesource.com> wrote:

Freewind

unread,
Mar 14, 2011, 8:19:57 AM3/14/11
to Scalate
@James, thank you so much!

I just tried to use sbt + jsp + jrebel, and found the same problem: if
a class has been imported to jsp has been changed, although jrebel has
loaded, jsp can't be compiled if it uses a new method in the new
version of that class.

I'm not sure where is the problem now. May be just because I use sbt?
I think I should try scalate + jetty + jrebel, without sbt.

I will post the result here after I tried

On 3月14日, 下午7时20分, James Strachan <ja...@fusesource.com> wrote:
> I created an issue to track thishttp://www.assembla.com/spaces/scalate/support/tickets/228

James Strachan

unread,
Mar 14, 2011, 8:32:19 AM3/14/11
to sca...@googlegroups.com, Freewind
Make sure you add a dependency on scalate-jrebel when trying scalate +
jrebel out - should work in sbt and mvn.

Remember you've always the Scalate console as a workaround until you
figure out your configuration & enviromment; you just need to set the
"scalate.mode" system property to "dev" when running Jetty.

2011/3/14 Freewind <nowi...@gmail.com>:

Reply all
Reply to author
Forward
0 new messages