Friday, November 20, 2009

More about GWT and Spring

The following was contributed by Yaakov Chaikin (one of the authors of Core Servlets and JavaServer Pages) following some conversations we had regarding an earlier post of mine.
I am only too happy to post it here, with many thanks to Yaakov for taking the time for drafting it.




Let me share one more thing with the readers of Marco's blog. Marco mentioned that he was looking for a more general approach to wiring Spring beans into GWT RPC servlets, so I'd like to offer one.

First, let's explain the basic problem as I understand it. Servlets and Spring beans live in different worlds.

Servlets' lifecycle (when they are created, loaded into memory, initialized, invoked, etc) is controlled by the container (your server). Spring bean's lifecycle is controlled by Spring. So, what does it mean? Well, let me give you an example of what can't be done as a result of this, no matter how you decide to load the Spring's config file and initialize Spring application context:

public class SomeServlet extends HttpServlet {
  @Autowired
  private SomeServiceInterface someService;

  public void doGet(.....)
}

Why won't @Autowired work here? Because for it to work you need Spring to instantiate SomeServlet. Unfortunately, this is not (at least as far as I know, not yet) possible. It's the server's job (according to the spec) to control the lifecycle of SomeServlet and therefore it
gets to decide when to create this class and make it available for requests.

So, you are left with few choices here. Fortunately, Spring helps you out quite a bit here. First, let's look at a way to load Spring configuration without having to write any code. For that, use the
following configuration in your web.xml:

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:/config.xml<</param-value>
</context-param>

<listener>
  <listener-class>
     org.springframework.web.context.ContextLoaderListener
  </listener-class>
</listener>

Now, you can use the following code in just about any web component that has access to the ServletContext (like a servlet) and pull out the Spring context:

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
...
...
ServletContext servletContext = getServletContext();
WebApplicationContext springContext =
WebApplicationContextUtils.getWebApplicationContext(servletContext);
...

Back to GWT... So, if you want to stop there, you can use the code above in your GWT RPC servlet's init() method (remember, init() will be called only once per servlet and there is only one instance of the servlet ever created by the container, handling all requests in a different thread):

public class MyGWTServlet extends RemoteServiceServlet implements MyService {
  private SomeServiceInterface someService;

  public void init() {
    ServletContext servletContext = getServletContext();
    WebApplicationContext springContext =
        WebApplicationContextUtils.getWebApplicationContext(servletContext);

    someService = (SomeServiceInterface)
        springContext.getBean("someServiceBeanId");
  }
  ...
  ...
}

In my example, "someServiceBeanId" better be configured as a singleton and be thread safe or we would have a serious multi-threading problem on our hands.

However, personally, I didn't want to stop here since I really like the idea of @Autowired together with @Service, @Component, etc.
One huge reason for this is that I use these in such a way that when I stand up my application I will know right away whether or not I messed something up in my code as far as using the Spring configured beans.

For an example of how things can go wrong, consider the servlet code above. Say, I mistyped "someServiceBeanId" and spelled it 'id' (with the lower case i). What would happen when I deploy my web application? Nothing!

Everything would be just fine: no warnings, no errors. I start using my app and everything is still fine. That is until I happen to use some functionality that happens to use that particular GWT RPC servlet. Only then will I be surprised to see a NoSuchBeanDefinitionException. Personally, I'd rather know at deployment time that something is messed up. And the fact that I deploy my web app regularly during development will point out the problem rather quickly.

So, here is the solution that I use:

First, create a SpringRegistry class which looks roughly like this:

@Component
public class SpringRegistry {
public static final String KEY = "springRegistry";

@Autowired
private SomeServiceInterface someService;

@Autowired
private SomeOtherServiceInterface someOtherService;

@Autowired
...

public SomeServiceInterface getSomeServiceInterface() {
return someService;
}

public SomeOtherServiceInterface getSomeOtherServiceInterface() {
return someOtherService;
}

...
}


Now that we have a central bean that can autowire our services, we can define another ServletContextListener to populate that bean in one place. The code for that would look roughly like this:

public class SpringRegistryInitializer implements ServletContextListener {
  /**
   * Spring framework's autogenerated name for the SpringRegistry

      *   component define above.
   */

  private static final String SPRING_REGISTRY_CONFIG_NAME = "springRegistry";

  @Override
  public void contextInitialized(ServletContextEvent event) {
    ServletContext servletContext = event.getServletContext();
    WebApplicationContext springContext =
        WebApplicationContextUtils.getWebApplicationContext(servletContext);

    // Manually retrieve spring registry from spring context
    SpringRegistry springRegistry = (SpringRegistry)
        springContext.getBean(SPRING_REGISTRY_CONFIG_NAME);


    // Store SpringRegistry in servlet context for all web components
    // to be able to retrieve it
    servletContext.setAttribute(SpringRegistry.KEY, springRegistry);
  }

  @Override
  public void contextDestroyed(...) {}
}

ServletContextListener will now make sure that we are autowiring all of my services right from web application initialization (which is before any requests can be accepted by the spec.)

However, we must now remember to configure our new listener in web.xml and we must place our configuration somewhere after our configuration of Spring's ContextLoaderListener.
This is because our listener depends on the Spring context to be already initialized and according to the servlet spec the listeners will be executed in the order they are defined in web.xml.

