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

Reply via email to