Extending GLCanvas

I read that there was a request to make GLCanvas non-final and instantiable. I also read that it was denied, since managing open GL context’s in conjunction with Java is difficult. I can understand that a lot of issues can arise, but extending the class is a valid and useful thing to do. Right now I am using GL4Java, I use to use Magician, and am currently extending GLCanvas, to a class called Graph3D, to fix some bugs in the underlying implementation and to add a slew of capabilities. Think about registering mouse listeners to that Graph3D, it needs to be returned as the source of mouse/keyboard events. In the case that I cannot subclass GLCanvas, I have to requests for registering mouse events to the Graph3D, just pipe them to the GLCanvas, and on the way back make the source the Graph3D again, or I have to expose to the users of my API that there is this thing called a GLCanvas, which I do not think is acceptable. Especially when we are changing underlying OpenGL binding implementations like diapers on a baby. :-[

-Jason

This is a good point that I hadn’t considered before. What would you say if all of the “interesting” methods that are currently in GLCanvas (display(), paint(), etc.) were final but the class itself was not?

Probably 90% of the bugs that were posted to the GL4Java mailing list over the past year or two were related to people subclassing GL4Java’s GLCanvas and forgetting to perform some key context manipulation in their subclass. This was the reason for making JOGL’s GLCanvas and GLJPanel final. If we protect ourselves against user error by enforcing proper context handling using final methods, we could allow subclassing.

Hopefully you don’t need to subclass the JOGL canvas to fix bugs as you’ve had to do with other implementations. If you find bugs please file issues on http://jogl.dev.java.net/ .

I am curious what capabilities you’re adding to the GLCanvas class; my experience has been that since keyboard and mouse events come in on the AWT thread that it’s usually necessary to have some application-level intervening code that consumes the events and sets some state later processed by the OpenGL rendering thread. Are you interposing on the mouse and keyboard events in Graph3D, performing some processing before handing off the event to the end user? If so, how does this work, and are you executing any OpenGL commands during that interposition?

gleem (checked in to the jogl-demos source tree, and also at http://www.media.mit.edu/~kbrussel/gleem/) defines a new set of events that end users can register for as the manipulators move or as window updates become necessary. These were implemented without subclassing GLCanvas, primarily to allow gleem to work with an arbitrary GLDrawable.

Careful - saying we don’t allow subclassing because a lot of people don’t do it right is not a good answer. A lot of people mess up with the Thread class but that is no reason to remove it from the Java language.

I think this also brings up another question - should GLCanvas extend Canvas or take a Canvas as a parameter?

By extending Canvas you kill all chances of working with any other tools or API’s that also subclass canvas. This was a mistake made by Java 3D and JAI. Both API’s extended Canvas and thus blocked the opportunity for these two API’s to work together on the same Canvas.

d

[quote]Careful - saying we don’t allow subclassing because a lot of people don’t do it right is not a good answer.
[/quote]
True, but a good API is programmer friendly in that it’s design minimizes the risk of improper use.

My 2 cents on this philisophical topic…

“… but not at the expense of limiting its usefulness or impacting its performance.”

Just to add in my quickie opinion. People are going to make mistakes and they are going to do some things incorrectly as they come up to speed - that’s fine. But we don’t want to lose functionality in an effort to cater to this audience.

Better to make the mistake and crash your box and remember never to make that mistake again than to not be able to perform some crucial functionality. Of course there are limits to this, but overall - give me functionality.

Well, it was asked what I am doing when extending GLCanvas, to this class called Graph3D. Graph3D contains not only the Canvas, but the camera that performs manipulation in the scene. It also has Universe3D(s) that are drawn by this Graph3D. It also deals with requests for re-rendering in a non-blocking fashion. So when the user presses the mouse button in the Graph3D, it notifies the listeners just like every other Java component and the user will often do something like move the view. Since the Graph3D IS the view, they can call Graph3D.getCamera().dolly(), etc. At the same time, when the Universe has changes to it, either through adding, deleting, or modifying some geometry, it notifies all the Graph3D’s that they need to re-render the scene. So that is the skinny on what I am doing by the current subclassing of GL4Java’s GLCanvas. Since what I write is ALSO an API, I can understand the problem with allowing users to extend a class and “screw” things up. I am highly against making classes or methods final in the lowest level of an API. The decision that we’ve taken is that we have at the lowest level a set of interfaces that can be implemented, then a number of InterfaceAdapters that implement those interfaces in varying modes of complexity and safety. These implementing adapters are then capable of having the diversity of extreme safety to extreme flexibility. Would it be OK to have some methods final, yeah I guess, but it would have to be inconjunction with not having to use the factory as defined by the current implementation. If it would be useful I can gin up some simple contrived examples of what I mean.

-Jason

[quote]Careful - saying we don’t allow subclassing because a lot of people don’t do it right is not a good answer. A lot of people mess up with the Thread class but that is no reason to remove it from the Java language.

d
[/quote]
On the contrary, forbidding subclassing or overriding by judicious use of the final keyword is standard practice in the J2SE libraries. Subclassing is typically forbidden because allowing the end user to do so would introduce a security hole or allow JVM crashes. From my experience with GL4Java this is very clearly the case with the GLCanvas implementation, hence the design decision in JOGL to make GLCanvas final. Going forward, I think we should try to preserve the safety features of the JOGL library, which will improve its stability both in actuality and perception, while still providing the features necessary to make it most useful. This will require careful API and implementation design rather than just making everything public and customizable. The source code is always available if a developer needs to customize it immediately for a particular purpose and can’t wait for an RFE to be handled.

Two points:

  1. As far as I understand, GLCanvas is made final not for safety, but for robustness - so people will not make errors because of using context from different thread. Now you talk about safety/crashes - is there anything which makes extending GLCanvas dangerous for jvm ?

  2. Do you really hope to make jogl safe EVER ? Please put this line in display method for GLGears

gl.glReadPixels(0,0,100000,100000,GL.GL_RGBA,GL.GL_INT,MappedByteBuffer.allocateDirect(4));

Just be sure to make backup of important data on computer. My Windows XP with NTFS barely recovered from it after hard reboot.

There are hunderds of points like this in opengl which can be used to crash computer. There are also probably some more which can be used to access arbitrary code in memory, modify it and possibly execute rootkit-like code. Do you really hope all of it can be fixed ?

And I would argue that they should not be fixed. Once you get to this point where you’re going after performance - safety is going to fall away and we just have to accept that we cannot be 100% safe and have good performance. The whole idea of having DirectByteBuffers - touching native memory or accessing things through JNI will make it nearly impossible to keep things safe. That;'s just the way of things and we need to accept that and move on.

[quote]And I would argue that they should not be fixed. Once you get to this point where you’re going after performance - safety is going to fall away and we just have to accept that we cannot be 100% safe and have good performance. The whole idea of having DirectByteBuffers - touching native memory or accessing things through JNI will make it nearly impossible to keep things safe. That;'s just the way of things and we need to accept that and move on.
[/quote]
I agee with everything but your last 2 lines Cas.

NDBB’s actually are quite safe in of themselves because access through them is bounds checked. Now ofcourse if what you are exposing THROUGH them can be screwed up, say video registers on a game console, I do agree that thats another story. But its not really the NDBB itself thats the issue, its what you are chosing to do with it.

JK

Mmph?

I may as well say something then!

Let’s put a child’s perspective on the discussion:

“Bottom”.

There.

final is a great world to ensure that a class is used as a delegate rather than as an extension.

However I have determined that in an open source project that final is an irrelevant keyword regarding security or safety because one can simply remove it and recompile.

Cas :slight_smile:

Everyone knows how I feel about the final keyword, but if you don’t, it’s great in an application, but should be used VERY sparingly in an API. As a comprimise I would accept the class to be public with some final methods. That would allow me to accomplish the tasks that I need to, in an architectural fashion that is pleasing to the people using my tools, otherwise I need to do extra conversion and object creation or expose internals about what bindings I am using. I cannot agree more that we cannot make things safe. "while(true); " still has caused more problems than a well documented API that warns you of the inherent danger in extending and replacing it’s functionality. As an aside… I really dislike factories, the classes that they produce could be implented differently and hide the abstractness of the underlying structure (Win32, Mac, Linux…)

-Jason

I really hate to bring this up again, but I was hoping that as time passed there would be more banter on this subject. While I know that jogl is open source and I can change the libraries to say whatever I want them too, I am going to once again suggest that GLCanvas becomes instantiable and non-final. For safety reasons, I will not press the case in making any methods/fields un-finalized. When events are propagating around the system, it would be nice to tell the users of my API that the mouse event came from my API and not expose any part of JOGL.

Maybe I’m the only one making an API with JOGL? I kinda doubt that…

As an aside, how does JOGL relate the the agreement that Sun and SGI signed that says they are going to write a Java binding to OpenGL? It sounds like it may be YAJOGL (Yet another Java to Open GL).

Sorry but there hasn’t been a lot of time to address JOGL RFEs recently. If you’d like to see this get done more quickly, please make a strawman GLCanvas class that is non-final but with all of the internal methods relating to the GLContext final (following the design in the posts above). Send me a review and I’ll probably either make you a developer so you can check it in or (with your permission) make the necessary changes in the source tree.

I’m done with the implementation, how do you want me to post it?

I also made a jogl-demo…