If you don't want to worry about this condition, you can always do the Spring context loading yourself inside that same SpringRegistryInitializer, but it seems cleaner to me to use the already Spring provided SpringContextLoaderListener.
So, here is how our web.xml will look now:

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:/config.xml<</param-value>
</context-param>

<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<listener>
  <listener-class>yourpackage.SpringRegistryInitializer</listener-class>
</listener>

Finally, the code in our GWT RPC servlet can look like this:
public class MyGWTServlet extends RemoteServiceServlet implements MyService {
private SomeServiceInterface someService;

public void init() {
SpringRegistry registry = (SpringRegistry)
getServletContext().getAttribute(SpringRegistry.KEY);

someService = registry.getSomeService();
}
...
...
public void doSomeOperation(....) { //use someService here }
}
Note, once again, that someService better be configured as a singleton and be thread safe or we would have a serious multi-threading problem on our hands.
Also, note that this approach gives you a nice clean separation between Spring and your web application code.

In your servlet or other web component's code you are no longer even retrieving the Spring configured bean through using using the bean's configured ID. It's all hidden from your servlet code inside the SpringRegistry class.

If, for whatever reason, you don't like or are not able to use @Autowired, etc., you can still use this approach and get the benefits of making sure you that if you make a mistake, it will be clear at the first time you deploy to a web container (server).
Just remove all that autowired stuff and inside your SpringRegistry provide setters for the services and use Spring SETTER injection in your Spring config file.

You'll get the same effect.

Sunday, November 8, 2009

rsync on an SSHFS mount point

Turns out that
"If you plan [to] use rsync to sync files from your local machine to your ssh-server, you need "workaround=rename"
Otherwise, you will not be able to update an older version of a file with a newer one. Without this option, you will be able to create files and folders and delete them, but you will get an error like this, if you try to update a file:
rsync: rename "/path/to/file.Q3Btvn" -> "to/file": Operation not permitted (1)

The original entry was from a comment to this entry in Ubuntu Forums; reporting it here, as it was driving me insane (been wasting quite some time trying to figure whether it was a permission issue).

The complete /etc/fstab entry in my system looks something like:
# This mounts the entire filesystem of server on /mnt/server mountpoint
# Use with care!
sshfs#marco@server:/ /mnt/server fuse users,auto,workaround=rename 0 0

However, if you are mounting a Samba file server, and the path contains spaces, beware of the escape code for that being different from the URL one (%20) or the console (\ followed by space; as in: /fileserver/My\ Pictures).

/etc/fstab requires the \040 escape code to mount a filesystem with spaces in its pathname:
# This mounts the Samba share My Pictures on the NFS server 
#fileserver under /media/pictures
//fileserver/My\040Pictures/ /media/pictures cifs user=guest,password=,iocharset=utf8,file_mode=0777,dir_mode=0777 0 0

Sunday, November 1, 2009

Why hashCode() matters

If you have ever overridden the equals() method of Object in your class code (and who hasn't?) you will obviously also re-implemented hashcode() too, following the (ominously scary) warning in the Javadoc of equals():

Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.

Or perhaps not.

The reality is that we developers can be lazy, and sometimes laziness leads to making one assumption too many... such as that, having a sensible implementation of equals() somehow alleviates from the need of re-implementing hashCode() too.

Well, if you are like me, and you haven't heeded Sun's advice, then it's worth noting that this will soon or later bite you, and possibly pretty hard (and, I'd guess rather sooner than later...).

The reason is that the Collections framework make pretty heavy use of hashCode() to speed up such mundane matters as objects lookup and matching; unsurprisingly, especially so in the heavily-used implementation classes such as HashMap and HashSet.

In particular, the contains() method of either Collections will not do an asinine sequential sweep of the entire collection (if the concrete implementation is based directly or indirectly on either of the above two classes) using an equals() test on each element, returning true the first time an equal (in the sense defined by your implementation of equals()) element is encountered, or false otherwise.

Sun's implementation will instead use hashCode() to 'hit' the first possible 'bucket' where the element would have been stored by the HashSet, and, upon finding it (possibly) empty, it will simply assume that the Set does not contain the given element, even though an element that would have been equal (in the sense as defined by your implementation of equals()) is indeed someplace else inside that Set's internal implementation storage.

So, if you do plan to use the Collection framework with your newly-minted class, which you have implemented equals() for, then do yourself a favour and implement a suitable hashCode() too.
In fact, I suggest you do so even if you don't plan to use Collections of those objects: you know Sod's Law, now, don't you?

(and, no, there is no prize in guessing how I found out...)

Sunday, September 27, 2009

Mounting SSHFS drives in Ubuntu

If you have a remote file server that you usually access via SSH, it is extremely simple to mount a directory on your 'local' filesystem (many applications will not allow you to 'browse' to network drives when looking for files to open).

You can simply add the following to /etc/fstab (remember to mkdir -p /path/to/dir and chown it to yourself):
# sshfs (see http://ubuntuforums.org/showthread.php?t=270806)
# The lines below will NOT mount the directories automatically - use: mount /path/to/dir (no need to sudo)
# To mount an arbitrary directory use: sshfs myserver:/remote/dir /path/to/dir
sshfs#marco@myserver:/media/data/shared/media /media/multimedia fuse users,auto 0 0
executing mount /media/multimedia will make all files on myserver located in /media/data/shared/media visible (assuming user `marco` on myserver has the right permission).

To avoid having to type a password each time you mount that directory, I recommend to create a public/private key-pair (there are a number of good tutorials about how to do this, you can see http://pkeck.myweb.uga.edu/ssh/) which you will need anyway for the next step.

Mounting automatically when starting Gnome

Unlike all the other mountpoints defined in /etc/fstab, and despite the `auto` option, the sshfs ones will not mount at boot (I suspect that that is because /etc/fstab are mounted as root, who is most definitely not allowed to ssh into my server - nor into yours, right??? - and in any event, even if it were, would result in a pretty useless situation as I would have either no access to the directories, or I would have to make them all world-readable, which is a BAD idea at the best of times....)

Using .bashrc is really not an option, as it requires me to launch a terminal session, and then leave it open for the duration of my Gnome session (closing it will automatically umount my drives).

I use Gnome (at home, and KDE at work - still can't quite decide which one is better, and I laugh at all those embroiled in this religious war.... they're both excellent windows managers and leave Windows in a trail of shame and uselessness) so I'd like to have the drives mounted when I start the session, without having to launch a terminall session.

The easy option is to create a simple shell file in my ~/bin directory:
#!/bin/sh
# Mounts external drives on sshfs (not mounted automatically from /etc/fstab)

mount /media/multimedia
mount /media/www

and add it to the session startup scripts for the Gnome session: System > Preferences > Startup Applications

If you now log out and log back in (no need to reboot) you will find your sshfs mountpoints proudly showing in the local directory.

You may also want to consider changing the 'auto' option back to 'noauto' should speed up the boot process.




Friday, July 3, 2009

Using a decent blog editor

Let's face it, Blooger's editor for posts is, er, well.. "lacking" -- ok, it sucks! There, I've said it....

There are so many shortcomings with it that there's no point in listing them all here, but suffice to say that having a tiny editing window is not the most enticing UI for an editor that anyone could think of. And, don't get me started with the crazy use of <span> tags all over the place, the massive mess-up that happen when moving from the Rich Text editing to HTML editing and back, etc. etc.

The real issue with the built-in editor, has been the near-impossibility to properly format the 'code' sections (usually by means of a <pre> tag) without that being messed up by the over-zealous <span>ning thing....

Ecto

So, I'm typing this one entry right now with ecto, and, if I try to enter a class MyClass code snippet below:


public class MyClass {
public aMethod(String aString) {
return "this is lame";
}
}
this should Just Work.

But, as you can see above, It Just Doesn't.... moving back from the HTML editor, the 'beginning-of-line' spaces get stripped out, despite them being between <pre> tags.

Oh, well, on to looking for something else -- stay tuned!

Update: this is actually even worse than it appeared at first: for some unknown reason (but most likely, lousy programming skills...) when you edit a post, ecto adds a bunch of <br /> tags, just after each closing </p> tag, thus adding extra lines: there is absolutely no way of getting rid of them; even manually deleting them, they get added back up.
I had eventually had to manually 'fix' this entry in Blogger's native editor (so, it turns out, it's not so bad after all :-)

Avoid.

Flock

So I moved on to flock, a much more fully-fledged browser-type, with lots of features, gadgets, etc.
Looks a bit daunting at first sight, but by clicking randomly and probing around, it's pretty easy to get started and it took me less than five minutes to figure out how to sign on my blogger account and get started editing.

flock logo

The editor looks decent, with several options for fonts and other gadgetry, and I'll be now trying the usual trick with some code snippet, defining a new exciting LameClass that doesNothing() but with flair:

public class LameClass {
public void doesNothing() {
Sytem.out.println("with flair!");
}
}

And flock works offline too:
I'm typing this on the train, without internet connection.

It is definitely friendly enough, and I will be using it for a while to see whether it works as advertised.

Blogged with the Flock Browser

Thursday, June 11, 2009

A DiffSet generic collection

Working on a GWT project that requires fairly frequent RPC calls to the server to exchange data I was confronted with the following problem:


