Posts Tagged Ext-GWT
Porting Swing’s Action pattern to GXT (Ext-GWT)
Posted by Olivier Gérardin in GWT on 2009-09-14
While working with GWT and GXT, it occurred to me that there was no equivalent in either to Swing’s Action architecture… So I set myself to implement an equivalent functionality in GXT.
The Swing legacy
In a word, the action architecture is an implementation of the Command design pattern, with the Action class being an abstraction of a command which is not bound to a specific UI component. Action implements ActionListener, which lets users perform it, namely by calling its actionPerformed method. An Action may also contain additional meta-information such as a name, a description, an icon, etc.
The cool thing with actions is that many Swing components (such as a JButton or a JMenuItem) are action-aware, which means that they can be constructed from an action instance. The data required to build the UI component, such as the button’s label, is taken from the Action’s meta-data. When the component is activated (read: clicked), the corresponding action’s actionPerformed method is then called.
Furthermore, if the action is disabled, then the corresponding UI component becomes disabled too. If you used the same Action instance to construct several UI components, they will all reflect the action’s disabled status! Now this is starting to get interesting…
Let’s see if we can make this happen with GXT.
Step 1: the Action classes
First we need an ActionListener interface:
import com.extjs.gxt.ui.client.event.BaseEvent;
public interface ActionListener {
/**
* Invoked when an action occurs.
*/
void actionPerformed(BaseEvent e);
}
This is quite similar to Java’s original ActionListener interface, except that we use GXT’s BaseEvent instead of Java’s ActionEvent, for obvious reasons. The original ActionListener also inherited EventListener, which is not needed here.
Next we need an Action interface that allows UI components to fetch what they need to construct themselves (name, etc.). The original Action interface contains
- a set of String constants that define the names of the properties (NAME, SHORT_DESCRIPTION, SMALL_ICON, etc.)
- methods to get/set those properties
- methods to add/remove a PropertyChangeListener so that we can be notified of changes
In native Java, the property-related methods are implemented completely in AbstractAction using ArrayTable and SwingPropertyChangeSupport, which means I would have to add a lot of code to duplicate the functionality.
Fortunately, GXT has a class called BaseModel which provides exactly the same set of functionality: named properties plus support for change listeners. So I slightly modified the Action interface so that GXT’s BaseModel would directly implement the property-related methods:
Object getValue(String key)becomes<X> X get(String key)void putValue(String key, Object value)becomes<X> X set(String key, X value)void addPropertyChangeListener(PropertyChangeListener listener)becomesvoid addChangeListener(ChangeListener... listener)void removePropertyChangeListener(PropertyChangeListener listener)becomesvoid removeChangeListener(ChangeListener... listener)
Here is the full listing (most comments removed for brevity; see original Action Javadoc):
import com.extjs.gxt.ui.client.data.ChangeListener;
public interface Action extends ActionListener {
/**
* Useful constants that can be used as the storage-retrieval key
* when setting or getting one of this object's properties (text
* or icon).
*/
public static final String DEFAULT = "Default";
public static final String NAME = "Name";
public static final String SHORT_DESCRIPTION = "ShortDescription";
public static final String LONG_DESCRIPTION = "LongDescription";
public static final String SMALL_ICON = "SmallIcon";
public static final String ACTION_COMMAND_KEY = "ActionCommandKey";
public static final String ACCELERATOR_KEY = "AcceleratorKey";
public static final String MNEMONIC_KEY = "MnemonicKey";
/**
* The key used for storing the CSS icon style (added)
*/
public static final String ICON_STYLE = "IconStyle";
public <X> X get(String key);
public <X> X set(String key, X value);
public void setEnabled(boolean b);
public boolean isEnabled();
public void addChangeListener(ChangeListener... listener);
public void removeChangeListener(ChangeListener... listener);
}
A few comments on this:
- get/set methods are now generic (which must be good),
- we use GXT’s ChangeListener instead of Java’s PropertyChangeListener, because that’s what GXT’s BaseModel supports
- not all properties make sense in GXT, but I have kept them nonetheless. You never know…
- I have added a property ICON_STYLE, which might be useful in a GWT context if we want to provide an icon as a CSS style rather than an Image.
Now we need an implementation of the Action interface that provides default behaviours for get/set methods and property change listeners; thanks to our little changes in Action, we just have to extend GXT’s BaseModel, which will handle most of the job.
import com.extjs.gxt.ui.client.data.BaseModel;
public abstract class AbstractAction extends BaseModel implements Action {
/**
* Specifies whether action is enabled; the default is true.
*/
protected boolean enabled = true;
public AbstractAction() {
}
public AbstractAction(String name) {
set(Action.NAME, name);
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean newValue) {
boolean oldValue = this.enabled;
if (oldValue != newValue) {
this.enabled = newValue;
notifyPropertyChanged("enabled", newValue, oldValue);
}
}
}
That’s it! The get/set/addChangeListener/removeChangeListener methods are directly implemented by BaseModel and don’t even need to be redeclared here. I have dropped Cloneable and Serializable from the implemented interfaces because it doesn’t make much sense in a GWT context.
Step 2: the UI components
OK, now we have Actions that have properties, can notify changes, and can do something when they are performed. What we need to really make this useful is UI components that can accept an Action and will do what’s needed to translate that into UI stuff.
Let’s extend Menu so that we can call add(Action):
public class Menu extends com.extjs.gxt.ui.client.widget.menu.Menu {
public boolean add(final Action action) {
final MenuItem item = new MenuItem(action.get(Action.NAME));
// Use the action's long description as tooltip
String longDesc = action.get(Action.LONG_DESCRIPTION);
if (longDesc != null) {
item.setToolTip(longDesc);
}
item.setEnabled(action.isEnabled());
item.addSelectionListener(new SelectionListener() {
public void componentSelected(ComponentEvent event) {
action.actionPerformed(event);
}
});
// make sure changes in the "enabled" state of the action are propagated
// to the MenuItem
action.addChangeListener(new ChangeListener() {
public void modelChanged(ChangeEvent event) {
PropertyChangeEvent propertyChangeEvent = (PropertyChangeEvent) event;
if (propertyChangeEvent.getName().equals("enabled")) {
boolean enabled = (Boolean) propertyChangeEvent.getNewValue();
item.setEnabled(enabled);
}
}
});
return add(item);
}
}
The outline is very simple:
- create a MenuItem
- give it name, tooltip, state according to the Action
- make sure that selecting it will trigger the action
- make sure that if the “enabled” status of the action changes, the “enabled” status of the MenuItem changes accordingly
- add the MenuItem
Now let’s do the same for a Button; in this case we’ll add a constructor that takes an Action :
public class Button extends com.extjs.gxt.ui.client.widget.button.Button {
public Button() {
}
public Button(String text) {
super(text);
}
public Button(String text, SelectionListener listener) {
super(text, listener);
}
public Button(final Action action) {
this(action.get(Action.NAME));
// Use the action's long description as tooltip
String longDesc = action.get(Action.LONG_DESCRIPTION);
if (longDesc != null) {
setToolTip(longDesc);
}
setEnabled(action.isEnabled());
addSelectionListener(new SelectionListener() {
public void componentSelected(ComponentEvent event) {
action.actionPerformed(event);
}
});
// make sure changes in the "enabled" state of the action are propagated
// to the Button
action.addChangeListener(new ChangeListener() {
public void modelChanged(ChangeEvent event) {
PropertyChangeEvent propertyChangeEvent = (PropertyChangeEvent) event;
if (propertyChangeEvent.getName().equals("enabled")) {
boolean enabled = (Boolean) propertyChangeEvent.getNewValue();
setEnabled(enabled);
}
}
});
}
}
You get the picture, it’s easy to generalize this to any UI component.
Conclusion
With this pattern, you can now easily create a menu item and a button, linked to the same action. If the action becomes unavailable, you call Action.setEnabled(false), and automagically the button and menu item become disabled…
PS: some of the code here is directly taken from the JDK source; I believe this is legit use under the Java Research License, but if it is not, let me know.
WebDriver: automated web UI testing
Posted by Olivier Gérardin in Java on 2009-06-04
Automating UI testing is not a trivial task, yet it is highly desirable as part of a complete non-regression test suite, which is (as everyone knows by now) a must-have for any project claiming to be agile. This is how I came across WebDriver while looking for ways to automate testing a GXT-generated frontend.
While being quite similar in its goals to Selenium, WebDriver takes a different approach: instead of interacting directly with the application’s JavaScript, it runs totally external to the browser and “drives” it, a bit like SeleniumRC.
Yes, it introduces a platform dependency, but this is mitigated by 2 points: the FirefoxDriver is available on all platforms, and you also have a HtmlDriver which is not platform-dependant, but unfortunately cannot work with JavaScript interfaces.
On the other hand, piloting the browser means you test exactly what the user will see. And depending on the browser is also a good thing because the browser is part of what you want to test! if your application has a glitch on IE which does not exist on Firefox (this is just an example of course…), then you want your tests to find out.
Writing a WebDriver test can be done in minutes. It’s simpy an API, so you can integrate it in any kind of Java code, including a JUnit test suite.
For example:
import ...
public class TestWebDriver {
public static void main(String[] args) {
WebDriver driver = new FirefoxDriver();
driver.get("http://localhost:8080/myApp/MyHostPage.html");
WebElement checkbox = driver.findElement(By.xpath("//div[@id='checkbox-id']/input"));
checkbox.setSelected();
WebElement element = driver.findElement(By.id("submit-button-id"));
element.click();
System.out.println("Page title is: " + driver.getTitle());
}
}
Can’t imagine much simpler than that. Want to test with IE ? Use InternetExplorerDriver instead of FirefoxDriver. Checking iPhone compatibility? Try IPhoneDriver.
As I’m working with GXT, there are a few things to be aware of. You will most often look for elements by ID, but of course the ID you set with GXT’s setId() is not always where you expect it to be. For example, if you set it on a Checkbox, it’s actually attached to the DIV that surrounds the INPUT element, not the INPUT element. This is why, in the example above, I used XPath to select the element, rather than direct selection by ID. When you want to access an element, the best is to have a look at the HTML by using an inspection tool such as Firebug or similar; then you can easily write an XPath expression that will select just the element you need.
WebDriver will eventually be integrated into Selenium 2.0.
GXT: tooltips on individual TreeItems
Posted by Olivier Gérardin in GWT on 2009-05-13
In the series: “how to lose time by fixing GXT stuff that should work but doesn’t“, today we address tooltips on individual TreeItems. If you ever tried to set a tooltip on a TreeItem and got frustrated because it didn’t work, you might find this post interesting:
http://extjs.net/forum/showthread.php?p=329305#post329305
As usual, a lot of time is spent working around GXT oddities, only to find new ones… For example, Component.setToolTip takes not a ToolTip, but a ToolTipConfig. Additionally, it instantiates the ToolTip. There is no way of passing an already constructed ToolTip to a Component, which means you can’t use a subclass of ToolTip. (Hint for GXT developpers: Law of Demeter)
Why Ext-GWT MVC is broken
Posted by Olivier Gérardin in GWT on 2009-03-18
Introducing Ext-GWT
Our current project is a GWT project, and we’re using Ext-GWT as a widget library and framework.
Ext-GWT (formerly MyGWT) is a “pure” Java/GWT port of the well known Ext-JS JavaScript library, not to be mistaken for gwt-ext, which is a Java/GWT wrapper around Ext-JS… Still following?
In short, gwt-ext requires Ext-JS, while Ext-GWT doesn’t. Ext-GWT is from the same company that makes Ext-JS (appropriatley called Ext), while gwt-ext is an independant work. Also, since version 2.1, Ext-JS removed LGPL from its licensing options, which effectively prevents software like gwt-ext from using it, so it’s stuck with v 2.0.x.
Anyway, this isn’t my point. Ext-GWT in its version 1.2 features a so-called “lightweight” MVC implementation, which we use on our project. Unfortunately, this implementation is quite flawed, and this isn’t harmless because it allows all sorts of problems to arise, that a clean MVC should prevent.
YAAADMVC (Yet another attempt at defining MVC)
First, it’s hard to come by a good explanation of MVC. according to Wikipedia, it was first described in 1979 by Trygve Reenskaug, and since then it has seen innumerous variations and implementations, some bright, some less bright… Judging by the number of incorrect or plainly wrong explanations you can find on the web, there must be something inherently hard to get in it. However, I’ll have my shot at explaining.
MVC is about roles. It defines three roles, namely Model, View and Controller, and how they interact. Some have interpreted these roles to be software components, which led to MVC frameworks, and some as architectural components, which led for example to so-called MVC web frameworks. Here we concentrate on the software component approach.
So what are those three roles?
- The model holds the data and provides an interface to manipulate the data.
- The view is a graphical representation of the model, and possibly also user controls (such as buttons, etc.). It is also able to generate events to any interested listeners, for example to signal a user action (button pressed, etc.)
- The controller pilots both the view and the model. It reacts to user interaction in the appropriate manner, including possibly updating the model.
This definition might not be universal, and some might disagree on some points, but it is viable.
Some important points:
- The model does not know anything of views or controllers. Ideally, it is observable and notifies its changes to any interested listeners.
- The view only has to know its model, at least enough of it to build the display. If the model is observable, the view will register as a change listener and update the display whenever the model changes. The view does not need to know its controller (and indeed you could use a view without a controller if you didn’t need user interaction)
- The controller listens to events sent by the view, and only the controller should have the intelligence to know what to do when something happens, like a user pressing a button.
Why is this important? because it cleanly separates the responsibility of each component, and we know that leads to code that is more readable, more testable and more maintainable. Less coupling, more consistency: the basis of a good architecture.
Here’s the best diagram I’ve found describing the relationships between MVC components (from http://best-practice-software-engineering.ifs.tuwien.ac.at/patterns/mvc.html):
MVC in Ext-GWT
So let’s have a look at Ext-GWT’s MVC implementation. This is the constructor of class View:
/**
* Creates a new view instance.
*
* @param controller the parent controller
*/
public View(Controller controller) {
this.controller = controller;
}
Yes, the view knows its controller… Why is it so? Looking further into the source code, we can find the explanation:
/**
* Called when a view needs to pass an event to it's controller.
*
* @param event the app event
*/
protected void fireEvent(AppEvent event) {
Controller c = controller;
while (c != null) {
if (c.canHandle(event)) {
c.handleEvent(event);
}
c = c.parent;
}
}
So apparently, the view knows its controller only to be able to send events to it… In a correctly designed system, the view should allow the controller to register itself as an event listener, thus eliminating an unnecessary dependency. We can also notice that the knowledge that controllers have a parent, and that the event should be propagated to all ancestor controllers, is all built right there into the view… ouch.
But there’s more. The handleEvent() method in class Controller is public, making it possible for anyone to call it. The problem is that, as we can see above, the handleEvent() method should only be called if canHandle() is true. Making handleEvent() a public method allows anyone to bypass this rule.
We find a different flavour of the same design flaw in method Controller.forwardToView():
/**
* Forward an event to a view. Ensures the view is initialized before
* forwarding the event.
*
* @param view the view to forward the event
* @param event the event to be forwarded
*/
public static void forwardToView(View view, AppEvent event) {
if (!view.initialized) {
view.initialize();
view.initialized = true;
}
view.handleEvent(event);
}
Here, we can see that the method View.initialize() must be called once before the first call to handleEvent(). But this is enforced only here, so it’s easy to call View.handleEvent() directly and break this rule. If handleEvent() depends on something that is done in initialize(), you can imagine what can happen. You could also call initialize() and not set initialized to true, then it would be called again the next time…
You will also notice that the existence of the Controller.forwardToView() method implies that the controller can forward events to a view. This is clearly not appropriate because what the controller really does is send orders to the view. And since the controller must know its view, it’s best to simply call a method of the view when it needs to alter it.
Of course you could send orders disguised as events, but it has two major drawbacks:
- it complicates the control flow and makes it very hard to understand
- it prevents static code analysis and refactoring that is offered by modern IDEs.
In addition, for some reason Ext-GWT event types are not defined as Java enum members, but mere integers. This makes it very difficult to identify an event from just its code, for example when stepping through code.
Bottom line: don’t use Ext-GWT’s MVC
Ext-GWT has a lot of nice things to offer, but clearly its MVC implementation is not one of them. More could be said about it, but I think you get the picture: don’t use it. Write your own clean MVC implementation from scratch, you’ll save yourself a lot of trouble.
