-
1. Re: Lifecycle stop() method and new objects
dmlloyd Nov 27, 2008 2:08 PM (in response to gcompienne)Are you setting up explicit classloader dependencies via jboss-classloading.xml? If not, how are you setting up your classloaders?
-
2. Re: Lifecycle stop() method and new objects
alesj Nov 27, 2008 2:16 PM (in response to gcompienne)The classloader should be there,
since we only remove it from BMD once it's uninstalled:
- http://anonsvn.jboss.org/repos/jbossas/projects/jboss-deployers/trunk/deployers-vfs/src/main/java/org/jboss/deployers/vfs/deployer/kernel/BeanMetaDataDeployer.java
In deployment phase it's removed here:
- http://anonsvn.jboss.org/repos/jbossas/projects/jboss-deployers/trunk/deployers-impl/src/main/java/org/jboss/deployers/plugins/classloading/AbstractLevelClassLoaderSystemDeployer.java
I'm not saying its impossible, but I doubt it's us. ;-)
Since this would already pop-up, like you said,
some stop/destroy method needs to do something.
Perhaps you don't have your dependencies right,
and something snatches cl from the bean,
w/o properly unwinding/uninstalling it? -
3. Re: Lifecycle stop() method and new objects
alesj Nov 27, 2008 2:18 PM (in response to gcompienne)"alesj" wrote:
I'm not saying its impossible, but I doubt it's us. ;-)
This doesn't mean I won't consider/accept a test case. :-) -
4. Re: Lifecycle stop() method and new objects
gcompienne Nov 28, 2008 6:35 AM (in response to gcompienne)At the moment I must admit I haven't defined any dependencies metadata as everything is self contained in a single small jar file. Do I still need to define them? (admittedly I kind of relied on the JAR structure deployer to define the default CL going with a JAR...)
The sample is a simple telnet echo server. If I connect to the echo server the "Handler" object gets created fine. And then if I delete the JAR, the bean is also undeployed fine.
Now, if I deploy and then immediately undeploy the JAR (without connecting to the telnet server) then I have a NoClassDefFoundError that occurs during the undeploy stage (typically when I try the close down any Handlers if any but to do that the code needs to create one dummy Handler...).
Here is the stack trace:11:17:53,876 WARN [StartStopLifecycleAction] Error during stop for Controler java.lang.NoClassDefFoundError: mcfproto/impl/Handler at mcfproto.impl.NetServer.closeAll(NetServer.java:110) at mcfproto.impl.NetServer.stop(NetServer.java:72) at mcfproto.impl.ControlerImpl.stop(ControlerImpl.java:20) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.jboss.reflect.plugins.introspection.ReflectionUtils.invoke(ReflectionUtils.java:59) at org.jboss.reflect.plugins.introspection.ReflectMethodInfoImpl.invoke(ReflectMethodInfoImpl.java:150) at org.jboss.joinpoint.plugins.BasicMethodJoinPoint.dispatch(BasicMethodJoinPoint.java:66) at org.jboss.kernel.plugins.dependency.KernelControllerContextAction$JoinpointDispatchWrapper.execute(KernelCont rollerContextAction.java:241) at org.jboss.kernel.plugins.dependency.ExecutionWrapper.execute(ExecutionWrapper.java:47) at org.jboss.kernel.plugins.dependency.KernelControllerContextAction.dispatchExecutionWrapper(KernelControllerCo ntextAction.java:109) at org.jboss.kernel.plugins.dependency.KernelControllerContextAction.dispatchJoinPoint(KernelControllerContextAc tion.java:70) at org.jboss.kernel.plugins.dependency.LifecycleAction.uninstallActionInternal(LifecycleAction.java:249) at org.jboss.kernel.plugins.dependency.InstallsAwareAction.uninstallAction(InstallsAwareAction.java:157) at org.jboss.kernel.plugins.dependency.InstallsAwareAction.uninstallAction(InstallsAwareAction.java:42) at org.jboss.dependency.plugins.action.SimpleControllerContextAction.simpleUninstallAction(SimpleControllerConte xtAction.java:79) at org.jboss.dependency.plugins.action.AccessControllerContextAction.uninstall(AccessControllerContextAction.jav a:131) at org.jboss.dependency.plugins.AbstractControllerContextActions.uninstall(AbstractControllerContextActions.java :58) at org.jboss.dependency.plugins.AbstractControllerContext.uninstall(AbstractControllerContext.java:354) at org.jboss.dependency.plugins.AbstractController.uninstall(AbstractController.java:1631) at org.jboss.dependency.plugins.AbstractController.uninstallContext(AbstractController.java:1242) at org.jboss.dependency.plugins.AbstractController.uninstallContext(AbstractController.java:1146) at org.jboss.dependency.plugins.AbstractController.uninstall(AbstractController.java:655) at org.jboss.dependency.plugins.AbstractController.uninstall(AbstractController.java:568) at org.jboss.deployers.vfs.deployer.kernel.BeanMetaDataDeployer.undeploy(BeanMetaDataDeployer.java:156) at org.jboss.deployers.vfs.deployer.kernel.BeanMetaDataDeployer.undeploy(BeanMetaDataDeployer.java:51) at org.jboss.deployers.spi.deployer.helpers.AbstractSimpleRealDeployer.internalUndeploy(AbstractSimpleRealDeploy er.java:69) at org.jboss.deployers.spi.deployer.helpers.AbstractRealDeployer.undeploy(AbstractRealDeployer.java:112) at org.jboss.deployers.plugins.deployers.DeployerWrapper.undeploy(DeployerWrapper.java:192) at org.jboss.deployers.plugins.deployers.DeployersImpl.doUndeploy(DeployersImpl.java:1315) at org.jboss.deployers.plugins.deployers.DeployersImpl.doUninstallParentLast(DeployersImpl.java:1222) at org.jboss.deployers.plugins.deployers.DeployersImpl.doUninstallParentLast(DeployersImpl.java:1215) at org.jboss.deployers.plugins.deployers.DeployersImpl.uninstall(DeployersImpl.java:1177) at org.jboss.dependency.plugins.AbstractControllerContext.uninstall(AbstractControllerContext.java:354) at org.jboss.dependency.plugins.AbstractController.uninstall(AbstractController.java:1631) at org.jboss.dependency.plugins.AbstractController.uninstallContext(AbstractController.java:1242) at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:827) at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:553) at org.jboss.deployers.plugins.deployers.DeployersImpl.process(DeployersImpl.java:543) at org.jboss.deployers.plugins.main.MainDeployerImpl.process(MainDeployerImpl.java:541) at org.jboss.system.server.profileservice.hotdeploy.HDScanner.scan(HDScanner.java:290) at org.jboss.system.server.profileservice.hotdeploy.HDScanner.run(HDScanner.java:221) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441) at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:317) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:150) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(ScheduledThreadPoolExecutor.j ava:98) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(ScheduledThreadPoolExecutor. java:181) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:205 ) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:885) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907) at java.lang.Thread.run(Thread.java:619) 11:18:09,057 INFO [ControlerImpl] ControlerImpl started... 11:18:29,085 INFO [ControlerImpl] ControlerImpl stopped... 11:19:59,656 INFO [ControlerImpl] ControlerImpl started...
Here is the jboss-beans.xml<?xml version="1.0" encoding="UTF-8"?> <deployment xmlns="urn:jboss:bean-deployer:2.0"> <bean name="Controler" class="mcfproto.impl.ControlerImpl"> </bean> </deployment>
Here is the source for ControlerImpl:package mcfproto.impl; import org.jboss.logging.Logger; public class ControlerImpl { private static Logger log = Logger.getLogger(ControlerImpl.class); private NetServer server; public ControlerImpl() { server = new NetServer(); } public void start(){ server.start(); log.info("ControlerImpl started..."); } public void stop() { server.stop(); log.info("ControlerImpl stopped..."); } public void destroy() { server = null; } }
Here is the source for NetServer:package mcfproto.impl; import java.net.ServerSocket; import java.net.Socket; import java.util.HashSet; import java.util.Set; import org.jboss.logging.Logger; /** * Dummy telnet server that listen on port 23 and is used for testing */ public class NetServer { private final static Logger LOG = Logger.getLogger(NetServer.class); private static final int TELNET_PORT = 23; private ServerSocket m_Server; volatile boolean m_Quit; private Set<Handler> m_Handlers; private Thread m_Thread; public NetServer() { m_Handlers = new HashSet<Handler>(); } public void start() { try { m_Thread = new Thread(new Runnable() { public void run() { while (!m_Quit) { try { m_Server = new ServerSocket(TELNET_PORT); loop(); } catch (Exception e) { if (m_Quit) { // It is expected that we get an exception here // as the "stop" method violently close the socket... LOG.debug(e); } else { LOG.error("[NetServer] Inner server listen loop...", e); sleep(1000); } } } closeAll(); } }, "NetServer Thread"); m_Thread.start(); } catch (Exception e) { throw new RuntimeException(e); } } public void stop() { m_Quit = true; try { // force the "loop" to quit TCP "accept" by closing socket... m_Server.close(); } catch (Exception e) { throw new RuntimeException(e); } try { m_Thread.join(); } catch (InterruptedException e) { // demo code, so ignore (but should not in production code) } closeAll(); m_Server = null; m_Handlers = null; m_Thread = null; } void remove(Handler handler) { synchronized (m_Handlers) { m_Handlers.remove(handler); } } private void loop() throws Exception { // no need to synchronize as m_Quit is volatile and // is acting as a memory synchronization block. // (and here we don't need sequencing, just mem sync). while (!m_Quit) { Socket socket = m_Server.accept(); Handler handler = new Handler(socket, this); synchronized (m_Handlers) { m_Handlers.add(handler); } handler.start(); } } private void sleep(int ms) { try { Thread.sleep(ms); } catch (InterruptedException interruptedexception) { } } private void closeAll() { Handler[] handlers = null; synchronized (m_Handlers) { handlers = m_Handlers.toArray(new Handler[m_Handlers.size()]); } for (Handler handler : handlers) { try { handler.close(); handler.join(); } catch (Throwable throwable) { } } } }
And finally, here is the source for the Handler class:/* * Filename : Handler.java * Version : $Revision: $ * Date : $Date: $ * Copyright(c) Ubiquity Software Corporation * http://www.ubiquity.net */ package mcfproto.impl; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; import org.jboss.logging.Logger; public class Handler extends Thread { private final static Logger LOG = Logger.getLogger(Handler.class); private volatile boolean quit; private Socket m_Socket; private PrintWriter m_Writer; private NetServer m_Parent; public Handler(Socket socket, NetServer activator) throws Exception { m_Socket = socket; m_Parent = activator; m_Writer = new PrintWriter(new OutputStreamWriter(socket .getOutputStream())); } void close() { try { quit = true; m_Writer.close(); m_Socket.close(); } catch (IOException ioexception) { } } public void run() { try { send("Welcome to Proto. Please enter a command:"); send("Ex: *[echo msg]"); send("Ex: quit"); BufferedReader reader = new BufferedReader(new InputStreamReader( m_Socket.getInputStream())); String line; send("\n\r"); while (!quit && (line = reader.readLine()) != null) { process(clean(line)); } send("\n\rbye"); } catch (Exception e) { if (quit) { LOG.debug(e); } else { LOG.error( "Error whilst handler was trying to process client response.", e); } } finally { // TODO: check: need reader.close() ??? m_Parent.remove(this); close(); m_Socket = null; m_Writer = null; m_Parent = null; } return; } private void send(String msg) throws IOException { m_Writer.println(msg); m_Writer.flush(); } private void process(String line) throws IOException { LOG.debug("Handler:process() method called with \"" + line + "\""); if (line.startsWith("quit")) { LOG.debug("QUIT command received : (" + line + ")"); quit = true; } else if (line.startsWith("*")) { line = line.substring(1, line.length()); dispatch(line); } else { send("Unknown command received."); } } private void dispatch(String line) throws IOException { send(line); } private String clean(String line) { int size = line.length(); char[] buffer = new char[size]; int out = 0; for (int in = 0; in < size; in++) { char c = line.charAt(in); if (c == '\b') // backspace - ignore { if (out > 0) { out--; } } else if (c >= ' ' && c < '\177') { buffer[out++] = c; } } String cleanedString = new String(buffer, 0, out); return cleanedString; } }
-
5. Re: Lifecycle stop() method and new objects
alesj Nov 28, 2008 6:47 AM (in response to gcompienne)I guess you're experiencing this:
- https://jira.jboss.org/jira/browse/JBAS-6117
This is similar what we had with jboss-minimal tests:
- http://anonsvn.jboss.org/repos/jbossas/trunk/testsuite/src/main/org/jboss/test/jmx/shutdown/ExitOnShutdown.java
- http://anonsvn.jboss.org/repos/jbossas/trunk/testsuite/src/resources/jmx/shutdown/
Note: see jboss-structure.xml in this last link ;-) -
6. Re: Lifecycle stop() method and new objects
gcompienne Nov 28, 2008 6:48 AM (in response to gcompienne)Ah! I forgot to precise. For this test I am using JBoss 5 RC 2.
Thanks again for your help.
Gilles. -
7. Re: Lifecycle stop() method and new objects
gcompienne Nov 28, 2008 6:49 AM (in response to gcompienne)Ok, thanks (message crossover...).
I am going to try what JIRA suggest.
Gilles. -
8. Re: Lifecycle stop() method and new objects
gcompienne Nov 28, 2008 6:59 AM (in response to gcompienne)Yes, it worked.
Thanks :-) -
9. Re: Lifecycle stop() method and new objects
gcompienne Nov 28, 2008 12:44 PM (in response to gcompienne)For info.
Having though about the problem, I agree with JIRA if the situation is the case where components start threads and they still go on (creating new objects) after the stop method on the main POJO has ended.
But in my example, the "stop" method returns only once all threads involved in the component have stopped. So I have the feeling it could still highlight something strange somewhere.
But anyway, the given workaround works fine so I am definitivelly not going to complain ;-) (this is just for info in case this could highlight the why of some other problem). -
10. Re: Lifecycle stop() method and new objects
alesj Nov 28, 2008 1:31 PM (in response to gcompienne)"gcompienne" wrote:
So I have the feeling it could still highlight something strange somewhere.
But anyway, the given workaround ...
Actually I don't see this as a workaround. :-)
Although this is marked as workaround in mentioned JIRA issue.
It's a normal behavior on how you load classes,
when the deployment is deleted --> undeployed.
Unless you make a temp copy of it,
I don't see how else you're still gonna access that resource.
It's probably the fact that we now do it differently
due to VFS's capability of handling resources as they are (even nested one's),
that makes this example a bit unexpected - since almost everybody else does it the old way == temp copy. -
11. Re: Lifecycle stop() method and new objects
gcompienne Dec 3, 2008 4:39 PM (in response to gcompienne)Ah ok, I understand now (my fault).
I had been assuming that VFS was doing its own copy of the artifact and that the removal (or update) of the original file was only used as an indicator of an undeploy (or redeploy) to be done (then followed by a removal of the copy).
But, yeah, if it does not make a copy then yes, I can see it would have serious problems to try and load anything ;-)
Thanks for the clarification.
Gilles. -
12. Re: Lifecycle stop() method and new objects
norman.richards Jan 20, 2009 2:31 PM (in response to gcompienne)So, if deleting the file from the deploy directory is no longer correct, what is the "correct" way to undeploy on JBoss AS now?
-
13. Re: Lifecycle stop() method and new objects
alesj Jan 21, 2009 7:54 AM (in response to gcompienne)"norman.richards@jboss.com" wrote:
So, if deleting the file from the deploy directory is no longer correct, what is the "correct" way to undeploy on JBoss AS now?
It depends on what your app is doing at undeploy.
e.g. still loading/reading some resources
Then you need to apply a temp mechanism.
The fact that we did that before by default,
doesn't make what we do now not "correct". ;-)