  • the data set itself was likely to be of fairly large size -- not massive (we are not talking tens of MBs) but not smaller either: to give a rough estimate, assume anywhere up to 500-600 kB;

  • in addition, the time taken to 'process' the full dataset (both on the server, but, more importantly on the client) was likely to be such that a user would be faced with frequent, annoying interruptions;

  • however, the actual ('incremental') changes to the data are very likely to be minimal: roughly, on a data set that may contain up to several '000s entries, probably less than 10 (and usually only 2-3) would be changed between round-trips.
I was therefore rather surprised to find that nobody seemed to have already implemented a fairly simple solution to the problem: a DiffSet<T> that essentially 'captures' the incremental changes between two Set<T> as a sequence of Commands (which I called DiffCommand).

If you are not familiar with the Command pattern, I suggest you have a good read of the Head First Design Patterns book.

I have thus created a few classes, that implement exactly this behaviour, allowing client code to 'Compute a diff' on two arbitrary Collections, one being the original dataset, the other the modified one.

'Executing the diff' on the original will re-generate the new, modified one.

Doing this on the same pair of collections would be so close to pointless to border insanity (one definition of which is expecting a different outcome from the same behaviour) -- the true value is when you have a Client / Server setup and a 'wire protocol' (such as GWT RPC) over which you need to efficiently transfer large datasets:

