I fixed a bug in 1.2, where the exception was being rethrown before
it was recorded as the root cause.
-dain
On Feb 26, 2007, at 4:22 PM, David Jencks wrote:
On Feb 26, 2007, at 3:33 PM, Jason Dillon wrote:
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?
I definitely added it to trunk (2.0). I'm not sure if it made it
into 1.2.
thanks
david jencks
--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:
Unable to resolve dependency org.apache.openejb/openejb-
loader//jar
at
org.apache.geronimo.kernel.repository.DefaultArtifactResolver.res
olveInClassLoader(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