So, I am constructing some server logic in my webapp where it would be very
useful to know when the WebAppContext is being shut down. Basically, I need to
cleanly release resources...
I have been attempting to do this by writing a LifeCycle object, implementing
org.eclipse.jetty.util.component.LifeCycle, and then in my jetty-web.xml
deploying this to the WebAppContext using the addManaged method;
<Call name="addManaged">
<Arg><New id="mg" class="test.LifecycleObject"/></Arg>
</Call>
Based on what I have seen so far, this feels like a decent approach for how to
do this. I could also do this, using a LifeCycle.Listener and the
addLifeCycleListener method, but I see the same problem described below using
both approaches.
The problem I am having is that the call to addManaged fails,
java.lang.IllegalStateException: No Method: <Call name="addManaged"><Arg><New
id="mg" class="test.LifecycleObject"/></Arg></Call> on class
org.eclipse.jetty.webapp.WebAppContext
at
org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.call(XmlConfiguration.java:738)
at
org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.configure(XmlConfiguration.java:417)
at
org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.configure(XmlConfiguration.java:298)
...Caused by:
java.lang.NoSuchMethodException: addManaged
at org.eclipse.jetty.util.TypeUtil.call(TypeUtil.java:537)
at
org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.call(XmlConfiguration.java:730)
at
org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.configure(XmlConfiguration.java:417)...
My object that implements the LifeCycle interface is attached.
Ultimately, the problem appears to be classloader incompatabilities... When I
run the whole process in the debugger and put a breakpoint in the call method
of XmlConfiguration and then interrogate the objects involved just before the
call is passed in to TypeUtil.call() on the line;
Object n= TypeUtil.call(oClass,method,obj,arg);
I am seeing the following;
oClass.getName() -> org.eclipse.jetty.webapp.WebAppContext
arg[0].getClass() -> class test.LifecycleObject
arg[0].getClass().getInterfaces() -> [interface
org.eclipse.jetty.util.component.LifeCycle]
so I have ther right objects and my LifecycleObject class does implement the
right interface. But,
LifeCycle.class.isInstance(arg[0]) -> false
This clearly explains the call failure... When I dig closer, I see that the
LifeCycle.class object is loaded with server class loader and my
LifecycleObject is loaded with the web app context class loader.
LifeCycle.class.getClassLoader() ->
startJarLoader@217e9fe8arg[0].getClass().getClassLoader() ->
WebAppClassLoader=84066694@502c186
I get why this does not work, I am just trying to figure out how I should be
doing this... What I am trying to do seems like a pretty common use case, so I
figure someone else has solved this already. Besides I am getting tired of
banging my head on the wall!
I have tried this with my LifecycleObject class in my war file for my webapp as
well as having it in a jar file loaded using the --lib option when I start the
server. I get the same results both ways, so the class loaded seems to be
driven purely based on the fact the instance is created using <New> in the
jetty-web.xml.
Note that I am seeing all of this with Jetty 9.2.6.
I appreciate any suggestions anyone can give!
Thanks,
Scott
package test;
import org.apache.log4j.Logger;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.webapp.WebAppContext;
public class LifecycleObject implements LifeCycle {
public enum RunState {
STOPPED, STARTING, STARTED, STOPPING, FAILED;
}
private static final Logger LOG = Logger.getLogger(LifecycleObject.class);
private RunState m_state = RunState.STOPPED;
public LifecycleObject() {
LOG.debug("construction");
}
public static void registerStatic(final WebAppContext wac,
final LifecycleObject obj) {
wac.addManaged(obj);
}
@Override
public void start() throws Exception {
LOG.debug("start");
m_state = RunState.STARTING;
m_state = RunState.STARTED;
}
@Override
public void stop() throws Exception {
LOG.debug("stop");
m_state = RunState.STOPPING;
m_state = RunState.STOPPED;
}
@Override
public boolean isRunning() {
LOG.debug("isRunning");
if (m_state == RunState.STARTED) {
return true;
} else {
return false;
}
}
@Override
public boolean isStarted() {
LOG.debug("isStarted");
if (m_state == RunState.STARTED) {
return true;
} else {
return false;
}
}
@Override
public boolean isStarting() {
LOG.debug("isStarting");
if (m_state == RunState.STARTING) {
return true;
} else {
return false;
}
}
@Override
public boolean isStopping() {
LOG.debug("isStopping");
if (m_state == RunState.STOPPING) {
return true;
} else {
return false;
}
}
@Override
public boolean isStopped() {
LOG.debug("isStopped");
if (m_state == RunState.STOPPED) {
return true;
} else {
return false;
}
}
@Override
public boolean isFailed() {
LOG.debug("isFailed");
if (m_state == RunState.FAILED) {
return true;
} else {
return false;
}
}
@Override
public void addLifeCycleListener(Listener listener) {
LOG.debug("addLifeCycleListener");
}
@Override
public void removeLifeCycleListener(Listener listener) {
LOG.debug("removeLifeCycleListener");
}
}
_______________________________________________
jetty-users mailing list
[email protected]
To change your delivery options, retrieve your password, or unsubscribe from
this list, visit
https://dev.eclipse.org/mailman/listinfo/jetty-users