  1. the Client requires the data set to get started -- the Server computes it, stores it somewhere (let's call this checkPoint) and sends it over the network to the Client:

    Set<DataRecord> checkPoint = server.getData();


  2. the client stores its own local copy of checkPoint, and creates a new Collection (let's call it localCopy) that following a number of user interactions (or whatever), will be modified (records will be added, deleted or edited):

    Set<DataRecord> localCopy = new HashSet<DataRecord>(localCopy);


  3. at some point (for example, after an auto-save timer expires) the client will compute the DiffSet between localCopy and checkPoint, and send the difference to the server:

    DiffSet<DataRecord> diff = new DiffSet<DataRecord>();
    diff.computeDiff(localCopy, checkPoint);
    server.update(diff, callback);


  4. on the server side, we will have stored somewhere safe our checkPoint, which we will now update with the diff'ed data:

    public boolean update(DiffSet<DataRecord> diff) {
    Set<DataRecord> original = retrieveCheckPoint();
    diff.executeDiff(original);
    boolean success = saveCheckPoint(original);
    return success;
    }

  5. finally, in the client's callback (see GWT's RPC mechanism and callbacks) update checkPoint in case of success, or alert the user if things went pear-shape:

    AsyncCallback callback = new AsyncCallback() {
    public void onFailure(Throwable t) {
    // display 'user error'
    GWT.log(t.getClass().getName()+" was thrown because of " +
    t.getLocalizedMessage(), t);
    view.alertUser("Server Error", "Failed to save data on server ");
    }

    public void onSuccess(Boolean result) {
    if (result)
    controller.updateCheckPoint();
    }
    };


There is a lot more info in the javadoc and you can see some typical usage in the associated unit tests: the code is hosted on bitbucket, and can be retrieved using Mercurial:
$ hg clone http://bitbucket.org/marco/diffset/

Thursday, May 28, 2009

An Add / Edit ListBox for GWT

Update -- turns out that using Hyperlink is not the best solution: one is better off with Anchor widgets.
The change to the code is really trivial: simply change the constructor of the two Hyperlink widgets to look like:
Anchor addLnk = new Anchor("add");
that's it.
---
A relatively common 'widget' that one needs to use in several places all across a GWT application is what I call the "Editable ListBox", as shown in the picture below:



where one can both add one or more items to available choices, as well as edit the currently selected option.

While doing so by using standard GWT widgets is relatively straightforward, the code is 'repetitive' enough that soon as you start doing for the second time, the "smell" is so strong, one cannot help but reach out for the "refactoring medikit."



What I ended up writing is a simple AddEditListBox that displays a PopupPanel (more specifically, a DialogBox widget) that allows one to either edit the item, or add several in one go.

Interestingly enough, the class for the two dialogs is the same class (this allows for modifications to be propagated to both instances with minimal overhead, and it makes it easier to keep the same "look & feel," eliminating at the same time code duplication, with a very minimal increase in API complexity).






The additional benefit is that, in 'edit' mode, an empty entry is equivalent to a 'delete' command (and not to inserting an empty String - which actually the ListBox would allow) thus simplifying the API and saving screen real estate, thus avoiding a 'crowded' UI.

Starting from the UI component for the 'widget' we have the AddEditListBox:


/**
* Encapsulates the behaviour of a ListBox with add/edit functionality.
* This class 'decorates' the AddEditListener that it gets passed at creation to
* keep the 'backing model' (ie a Collection of Strings that will be presented in the ListBox)
* up-to-date with the user's actions.
*
* @author Marco Massenzio (m.massenzio@gmail.com)
*/
public class AddEditListBox implements AddEditListener {

protected Collection model;
protected AddEditListener listener;
protected DialogAddEdit box;
protected Panel container;
protected final ListBox list = new ListBox();

public AddEditListBox(Panel container,
Collection backingModel, AddEditListener listener) {
this.model = backingModel;
this.listener = listener;
this.container = container;
}

public AddEditListBox(Panel panel, Collection backingModel) {
this(panel, backingModel, null);
}

public void render() {
HorizontalPanel panel = new HorizontalPanel();
refreshBox();
list.setPixelSize(100, 20);
panel.add(list);
panel.add(Spacer.getXSpacer(10));
Hyperlink addLnk = new Hyperlink("add", "");
addLnk.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
linkClicked(false);
}
});
panel.add(addLnk);
panel.add(Spacer.getXSpacer(3));
Hyperlink editLnk = new Hyperlink("edit", "");
editLnk.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
linkClicked(true);
}
});
panel.add(editLnk);
container.add(panel);
}

public String getSelectedItem() {
return list.getItemText(list.getSelectedIndex());
}

private void refreshBox() {
list.clear();
for (String subject : model) {
list.addItem(subject);
}
}

public void linkClicked(boolean wasEdit) {
DialogAddEdit dlg = new DialogAddEdit(wasEdit ? getSelectedItem() : null, this, wasEdit);
dlg.show();
}

