Exception handling in AWTJPCTCanvas exceptionOccurred(...) method.

Started by Virtudude, November 26, 2010, 03:31:58 AM

Previous topic - Next topic

Virtudude

Hi,

I noticed that the jPCT exception handler, specifically in the "exceptionOccurred" handler of AWTJPCTCanvas, is triggering a "java.lang.reflect.ReflectPermission suppressAccessChecks" exception when a LWJGLException exception is thrown since I am running an applet in an environment that does not have the reflection permission set.

The problem is that the jPCT "exceptionOccurred" handler is eating the original LWJGLException, and hence the only exception I see is the secondary ReflectPermission (i.e. the only message I see is: ERROR: Unable to recover: access denied (java.lang.reflect.ReflectPermission suppressAccessChecks). Perhaps this handler is trying to do something with the LWJGL exception, and is using reflection in one way or another.

Is there any way to avoid using reflection in the exceptionOccurred method of AWTJPCTCanvas for those environments where reflection is not permitted?

If this is not possible, can you please print the stack trace of the original LWJGLException so that I know what the root cause is? Note: that the case is when I see the jpct message: "Unable to recover: " -- you may print out the LWJGLException in other cases but without the source I can't say for certain.

By the way, I did find the root cause by doing thread dumps, but this was a hit and miss approach. The issue is that my graphics driver was throwing a opengl.WindowsPeerInfo.nChoosePixelFormat related error since I was using a HW framebuffer mode that is not supported by the default drivers.

Thank you!  ;D
Dave

EgonOlsen

The use of reflection is a fierce hack that i had to include to handle lacking AA capabilities on Intel crapsets. I agree that, if that fails, the actual reason gets swallowed. I'll change that for the next release.

Virtudude

Thank you for getting back to me in a timely manner and for offering to include the original exception in the next release. And of course, thanks for this great engine!

Regarding the comment about using reflection, based on your response, I'm assuming that reflection is required, hence I'll have to consider this fact in the restrictive world the applet runs in.

I was hoping to by default use the mode FrameBuffer.SAMPLINGMODE_GL_AA_4X, and, if there is an exception raised, then I would do an internal retry with the mode RENDER_MODE_HARDWARE (and if that fails, resort to the software mode). The problem is that I have no way to intercept the exception and add my own handling routine or try to use a different framebuffer. In other words, I can't extend the hardware canvas since it is returned internally by jPCT via enableGLCanvasRenderer(); Also, I can't intercept the internal jPCT Logger. And in most cases the exception occurs outside my thread stack - i.e.:

at com.threed.jpct.AWTJPCTCanvas.exceptionOccurred(Unknown Source)
at org.lwjgl.opengl.AWTGLCanvas.paint(AWTGLCanvas.java:319)
at org.lwjgl.opengl.AWTGLCanvas.update(AWTGLCanvas.java:334)
at sun.awt.RepaintArea.updateComponent(Unknown Source)
at sun.awt.RepaintArea.paint(Unknown Source)


If you can think of any way that I can get an opportunity to capture an exception that is thrown within the above stack (as an example), without using reflection or anything else that will cause the applet to raise security exceptions, that would be much appreciated. For example, if I could handle the exception, I could present a customized error page instead of a blank applet.

If there is no way to intercept the exception, then unfortunately the choice is that I go with RENDER_MODE_HARDWARE since I need to support both higher end machines and machines with sub-par graphics cards. I would really like to support AA for those cards that can handle it and revert to using RENDER_MODE_HARDWARE if the card can't.

Thanks again for your assistance.  :)

Dave

EgonOlsen

I can't find the thread that deals with this right now, but the use of reflection is in there to hack around the problems you have mentioned. The actual problem is, that you have to feed a pixel format into the constructor of LWJGL's AWTGLCanvas. At that stage, any pixel format is valid, because the actual initialization doesn't happen there but later in the awt event dispatch thread. On the other hand, you can't query for valid pixel formats before, because you need a gl context to do so...which you don't have, because you have no canvas...
The only solution that i could come up with, was to override exceptionOccured() and use reflection to inject a new pixel format (without AA) into the already created instance of AWTGLCanvas and manipulate some class attributes to make LWJGL think that the canvas is new. It's clearly a hack, but i couldn't find any better way.
To solve your problem, a kind of callback might do the trick. I'm just not sure where to put it. However, i don't understand why reflection doesn't work in an applet if it's already signed anyway, which it has to be, because it uses opengl  ???

Virtudude

Thanks for the response and the explanation.

As for applet security, once I signed the jpct jar file in addition to my own Jars the reflection operation was permitted and the rollback happened as I was hoping (to revert from AA mode to normal HW mode). I suppose the reason that opengl was permitted and reflection was not is because opengl was run under a security context that was initiated from my Jar which is signed and thus trusted. Also, LWJGL jars come pre-signed and I guess for development this works fine (for prod all jars should be signed with the same cert). However, the reflection call must have been running under a different security context that was not trusted, but signing the jpct jar file established the trust that was required.

As for the callback, I no longer need it for this particular scenario since it is working as desired. That being said, I think if you did support a callback for other cases where exceptions occur that would be a nice addition. If you wanted to implement a callback I suppose one way is to use injection similar to the way Spring does. In this case, the client application would inject its own exception handler into jPCT that would implement an interface that jPCT understands (i.e. the interface could have an "exceptionOccured" if you want to be consistent or "handleException" method). When an exeption occurs, jPCT could test whether the client assigned (injected) a value to the handleException instance, and, if it did, then jPCT would call the method on that instance. Right now I see jPCT already has a mode that lets the client specify what should happen on an error (such as continue on or abort) which is nice, but allowing the client to handle exceptions the way they want (such as to display a more informative error web page, etc.) would be helpful. This way if an exception that can't be handled by jPCT occurs, the client will be able to display an error page (or do whatever else) that makes sense in their situation. Otherwise the applet might just go blank if jPCT aborts which is not desirable.

Just a suggestion, I know you probably have bigger fish to fry.

And, thanks again for your help.