Table of Contents
GeoGebra developing cookbook
As you know from Unifying Codebase and Unifying CodeBase FAQ, from GeoGebra 4.2 we are developing the project with a goal in mind, that GeoGebra will have two main application View Desktop and Web. The Desktop view is the "original" Java GUI, while the Web View is a JavaScript based view, compiled from Java code with the Google Web Toolkit (GWT) and uses the html5 <canvas> tag for presentation.
The main reason of this kind of development, that mobile devices OSes like Android, Apple OS, etc don't have Java plugin installed, but have html5 capable browser.
To avoid repeating the main logic, there is a project Common where the codebase that is used by both Views take place. As GWT JRE is not the same as the Java's JRE, the Common code must have a code GWT compatible. Thus developers should install the GWT Compiler plugin and use it before every commit on the code in GeoGebraWeb (Common and Web), use it both on the Common project and on the Web project if they change the code in Common too (otherwise just on the Web project). The goal of development is to take the code that is used by both View parts into Common and develop further features with this theory in mind, because it is the easiest way to get our functionality working in both Views.
As this kind of "evolution" needs different knowledge for both part, this cookbook is aimed to collect this knowledge: ideas, tips, tutorials, etc. Every developer is encouraged to add here his part, be it a Java based design pattern solution to help porting, adapting incompatible classes, or a html5 based advice how to create a mobile GUI. Be the source with you.
The Three Projects
Separation, Refactoring Tips
In GeoGebra 4.0, most classes couldn't be compiled with GWT. Parts of a class could be compliled with GWT, but parts of it could not. We wanted most of the code to be compiled with GWT - so be put into Common - and for this, we needed to separate the classes into more parts and/or refactor them. Here are some ideas how to separate the code to put some of it into Common and to let some of it remain in Desktop - although the bottleneck of the work is already done.
- Huge classes can be taken apart into more.
- For large classes and hard-to-port classes, like Kernel, Construction, Application and other interconnected classes use abstract classes in Common which contain their GWT-compatible code, and enhance these abstract classes in Desktop with Java-specific code (and later in Web with GWT-specific code), like AbstractKernel.java, Kernel.java (desktop), Kernel.java (web). According to the former guideline, create an almost-empty abstract class for each of these first in Common, create many such abstract classes, and then gradually put the content of the classes in Desktop to their corresponding abstract class in Common as they allow it - so probably they can be improved side by side, and we cannot port one such class in itself first.
- For smaller classes we could substitute the GWT-incompatible imports with corresponding interfaces (or dummy abstract classes), use the methods of those interfaces in the classes, and that way we could compile them with GWT, without making them abstract and subclassing them - this is something like the Adapter pattern. Factories contain methods which create the actual classes which are implementations of those interfaces. This was especially useful for porting outer Java classes, importing those Java classes in the implementations of the interface.
- How to instantiate a specific adapter class in a static method in a class in Common: e.g. AwtFactory.prototype.newColor
- Use only such interfaces or abstact classes in Common which can be implemented in Web.
Example: 2D Graphics
Let's consider the code used for drawing in the euclidian view. Plain Java and GWT use different techniques and interfaces for this task and while the low level code is different the high level drawing logic should be the same: To draw an GeoImage object we still have to load the file, calculate the image's position, scaling and rotation, and draw the pixels at the correct position. Therefore we want to use a common high-level interface for drawing which hides the differences between the underlying interfaces through abstraction.
Some of the problems arising in this context are…
How should the high-level interface look like?
As the existing code is using Graphics2D and related classes for drawing already they provide a good indicator about what features we need. So instead of coming up with a new interface we can try to port the features of Graphics2D we need at the moment to GWT and leave the remaining interface unimplemented at the moment. It's of course an open question how well the desktop way of drawing works together with GWT.
How do we want to access the interface in the common project?
The Graphics2D interface consists of multiple interconnected classes, but we cannot create instances of those classes in the common code as that code is used for both desktop and web. To solve this problem we use abstract factories for object creation. Both web and desktop projects subclass the abstract factory, ie. factories which create the correct kind of objects for the project. The common code just communicates with the abstract factory and common interfaces and thus will not have to bother about the underlying implementation of the interfaces and factory.
How do we translate our interface into native methods?
As we made our common interface similar to the one used in desktop Java (java.awt) the desktop implementation of the classes just have to act as an almost 1-to-1 map between our interface and java.awt (using the adapter pattern). We cannot use the Java classes directly because they don't inherit from our common interface of course.
The implementation of the interface for the web project is of course much more complicated, as a mapping between the GWT and our common interface has to be found. It's likely that in many situations the methods of the common interface are unnecessary for GWT, but unless major obstacles are found the common interface should be kept.
Naming Conventions
Important note: here the word interfaces means "something that can be implemented", so it could mean abstract classes or java interfaces, as the logic recommends. (If some functionality needed in Common which a java interface can't afford, abstract classes must be used)
- For all classes and packages: follow the convention in desktop (so geogebra.euclidian | geogebra.common.euclidian | geogebra.web.euclidian)
- For native classes which aren't supported by the GWT JRE, create an adapter like geogebra.awt.* (classes) geogebra.common.awt.* (interfaces) geogebra.web.awt.* (classes). For example common.awt.* interfaces are implemented by the geogebra.awt.* and the geogebra.web.awt.* classes. So geogebra.awt.Color.java (class), geogebra.common.awt.Color.java (interface), geogebra.web.awt.Color.java (class).
- For interfaces which are not native ones ClassnameInterface.java is used (like GeoElementInterface.java) (temporary?)
- For abstract classes which are parents of big classes AbstractClassname.java (like AbstractKernel.java)
- For factories *.factories.FunctionalityFactory.java (like geogebra.common.factories.AwtFactory.java). Functionality means logically dependent classes like awt or graphics or xmlhanding responsible classes. Additionally, name the object creator classes of the factory starting with new, e.g. newColor(...).
Musings on Refactoring
- Refactoring some thoughts about refactoring
- Statistics on the changing number of Java files in common/desktop/web
What works are in progress
Attachments
-
graphics2d-interface.png
(124.1 KB) -
added by florian 6 months ago.
common interface for 2D drawing related classes (concept only)