// implementation of the AddEditListener interface, follows here - see below for details
// ...
}

A few (important, in a real-life web application) details have been removed here to keep matters simple (i18n, styling of both the list box and the hyperlinks) but this is pretty much all there is to it.

A few notable points:

  • the 'backing model' is the Collection of items that is kept in sync with the UI elements;

  • the AddEditListBox does not extends the Widget class, it merely wraps it;

  • the UI components are added to a 'container' Panel, and are lined up in their very own HorizontalPanel (this has implications for CSS styling -- probably a subject for its very own blog entry...)

  • while the add / edit components are Hyperlink widgets, they do not generate History events (they actually do, but it's an empty string that the overall application can safely ignore) -- more about this later: for now simply note they implement their very own ClickHandler
And this is really all there is to the UI element, as far as the AddEditListBox goes -- next is the DialogAddEdit component, that gets created in response to the user clicking either of the add / edit anchors, and will display either of the two popups shown earlier:

/**
* A dialog box that allows the user to either add a number of items to a list
* that will be returned to the listener registered at construction) or
* to edit a value that is equally passed at construction (both the old and
* new values will be returned to the listener).
*
* This is typically used in conjunction with a {@link AddEditListBox} that
* uses this dialog to manage the add / edit commands; however, this is not
* required and this class can be used on its own.
*
* @author Marco Massenzio (m.massenzio@gmail.com)
* @see AddEditListener
*/
public class DialogAddEdit {

private static final String MSG_ADD = "Enter the value to be added in the box and " +
"hit 'Add & More' to continue adding values, 'Add & Close' when done. " +
"Blank (empty) values will be ignored:";

private static final String MSG_EDIT_ONLY = "Edit the value below, leave blank to delete it:";

/**
* When the dialog is cancelled or dismissed (with the 'Done' (or 'Save') button the {@code
* listener} gets notified
*
* @see AddEditListener
*/
protected AddEditListener listener;

/**
* the item originally passed in to be edited (if any) can be either {@code null} or empty
*/
protected String oldItem;

protected List items = new ArrayList();

/**
* Flag that, if {@code true} only allows the user to edit the one item passed in at construction.
*/
protected boolean allowEditOnly;

/**
* This dialog does not 'auto-hide' (must be dismissed via its Ok/Cancel buttons) and is 'Modal'
* (ie, all other mouse/keyboard events for any other widget are ignored).
*/
protected DialogBox dialog;

/**
* Contains the value currently being added/edited by the user
*/
protected TextBox nameBox;

protected Label statusLbl;

protected Button cancel;

protected Button okAndMore;

protected Button ok;

/**
* This constructor does not actually create the UI elements and it thus 'cheap' to call: only
* when the DialogBox is actually shown (by calling {@link #show()}) all the expensive UI widgets
* are created and initialised.
*
*


* If {@code allowEditOnly} is {@code false} the listener will be called via the
* {@link AddEditListener#itemsAdded(List)} with the list of items that have been added
* by the user.
*
* @param itemToEdit
* the original item to edit (can be {@code null} or empty)
* @param listener
* will be notified when the dialog is dismissed or canceled
* @param allowEditOnly
* if {@code true} will only allow the one item (if any) passed in as {@code itemToEdit}
* to be edited. Otherwise, a "Add & More" button will be available and the user will be
* allowed to enter multiple items.
*/
public DialogAddEdit(String itemToEdit, AddEditListener listener, boolean allowEditOnly) {
this.listener = listener;
this.oldItem = itemToEdit;
this.allowEditOnly = allowEditOnly;
}

protected void initUiElements() {
dialog = new DialogBox(false, true);
statusLbl = new Label();
statusLbl.setStylePrimaryName(Styles.MESSAGE_RED_SMALL);
nameBox = new TextBox();
nameBox.addKeyUpHandler(new KeyUpHandler() {
public void onKeyUp(KeyUpEvent event) {
if ((event.getSource().equals(nameBox)) && (event.getNativeKeyCode() == KeyCodes.KEY_ENTER)) {
if (!allowEditOnly)
okAndMore.click();
else
ok.click();
}
statusLbl.setText("");
}
});

okAndMore = new Button("Add & More");
okAndMore.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
String name = nameBox.getText();
if (name.length() > 0) {
items.add(name);
statusLbl.setText(name + " added");
}
nameBox.setText("");
nameBox.setFocus(true);
}
});

ok = new Button(allowEditOnly ? "Save" : "Add & Close");
ok.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
String name = nameBox.getText();
dialog.hide();
History.newItem("");
if (allowEditOnly) {
listener.itemEdited(oldItem, name);
} else {
if (name.length() > 0)
items.add(name);
listener.itemsAdded(items);
}
}
});

cancel = new Button("Cancel");
cancel.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
dialog.hide();
History.newItem("");
listener.editCancelled();
}
});
}

