Realtime class update

O

O.L.

Hello,

I have a standalone Java application which has to be started and then
not stopped for weeks.
Is it possible to rebuild some of its classes and reload then inside
the running JVM, to be able to modify its behaviour without having to
stop and restart the application ?
I heard about ClassLoader and its caching functionnality ... ?

Thank you if you have any info :)
Olivier
 
A

Andrew Thompson

O.L. wrote:
...
I have a standalone Java application which has to be started and then
not stopped for weeks.
Is it possible to rebuild some of its classes and reload then inside
the running JVM, to be able to modify its behaviour without having to
stop and restart the application ?

Not that I know of, but happy to be surpised.
I heard about ClassLoader and its caching functionnality ... ?

'aggressively' is how I would describe CL caching.
Thank you if you have any info :)

Have you considered web start* for this application?

Web start offers the DownloadService** that can check if
Jar's are updated.

This would still leave it up to the application to
a) check occasionally for upates
b) update the necesary parts or Jar archives.
c) inform the user they need to RESTART THE APP.

c) might not be necessary if you find some really
clever way to update the classes in the current
ClassLoader.

** <http://java.sun.com/javase/6/docs/jre/api/javaws/jnlp/javax/jnlp/DownloadService.html
* Gee, color everybody 'surprised'!

--
Andrew Thompson
http://www.athompson.info/andrew/

Message posted via JavaKB.com
http://www.javakb.com/Uwe/Forums.aspx/java-general/200707/1
 
R

Roedy Green

I have a standalone Java application which has to be started and then
not stopped for weeks.
Is it possible to rebuild some of its classes and reload then inside
the running JVM, to be able to modify its behaviour without having to
stop and restart the application ?
I heard about ClassLoader and its caching functionnality ... ?

This is tricky. Basically what you must do is fire up a new
ClassLoader. any class A objects created via class A reloaded are
considered logically distinct from the original class A objects. You
still have the problem of converting objects to the new format.
See http://mindprod.com/jgloss/classloader.html
 
L

Lew

Andrew said:
O.L. wrote:
...

Not that I know of, but happy to be surpised.

Then be happy. It's possible using the debugger hooks. There was an article
by Daniel Savarese in JavaPro about it, probably still findable.

You can also play ClassLoader games to load the new version, letting the old
one die and get garbage collected, but getting client classes to recognize the
switch is hard, from what I hear. I tend to avoid such complications.
 
P

Piotr Kobzda

Lew said:
Then be happy. It's possible using the debugger hooks. There was an
article by Daniel Savarese in JavaPro about it, probably still findable.

I didn't found it. But now (since 1.5) the instrumentation allows it also:
<http://java.sun.com/javase/6/docs/a...sses(java.lang.instrument.ClassDefinition...)>

The only JVM I know, which fully supports it (including "schema change"
HotSwap) is the J9VM (from IBM).

Fortunately, most of major JVMs allows for redefining executable code of
a class, which usually is enough. If not enough...
You can also play ClassLoader games to load the new version, letting the
old one die and get garbage collected, but getting client classes to
recognize the switch is hard, from what I hear. I tend to avoid such
complications.

It depends on what is expected. Sometimes it's also desired to have the
old clients still using old versions of the classes, and a new classes
available for the new clients only (see "Hot Code Changes" section at
Java Glossary page linked by Roedy). Otherwise, you may reference all
objects non-directly, e.g. via the map (or cache). But, of course,
using instrumentation (or JPDA) is easier in such a case.


piotr
 
T

Twisted

Then be happy. It's possible using the debugger hooks. There was an article
by Daniel Savarese in JavaPro about it, probably still findable.

You can also play ClassLoader games to load the new version, letting the old
one die and get garbage collected, but getting client classes to recognize the
switch is hard, from what I hear.

If you only want newly created objects to use the new version of the
class, you could create these objects via a Factory that uses
reflection to dynamically load the latest class version if newer than
what it's currently using, and then to generate an instance of the
current version (whether that was just updated or not), when invoked.
 
O

O.L.

Il se trouve que Twisted a formulé :
If you only want newly created objects to use the new version of the
class, you could create these objects via a Factory that uses
reflection to dynamically load the latest class version if newer than
what it's currently using, and then to generate an instance of the
current version (whether that was just updated or not), when invoked.

Thank you :)

I suppose this will cause problems with 'instanceof' and old/new
instances, but I think this is the best (and only) solution.
 
P

Piotr Kobzda

O.L. said:
Piotr Kobzda a formulé la demande :

How ?

As I said -- using Java instrumentation.

With that, you will not have to care about class loading and references
to them, you will need simply replace already running classes with
theirs new bytes (loaded or generated at runtime).

For details refer to:
<http://java.sun.com/javase/6/docs/technotes/guides/instrumentation/index.html>

In particular, read the java.lang.instrument package description. Usage
is explained there clearly.


piotr
 
T

Twisted

I suppose this will cause problems with 'instanceof' and old/new
instances, but I think this is the best (and only) solution.

Use instanceof on a common supertype, e.g. have WhateverBase and make
WhateverDerived1, WhateverDerived2, etc. be your versions. If they
adhere to a common contract checking for being "instanceof
WhateverBase" should suffice where you are forced somehow to use
instanceof and not polymorphism.

Maybe equals()? Define that in WhateverBase in terms of contract
methods if possible. If you must do special stuff depending on exact
implementation, make WhateverBase have a getVersion method and write:

(in WhateverBase)

public final boolean equals (Object o) {
if (this == o) return true;
if (o == null || !(o instanceof WhateverBase)) return false;
WhateverBase wb = (WhateverBase)o;
if (wb.getVersion() > getVersion()) return wb.equalsImpl(this);
return equalsImpl(wb);
}

protected abstract int getVersion ();

protected abstract boolean equalsImpl (WhateverBase wb);

(in WhateverDerived1)

protected int getVersion () { return 1; }
protected boolean equalsImpl (WhateverBase wb) {
WhateverDerived1 wd = (WhateverDerived1)wb;
// Whatever to compare two WhateverDerived1s
return something;
}

(in WhateverDerived2)

protected int getVersion () { return 2; }
protected boolean equalsImpl (WhateverBase wb) {
if (wb instanceof WhateverDerived1) return
equalsImpl2((WhateverDerived1)wb);
WhateverDerived2 wd = (WhateverDerived2)wb;
// Whatever to compare two WhateverDerived2s
return something;
}
private boolean equalsImpl2 (WhateverDerived1 wd) {
// Whatever to compare a WD2 and a WD1
return something;
}

I trust you see the pattern here. The key thing is to assign version
numbers sequentially. Each class needs to know how to compare itself
to each previous version, and needs its equalsImpl to be the one that
gets called. If you do otherwise the code will break -- it will
sometimes call an old version equalsImpl with a newer version
parameter and consequently throw a ClassCastException on the last cast
in the called equalsImpl method.

This is assuming all the WDs extend WB directly, never each other,
which I'll also recommend to ensure the CCE is thrown instead of
subtler broken behavior occurring instead, such as simply wrong return
values from some calls to equals().

This can be generalized to anything else that needs to effectively
dispatch on two run-time types and not just one. It won't be nearly as
easy or tidy however if you end up with two different serially-
versioned types and a binary operation between them...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,430
Messages
2,571,676
Members
48,796
Latest member
Greg L.

Latest Threads

Top