geronimo-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jason Dillon <ja...@planet57.com>
Subject Re: GBeanInstance/GBeanInstanceState eating exceptions?
Date Mon, 26 Feb 2007 23:33:33 GMT
I think David Jencks added something (or was going to add something)  
which would provide more detail for these exceptions when run from  
the car-m-p.

David, did you ever get around to adding that?  If not, is it  
something you can easily do?

--jason


On Jan 19, 2007, at 4:20 PM, Dain Sundstrom wrote:

> I didn't know you wanted details :)   Honestly, I have no idea why  
> the exception is being eaten, other than it may be expected.  The  
> startup is asynchronous, so the start may wake up in a "not yet  
> ready" state.  The reason it is in the current state is recorded in  
> GBEanInstance.getStateReason().
>
> It is the configuration object that has decided, that it has waited  
> long enough and if all beans are not started it is going to give  
> up.  The feature was recently added, and is a big improvement over  
> the previous behavior of waiting forever.  Basically, the  
> configuration attempts to get all beans started, if they don't all  
> start then it throws an exception stating why some of the beans  
> didn't start.
>
> Anyway, if you see some more information that needs to be  
> propagated, by all means add it, just be careful, that you aren't  
> wiping out relevant information with irrelevant info.
>
> -dain
>
> On Jan 19, 2007, at 2:05 PM, Jason Dillon wrote:
>
>> Where are the methods to pass back failure information from  
>> GBeanInstanceState to GBeanInstance (and so on) ?
>>
>> I don't see anything like getFailureReason() or anything similar.
>>
>> How is one supposed to expose the MissingDependencyException that  
>> is thrown in GBeanInstanceState.attemptFullStart(), which occurs  
>> when calling gbeanInstance.createInstance() and is then caught and  
>> eaten?
>>
>> I need to propagate this exception detail back further to the  
>> component that asked for the component to be loaded, and attach  
>> the detail to the failure exception that is thrown when we ask a  
>> configuration to load.
>>
>> What is the api to store and retrieve exceptions later that you  
>> mention?
>>
>> --jason
>>
>>
>> On Jan 17, 2007, at 10:40 PM, Dain Sundstrom wrote:
>>
>>> I'm not going to try to justify the design, but I'll explain it...
>>>
>>> The lifecycle method don't necessarily result in the bean fully  
>>> completing a state change.  The bean may enter a transition state  
>>> like starting or stopping and wait there for a resource to become  
>>> available.  Really, they just initiate  a lifecycle change that  
>>> will complete at a later time.  If the method were to throw an  
>>> exception it would be completely random if it "worked" or not.   
>>> Therefore, the methods don't throw exceptions and then are  
>>> supposed to store the exception so it can be retrieved later.
>>>
>>> The key is that most gbeans are started by the configuration and  
>>> the configuration will gather any failures and throw a single  
>>> exception containing all the problems.
>>>
>>> Now if there are places problems occurs and the exceptions aren't  
>>> saved, it is a bug.
>>>
>>> -dain
>>>
>>> On Jan 17, 2007, at 2:06 PM, Jason Dillon wrote:
>>>
>>>> Why do GBeanInstance/GBeanInstanceState eat exceptions instead  
>>>> of throwing them?
>>>>
>>>> This seems to be a common pattern with GBeans, where they don't  
>>>> propagate the exception detail.  I was just looking at  
>>>> GBeanInstance.start(), but looks like stop() and other methods  
>>>> have the same basic issues.
>>>>
>>>> The lack of detail being propagated results in build failures like:
>>>>
>>>> <snip>
>>>> Configuration gbean failed to start org.apache.geronimo.configs/ 
>>>> openejb/2.0-SNAPSHOT/car
>>>> </snip>
>>>>
>>>> But they show no detail as to why they failed.  This one happens  
>>>> to be caused by:
>>>>
>>>> <snip>
>>>> org.apache.geronimo.kernel.repository.MissingDependencyException: U 
>>>> nable to resolve dependency org.apache.openejb/openejb-loader//jar
>>>>         at  
>>>> org.apache.geronimo.kernel.repository.DefaultArtifactResolver.resol 
>>>> veInClassLoader(DefaultArtifactResolver.java:123)
>>>>         at  
>>>> org.apache.geronimo.kernel.repository.DefaultArtifactResolver$ 
>>>> $FastClassByCGLIB$$e847b746.invoke(<generated>)
>>>>         at net.sf.cglib.reflect.FastMethod.invoke 
>>>> (FastMethod.java:53)
>>>> ...
>>>> </snip>
>>>>
>>>> But you would never know that unless you hack up the  
>>>> GBeanInstanceState with printlns or something.  There is some  
>>>> logging which is done, but that is getting lost due to mismatch  
>>>> in log4j and maven logging systems.  I thought I had a bridge  
>>>> setup to handle this, but it appears to have been broken for  
>>>> sometime.  But aside from the logging issue, I think its a  
>>>> bigger problem that the GBean stuff is not throwing exceptions  
>>>> with meaningful details.
>>>>
>>>> There are other bits which look rather wrong wrt showing  
>>>> exception details, like:
>>>>
>>>> <snip>
>>>> try {
>>>>     kernel.startRecursiveGBean(dependent);
>>>> } catch (GBeanNotFoundException e) {
>>>>     // this is ok the gbean died before we could start it
>>>> } catch (Exception e) {
>>>>     // there is something wrong with this gbean... skip it
>>>> }
>>>> </snip>
>>>>
>>>> There is no log here at all... this exception just gets  
>>>> swallowed up.
>>>>
>>>> This also looks fishy:
>>>>
>>>> <snip>
>>>> try {
>>>>     // try to create the instance
>>>>     if (!gbeanInstance.createInstance()) {
>>>>         // instance is not ready to start... this is normally  
>>>> caused by references
>>>>         // not being available, but could be because someone  
>>>> already started the gbean.
>>>>         // in another thread.  The reference will log a debug  
>>>> message about why
>>>>         // it could not start
>>>>         return;
>>>>     }
>>>> } catch (Throwable t) {
>>>>     // oops there was a problem and the gbean failed
>>>>     log.error("Error while starting; GBean is now in the FAILED  
>>>> state: abstractName=\"" + abstractName + "\"", t);
>>>>     setStateInstance(State.FAILED);
>>>>     lifecycleBroadcaster.fireFailedEvent();
>>>>
>>>>     if (t instanceof Exception) {
>>>>         // ignore - we only rethrow errors
>>>>         return;
>>>>     } else if (t instanceof Error) {
>>>>         throw (Error) t;
>>>>     } else {
>>>>         throw new Error(t);
>>>>     }
>>>> }
>>>>
>>>> // started successfully... notify everyone else
>>>> setStateInstance(State.RUNNING);
>>>> lifecycleBroadcaster.fireRunningEvent();
>>>> </snip>
>>>>
>>>> The catch here is actually what was handling the above  
>>>> MissingDependencyException, which sets the state to failed,  
>>>> broadcasts the event, then eats the exception, and then  
>>>> continues to set the state to running and broadcasts that event,  
>>>> which should fail on the state transition of FAILED ->  
>>>> RUNNING... but we should not even be attempting that transition  
>>>> because of the caught exception.
>>>>
>>>> The nice comment about the createInstance() logging a DEBUG  
>>>> message is also odd... this failure reason really should also be  
>>>> propagated via an exception to allow higher-level systems to  
>>>> handle it as needed.  All of this exception eating is really  
>>>> making things much more difficult than they need to be when  
>>>> using the car plugin to build the server.
>>>>
>>>>  * * *
>>>>
>>>> What is the reasoning behind this behavior?  I think that we can  
>>>> simplify things a lot by simply throwing exceptions, as well as  
>>>> propagating details to layers that really need it (like the  
>>>> car:package goal really needs to know why the gbean failed to  
>>>> start so that it can communicate that to the user).
>>>>
>>>> Can someone please explain to me why these exceptions are not  
>>>> being thrown?
>>>>
>>>> Thanks,
>>>>
>>>> --jason
>>>
>>
>


Mime
View raw message