/**
* Position the popup 1/4th of the way down and across the screen, and shows the popup dialog.
*/
public void show() {
// lazy initialization only gets performed here
createDialog();
// Since the position calculation is based on the offsetWidth and offsetHeight of the popup, you
// have to use the setPopupPositionAndShow(callback) method.
//
// The alternative would be to call
// show(), calculate the left and top positions, and call setPopupPosition(left, top). This
// would
// have the ugly side effect of the popup jumping from its original position to its new
// position.
dialog.setPopupPositionAndShow(new PopupPanel.PositionCallback() {
public void setPosition(int offsetWidth, int offsetHeight) {
int left = (Window.getClientWidth() - offsetWidth) / 4;
int top = (Window.getClientHeight() - offsetHeight) / 4;
dialog.setPopupPosition(left, top);
}
});
// we have to wait until the popup is shown, or the setFocus will have no effect
nameBox.setFocus(true);
nameBox.selectAll();
}

protected void createDialog() {
initUiElements();
dialog.setText("Edit or Add items");
Panel contents = new VerticalPanel();
contents.add(new Label(createContents()));
contents.add(Spacer.getYSpacer(3));
if ((oldItem != null) && (oldItem.length() > 0)) {
nameBox.setText(oldItem);
nameBox.setSelectionRange(0, oldItem.length());
}
contents.add(nameBox);
contents.add(Spacer.getYSpacer(2));
contents.add(statusLbl);
contents.add(Spacer.getYSpacer(3));
HorizontalPanel buttons = new HorizontalPanel();
buttons.setHorizontalAlignment(HorizontalPanel.ALIGN_RIGHT);
buttons.add(Spacer.getXSpacer(15));
buttons.add(cancel);
if (!allowEditOnly) {
buttons.add(Spacer.getXSpacer(5));
buttons.add(okAndMore);
}
buttons.add(Spacer.getXSpacer(5));
buttons.add(ok);
VerticalPanel p = new VerticalPanel();
p.setHorizontalAlignment(HorizontalPanel.ALIGN_CENTER);
p.add(contents);
p.add(buttons);
dialog.setWidget(p);
}

protected String createContents() {
if (allowEditOnly) {
return MSG_EDIT_ONLY;
}
return MSG_ADD;
}

}


Again, i18n and styling largely omitted, but all the main elements are here: as you can see, the UI manipulation is heavier here, but nothing too complex either (after all, we're talking a TextBox and three buttons at most).

From a user's perspective, hitting 'Enter' saves the current value and positions the cursor for a new entry, and when done, hitting the 'Add & Close' button triggers the listener to be called -- in an 'edit only' box, hitting 'Enter' triggers the box to be dismissed and the listener to be called with the old/new value pairs.

As a small concession to usability, a 'status' message pops up when the user hits the 'Add & More' (or hits Enter) confirming the previous value has been saved: soon as the user starts typing (pedantically, soon as they hit KeyUp on the first char) the status message is dismissed.

Ok -- time to show the Listener interface (although, it should be pretty clear from the code above):
public interface AddEditListener {
/**
* Called after the user has clicked the Done (or Save) button
*
* @param items the items that have been added by the user (using the 'Add & More' button)
* Can be empty, containing only one item or many.
*/
public abstract void itemsAdded(List items);

/**
* One of the items the dialog was called to edit, has been deleted
*
* @param item the one that was selected by the user to be deleted
*/
public abstract void itemDeleted(String item);

/**
* The user has dismissed the dialog box, clicking on its Done (or Save) button
*
* @param oldValue the value that was originally passed in to be edited
* @param newValue the new value, as accepted by the user
*/
public abstract void itemEdited(String oldValue, String newValue);

/**
* The dialog was dismissed by the user by clicking on 'Cancel' button.
*/
public abstract void editCancelled();
}


Nothing too fancy here, the twist being in the AddEditListBox in that it "Decorates" the Listener it gets passed at construction, so as to keep the backing model in sync (and thus removing the burden from the API client):

  // implementation of the AddEditListener interface,
// "decorates" the listener passed in at construction

public void editCancelled() {
// nothing to do here
if (listener != null)
listener.editCancelled();
refreshBox();
}

public void itemDeleted(String item) {
model.remove(item);
if (listener != null)
listener.itemDeleted(item);
refreshBox();
}

public void itemEdited(String oldValue, String newValue) {
model.remove(oldValue);
if ((newValue != null) && (newValue.length() > 0))
model.add(newValue);
if (listener != null)
listener.itemEdited(oldValue, newValue);
refreshBox();
}

public void itemsAdded(List items) {
model.addAll(items);
if (listener != null)
listener.itemsAdded(items);
refreshBox();
}

In fact, unless the client has some specialised need, it needs not even implement the Listener interface itself, and can just leave it to the AddEditListBox to deal with it -- for that reason, I have the two constructors, one which takes an AddEditListener, the other who doesn't:


public AddEditListBox(Panel container, Collection backingModel, AddEditListener listener) {
// ...
}

public AddEditListBox(Panel panel, Collection backingModel) {
this(panel, backingModel, null);
}

So, for a generic client, adding an "add/edit list box" is pretty straightforward:

// ...
VerticalPanel acctMgtPanel = new VerticalPanel();
acctMgtPanel.add(Spacer.getXSpacer(15));
Label subjectsHeading = new Label();
subjectsHeading.setText("School subjects");
subjectsHeading.setStylePrimaryName(Styles.HEADING);
acctMgtPanel.add(subjectsHeading);
AddEditListBox subjectsBox = new AddEditListBox(acctMgtPanel, getModel().getSubjects());
subjectsBox.render();
// ...

and it does not even need to implement the Listener interface (I still think there is value in providing maximum flexibility when implementing "general utility" classes, and there may definitely be cases in which one may want to add a listener ability -- for example, to filter unwanted or disallowed entries, react to others, warn the user of invalid ones, etc.).

A couple of points worth of note:
  • the classes above follow Joshua's "Favor Composition over Inheritance" principle -- so instead of extending the Widget or DialogBox classes, they wrap them instead;

  • implementing, as well as having a private member of type AddEditListener, follows the well-known Decorator pattern, the most famous example(s) of which are the InputStream family: if you are not familiar with it, I strongly suggest you read more about it (the Head First book on Design Patterns is an excellent introductory text -- and if you are into refactoring and patterns, Martin Fowler's Enterprise Patterns book is a great read)

I'm afraid I cannot really post the code for download (at least, not for now) as it's part of a (hopefully, commercial one day) application I'm writing, but if you have any questions, please feel free to post them here.

Friday, May 22, 2009

GWT, Spring and JPA - not really friendly to each other

For the past several months, I have been looking for ways to integrate GWT and Spring in a way that is not as painful as it appeared to be at first.

Certainly, the new /war deployment structure of GWT 1.6 is a massive stride forward, especially for those who, like me, think that Tomcat is still the easiest way to test and deploy a web application.

Obviously, by using GWT, one no longer needs Spring MVC (it could be integrated, but, honestly the pain and suffering seem hardly worth the result) but dependency injection, at least server-side, and all the other goodies that come with Spring are a massive win-win.

In particular, I am a strong believer in the value of JPA - not least, because allows one to use ORM outside of any particular J2EE container (as it happens, I've an application currently running on a server machine, as a stand-alone Java app, that uses JPA to persist data on a MySQL database).

Unfortunately, it turns out that it's not so simple to make GWT and Spring's flavour of JPA co-operate nicely, at least not if you are developing using Eclipse, and probably not even outside of Eclipse development environment.

To understand why, one needs to know that, to work outside of a J2EE container, Spring's JPA implementation needs to 'decorate' the entity classes with Aspects that will then require one to use a specific Java Agent (see also the javadoc for java.lang.instrument):



12.6.1.3.2. General LoadTimeWeaver
For environments where class instrumentation is required but are not supported by the existing LoadTimeWeaver implementations, a JDK agent can be the only solution. For such cases, Spring provides InstrumentationLoadTimeWeaver which requires a Spring-specific (but very general) VM agent (spring-agent.jar):


<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver">
</property>
</bean>

Note that the virtual machine has to be started with the Spring agent, by supplying the following JVM options:

-javaagent:/path/to/spring-agent.jar

[from Spring Reference manual, ver. 2.06]


Now, this work absolutely fine if you are using a Spring-powered Java application, and you want (or need) to use an EntityManagerFactory that is configured as follows:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.TopLinkJpaVendorAdapter">
<property name="showSql" value="false" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="oracle.toplink.essentials.platform.database.MySQL4Platform" />
</bean>
</property>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
</bean>
this has the advantage that one can configure multiple data sources (eg, one for testing and one for production) pointing at different schemas, or even different instances of MySQL running on different servers:

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${jdbc.url}" />
<property name="driverClassName" value="${jdbc.driver}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>

<bean id="testDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${jdbc.test.url}" />
<property name="driverClassName" value="${jdbc.driver}" />
<property name="username" value="${jdbc.test.username}" />
<property name="password" value="${jdbc.test.password}" />
</bean>

(the ${jdbc.*} expressions are parsed by a PropertyPlaceholderConfigurer and substituted from a properties files specified in its location property)
This will work by running your application with a command such as:
    java -javaagent:/var/lib/spring-framework-2.0.6/dist/weavers/spring-agent.jar com.ibw.application.MyClass
Now, to make Spring work in my GWT-based web app, I have (tentatively, I'm looking for a smarter / more general approach -- suggestions warmly welcome!) resorted to the oldest trick in the book: a Singleton, called at initialization by my servlets (either GWT RPC RemoteService implementations, or POS - Plain Old Servlets):

public class QuoteServiceImpl extends RemoteServiceServlet implements QuoteService {
private static final int MIN_SYM_LEN = 3;

private StockServiceConnector connector;
private StocksApplicationContext context = StocksApplicationContext.getInstance();

// rest of servlet code follows here....
}

where the StocksApplicationContext Singleton takes care of all the plumbing necessary to get Spring's DI framework started:
// Copyright Infinite Bandwidth ltd (c) 2009. All rights reserved.
// Created 28 Apr 2009, by marco
package com.ibw.stocks.server;

import java.util.logging.Logger;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* Singleton class that acts as the main application context for the server-side
* classes: it will initialise the Spring ApplicationContext, and generate the beans.
*
* This will also act as factory class (typically, just a thin wrapper around the Spring
* bean factories) for the main application server component(s): the business layer, DAOs, etc.
*
* To use, just invoke the {@link #getInstance() static getInstance} method, and
* invoke the desired methods on the returned instance. A further convenience method (
* {@link #getBean(String) getBean}) is provided, as a thin wrapper around Spring's
* {@link ApplicationContext#getBean(String) ApplicationContext's getBean} method.
*
* <h4>All rights reserved Infinite Bandwidth ltd (c) 2009</h4>
* @author Marco Massenzio
* @version 1.0
*/
public class StocksApplicationContext {
private static final String BEAN_DEFS_XML = "com/ibw/stocks/beans.xml";

private static Logger log = Logger.getLogger("com.ibw.stocks");
private ApplicationContext ctx;
private static StocksApplicationContext instance;

private StocksApplicationContext() {
log.info("Creating a StocksApplicationContext singleton. Bean definitions from " + BEAN_DEFS_XML);
ctx = new ClassPathXmlApplicationContext(BEAN_DEFS_XML);
}

public static StocksApplicationContext getInstance() {
if (instance == null) {
instance = new StocksApplicationContext();
log.info("A StocksApplicationContext factory has been created");
}
return instance;
}

public Object getBean(String beanName) {
return ctx.getBean(beanName);
}
}
Back to JPA, I thought that, having done all the above, I was pretty much done: unfortunately, when you launch your GWT application (either in Hosted Mode, or from within a browser) you get an exception, and it's clear that the javaagent option has not been picked up by either Jetty (currently, the embedded server in GWT's hosted mode).

The only solution I have found so far, is to use a much simpler EntityManagerFactory (*) setup (in /com/ibw/stocks/beans.xml):
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="StocksPU">
</bean>
that refers back to a Persistence Unit (in META-INFO/persistence.xml):
<?xml version="1.0" encoding="UTF-8"?>

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
version="1.0" >
<persistence-unit name="StocksPU" type="RESOURCE_LOCAL">
<class>com.ibw.stocks.model.Currency</class>
<class>com.ibw.stocks.model.Index</class>
<class>com.ibw.stocks.model.Stock</class>
<class>com.ibw.stocks.model.Quote</class>
<properties>
<property name="toplink.jdbc.driver"
value="com.mysql.jdbc.Driver" />
<property name="toplink.jdbc.url"
value="jdbc:mysql://my.server.com:3306/myschema" />
<property name="toplink.jdbc.user" value="auser">
<property name="toplink.jdbc.password" value="asifimtellingyou">
</properties>
</persistence-unit>
</persistence>

This works, but leaves me unhappy, as I now need to configure my data persistence configuration in an XML file (persistence.xml) instead of using Spring's beans properties (and the ability to inject values programmatically): I plan to explore next the possibility of using multiple Persistence Units, and use those to configure multiple configurations (eg, development, stating and production).


(*)UPDATE: although in the original post, this may be overlooked: this is, in fact, what tripped Yaakov (see comments below) and caused the server to complain about
"No persistence unit with name 'xxxx' found."
It took us an entertaining googlechat session when I felt compelled to explain to him things such as where to put WEB-INF, and then he eventually figured out what the problem was by himself, tracking down an old post of mine to GWT Group.

Why was that "entertaining"? well, this is the very same Yaakov Chaikin of Core Servlets and JavaServer Pages ... I just had no idea at the time!
Blogged with the Flock Browser

Using Mercurial as DSCM

A long time ago, I'd set up a CVS repository on my server, and, what with the dev team being of rather small size (at times, of size 1...) I never really felt the urge to move on with the times; I have considered several times 'upgrading' to SVN, but never really got round to it (also, scathing comments from other folks never really made me believe that it was The Right Thing for us).

However, I've recently started some development with some friends and we are, by necessity, operating in a very 'distributed' manner and we really need the ability to work also in 'disconnected' mode: myself in particular, what with being often working on a train on my way to London...

Having heard about Mercurial and always thought it would be good to give it a go, I decided today to install on my two Ubuntu boxes (the desktop and the home server) and that was as painless as it can possibly get:

sudo apt-get install mercurial

and you're set.



Tortoise is one of the best-written 'Explorer extensions' for Windows and undoubtedly one of the reasons why I stuck along with CVS for as long as I did - there is also a TortoiseHG extension for Linux, and I've (again) installed it with extreme ease.

I will soon try out the Eclipse plugin (that is pretty critical for my workflow) but the first impression is that this really is a very lightweight, yet powerful DSCM (and we now support it on Google Code too).

Sunday, May 10, 2009

Fixing the Network Manager applet in Ubuntu


Once again, after an update, the NM applet refused to co-operate and started showing all connections as 'unmanaged'.
This relates to Bug #280417, and the fix was rather simple:
Whatever updates occurred in the last day set all the devices to managed=false in /etc/NetworkManager/nm-system-settings.conf

Change that and run sudo killall nm-system-settings and it'll start working again.


I'm posting it here more as a note to self, than anything else.

And as I am in 'note-to-self' mode, it may be worth pointing out that, to configure a static IP address one has to edit:


/etc/network/interfaces

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
address 192.168.1.50
netmask 255.255.255.0
gateway 192.168.1.1
broadcast 192.168.1.255
network 192.168.1.0





/etc/resolve.conf

nameserver 192.168.1.1
# The following are the DNS servers for VirginMedia:
nameserver 194.18.4.100
nameserver 194.18.8.100