All posts by tristan.tarrant

Static resources versioning in web applications

I recently had trouble with a Javascript-heavy application which was deployed to the end users quite frequently in its initial stages. The problem was that users were seeing bugs which had been fixed with the latest release and that was because their browsers were caching the static resources of the web application for too long. A forced refresh (Ctrl+F5 or Ctrl+R) solved the problem but I wanted a better, automatic way.

The solution was to add a version to the path of each static resource and then use url rewriting to get the real file. In practice in my HTML I refer to resources like this:


In my case the 1.0.6 is the pom.version which I get using Maven resource filtering. I then use the wonderful URL Rewrite Filter (but I could also have used Apache’s mod_rewrite ) to rewrite URLs matching

^/[0-9]+[a-zA-Z0-9\.\-]+/(js|css|img)/(.*)$

to

/$1/$2

I think I’ll go back and apply this fix to all my apps ūüôā

Share

Too-OneBee

I have started yet another open-source project: Too-OneBee. It’s both an embeddable and standalone web console for monitoring a J2EE application. It lives at Google Code: http://code.google.com/p/too-onebee/
It embeds a javax.scripting console for running scripts within the webapp, a JMX browser, a session/request/application/server context viewer, a JNDI browser.
I would like to add pluggable handlers so that, for example, one could add Spring integration, a JDBC tool (a la phpMyAdmin), etc.

Too-One Bee - Scripting
Too-One Bee - Scripting
Share

Firefox 3.6 and Thunderbird 3.0 on Karmic

I regularly use Thunderbird 3.0 betas on my Karmic via the Ubuntu Daily Mozilla PPA. Unfortunately the PPA also contains snapshot builds of Firefox 3.5 and XulRunner 1.9.1, which I want to keep at their standard Ubuntu versions. To make apt-get upgradeing as painless as possible I am using package pinning to stop unwanted packages from other repositories to override the defaults.

I have added this to my /etc/apt/preferences file:
Package: *
Pin: release o=Ubuntu,a=karmic
Pin-Priority: 900

Package: firefox-3.5
Pin: release o=LP-PPA-ubuntu-mozilla-daily,a=karmic
Pin-Priority: -10

Package: firefox-3.5-branding
Pin: release o=LP-PPA-ubuntu-mozilla-daily,a=karmic
Pin-Priority: -10

Package: firefox-3.5-gnome-support
Pin: release o=LP-PPA-ubuntu-mozilla-daily,a=karmic
Pin-Priority: -10

Package: firefox
Pin: release o=LP-PPA-ubuntu-mozilla-daily,a=karmic
Pin-Priority: -10

Package: firefox-gnome-support
Pin: release o=LP-PPA-ubuntu-mozilla-daily,a=karmic
Pin-Priority: -10

Package: xulrunner-1.9.1
Pin: release o=LP-PPA-ubuntu-mozilla-daily,a=karmic
Pin-Priority: -10

Package: xulrunner-1.9.1-gnome-support
Pin: release o=LP-PPA-ubuntu-mozilla-daily,a=karmic
Pin-Priority: -10

Share

Eclipse 3.6, x86_64 and Gnome proxy support

I recently took the plunge back into 64-bit Ubuntu after I originally ditched it two and a half years ago mostly because of desktop Java stuff. I am now using Eclipse 3.6M2 so that compatibility with GTK+ 2.18 is good, but I’ve encountered a problem with native proxy support: my proxy settings were completely ignored from within Eclipse. I have contributed a (very simple) patch to Eclipse’s Bugzilla and it will hopefully appear in Eclipse 3.6M4.

Share

Canyon: cleaning up

I am currently cleaning up the various Canyon SPIs (Service Provider Interface) so that the canyon object which is exposed to the scripts now has a standard interface for the various methods therein (show(), hide(), get(), etc). Next up is writing the much needed documentation, tutorial and website. I’ll try to do that when I release 0.6.0

Share

Eclipse 3.5 and GTK+ 2.18

Since GTK+ 2.18 has introduced Client Side Windows, a couple of problems have appeared in Eclipse 3.5. One of them was resolved in GTK+ 2.18.0 (https://bugzilla.gnome.org/show_bug.cgi?id=589963), the other one needs fixing at the SWT-level (https://bugs.eclipse.org/bugs/show_bug.cgi?id=287307)

Since I don’t want to run Eclipse 3.6 milestones yet, I created a small diff between the two SWT versions (3.5.1 and 3.6) and isolated the necessary changes. I am currently running Eclipse 3.5.1 with this patch on my Ubuntu Karmic installation, and it fixes the problem.

Here is the diff:
diff -urN swt-3.5/org/eclipse/swt/internal/gtk/OS.java swt-3.6/org/eclipse/swt/internal/gtk/OS.java
— swt-3.5/org/eclipse/swt/internal/gtk/OS.java¬†¬† ¬†2009-08-20 15:16:38.000000000 +0200
+++ swt-3.6/org/eclipse/swt/internal/gtk/OS.java    2009-09-17 05:24:42.000000000 +0200
@@ -4887,6 +4885,21 @@
lock.unlock();
}
}
+/**
+ * @method flags=dynamic
+ * @param window cast=(GdkWindow *)
+ * @param sibling cast=(GdkWindow *)
+ * @param above cast=(gboolean)
+ */
+public static final native void _gdk_window_restack(int /*long*/ window, int /*long*/ sibling, boolean above);
+public static final void gdk_window_restack(int /*long*/ window, int /*long*/ sibling, boolean above) {
+    lock.lock();
+    try {
+        _gdk_window_restack(window, sibling, above);
+    } finally {
+        lock.unlock();
+    }
+}
/** @param window cast=(GdkWindow *) */
public static final native void _gdk_window_scroll(int /*long*/ window, int dx, int dy);
public static final void gdk_window_scroll(int /*long*/ window, int dx, int dy) {
diff -urN swt-3.5/org/eclipse/swt/widgets/Control.java swt-3.6/org/eclipse/swt/widgets/Control.java
— swt-3.5/org/eclipse/swt/widgets/Control.java¬†¬† ¬†2009-08-07 14:50:38.000000000 +0200
+++ swt-3.6/org/eclipse/swt/widgets/Control.java    2009-09-17 05:24:42.000000000 +0200
@@ -3332,6 +3319,30 @@
region = null;
}

+void restackWindow (int /*long*/ window, int /*long*/ sibling, boolean above) {
+        if (OS.GTK_VERSION >= OS.VERSION (2, 17, 11)) {
+            OS.gdk_window_restack (window, sibling, above);
+        } else {
+            /*
+            * Feature in X. If the receiver is a top level, XConfigureWindow ()
+            * will fail (with a BadMatch error) for top level shells because top
+            * level shells are reparented by the window manager and do not share
+            * the same X window parent.  This is the correct behavior but it is
+            * unexpected.  The fix is to use XReconfigureWMWindow () instead.
+            * When the receiver is not a top level shell, XReconfigureWMWindow ()
+            * behaves the same as XConfigureWindow ().
+            */
+            int /*long*/ xDisplay = OS.gdk_x11_drawable_get_xdisplay (window);
+            int /*long*/ xWindow = OS.gdk_x11_drawable_get_xid (window);
+            int xScreen = OS.XDefaultScreen (xDisplay);
+            int flags = OS.CWStackMode | OS.CWSibling;
+            XWindowChanges changes = new XWindowChanges ();
+            changes.sibling = OS.gdk_x11_drawable_get_xid (sibling);
+            changes.stack_mode = above ? OS.Above : OS.Below;
+            OS.XReconfigureWMWindow (xDisplay, xWindow, xScreen, flags, changes);
+        }
+    }
+
boolean sendDragEvent (int button, int stateMask, int x, int y, boolean isStateMask) {
Event event = new Event ();
event.button = button;
@@ -3682,15 +3693,7 @@
if (!OS.GDK_WINDOWING_X11 ()) {
OS.gdk_window_raise (enableWindow);
} else {
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†int /*long*/ topWindow = OS.GTK_WIDGET_WINDOW (topHandle);
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†int /*long*/ xDisplay = OS.gdk_x11_drawable_get_xdisplay (topWindow);
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†int /*long*/ xWindow = OS.gdk_x11_drawable_get_xid (enableWindow);
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†int xScreen = OS.XDefaultScreen (xDisplay);
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†int flags = OS.CWStackMode | OS.CWSibling;
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†XWindowChanges changes = new XWindowChanges ();
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†changes.sibling = OS.gdk_x11_drawable_get_xid (topWindow);
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†changes.stack_mode = OS.Above;
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†OS.XReconfigureWMWindow (xDisplay, xWindow, xScreen, flags, changes);
+                restackWindow (enableWindow, OS.GTK_WIDGET_WINDOW (topHandle), true);
}
if (OS.GTK_WIDGET_VISIBLE (topHandle)) OS.gdk_window_show_unraised (enableWindow);
}
@@ -4170,29 +4173,12 @@
OS.gdk_window_lower (window);
}
} else {
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†XWindowChanges changes = new XWindowChanges ();
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†changes.sibling = OS.gdk_x11_drawable_get_xid (siblingWindow != 0 ? siblingWindow : redrawWindow);
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†changes.stack_mode = above ? OS.Above : OS.Below;
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†if (redrawWindow != 0 && siblingWindow == 0) changes.stack_mode = OS.Below;
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†int /*long*/ xDisplay = OS.gdk_x11_drawable_get_xdisplay (window);
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†int /*long*/ xWindow = OS.gdk_x11_drawable_get_xid (window);
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†int xScreen = OS.XDefaultScreen (xDisplay);
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†int flags = OS.CWStackMode | OS.CWSibling;
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†/*
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†* Feature in X. If the receiver is a top level, XConfigureWindow ()
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†* will fail (with a BadMatch error) for top level shells because top
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†* level shells are reparented by the window manager and do not share
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†* the same X window parent.¬† This is the correct behavior but it is
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†* unexpected.¬† The fix is to use XReconfigureWMWindow () instead.
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†* When the receiver is not a top level shell, XReconfigureWMWindow ()
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†* behaves the same as XConfigureWindow ().
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†*/
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†OS.XReconfigureWMWindow (xDisplay, xWindow, xScreen, flags, changes);
+            int /*long*/ siblingW = siblingWindow != 0 ? siblingWindow : redrawWindow;
+            boolean stack_mode = above;
+            if (redrawWindow != 0 && siblingWindow == 0) stack_mode = false;
+            restackWindow (window, siblingW, stack_mode);
if (enableWindow != 0) {
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†changes.sibling = OS.gdk_x11_drawable_get_xid (window);
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†changes.stack_mode = OS.Above;
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†xWindow = OS.gdk_x11_drawable_get_xid (enableWindow);
–¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†OS.XReconfigureWMWindow (xDisplay, xWindow, xScreen, flags, changes);
+                 restackWindow (enableWindow, window, true);
}
}
}
diff -urN swt-3.5/os.c swt-3.6/os.c
— swt-3.5/os.c¬†¬† ¬†2009-05-29 17:30:14.000000000 +0200
+++ swt-3.6/os.c    2009-09-17 05:24:42.000000000 +0200
@@ -5944,6 +5932,24 @@
}
#endif

+#ifndef NO__1gdk_1window_1restack
+JNIEXPORT void JNICALL OS_NATIVE(_1gdk_1window_1restack)
+    (JNIEnv *env, jclass that, jintLong arg0, jintLong arg1, jboolean arg2)
+{
+    OS_NATIVE_ENTER(env, that, _1gdk_1window_1restack_FUNC);
+/*
+    gdk_window_restack((GdkWindow *)arg0, (GdkWindow *)arg1, (gboolean)arg2);
+*/
+    {
+        LOAD_FUNCTION(fp, gdk_window_restack)
+        if (fp) {
+            ((void (CALLING_CONVENTION*)(GdkWindow *, GdkWindow *, gboolean))fp)((GdkWindow *)arg0, (GdkWindow *)arg1, (gboolean)arg2);
+        }
+    }
+    OS_NATIVE_EXIT(env, that, _1gdk_1window_1restack_FUNC);
+}
+#endif
+
#ifndef NO__1gdk_1window_1scroll
JNIEXPORT void JNICALL OS_NATIVE(_1gdk_1window_1scroll)
(JNIEnv *env, jclass that, jintLong arg0, jint arg1, jint arg2)
diff -urN swt-3.5/os_custom.h swt-3.6/os_custom.h
— swt-3.5/os_custom.h¬†¬† ¬†2009-05-29 17:30:14.000000000 +0200
+++ swt-3.6/os_custom.h    2009-09-17 05:24:42.000000000 +0200
@@ -112,6 +113,7 @@
#define gtk_status_icon_set_tooltip_LIB “libgtk-x11-2.0.so.0”
#define gtk_window_get_group_LIB “libgtk-x11-2.0.so.0”
#define gtk_window_get_opacity_LIB “libgtk-x11-2.0.so.0”
+#define gdk_window_restack_LIB “libgdk-x11-2.0.so.0”
#define gdk_window_set_keep_above_LIB “libgdk-x11-2.0.so.0”
#define gdk_window_set_accept_focus_LIB “libgdk-x11-2.0.so.0”
#define gtk_window_set_opacity_LIB “libgtk-x11-2.0.so.0”
diff -urN swt-3.5/os_stats.c swt-3.6/os_stats.c
— swt-3.5/os_stats.c¬†¬† ¬†2009-05-29 17:30:14.000000000 +0200
+++ swt-3.6/os_stats.c    2009-09-17 05:24:42.000000000 +0200
@@ -18,8 +18,8 @@

#ifdef NATIVE_STATS

-int OS_nativeFunctionCount = 1291;
-int OS_nativeFunctionCallCount[1291];
+int OS_nativeFunctionCount = 1292;
+int OS_nativeFunctionCallCount[1292];
char * OS_nativeFunctionNames[] = {
#ifndef JNI64
“Call__IIII”,
@@ -503,6 +502,7 @@
“_1gdk_1window_1raise”,
“_1gdk_1window_1remove_1filter”,
“_1gdk_1window_1resize”,
+¬†¬† ¬†“_1gdk_1window_1restack”,
“_1gdk_1window_1scroll”,
“_1gdk_1window_1set_1accept_1focus”,
“_1gdk_1window_1set_1back_1pixmap”,
diff -urN swt-3.5/os_stats.h swt-3.6/os_stats.h
— swt-3.5/os_stats.h¬†¬† ¬†2009-05-29 17:30:14.000000000 +0200
+++ swt-3.6/os_stats.h    2009-09-17 05:24:42.000000000 +0200
@@ -511,6 +510,7 @@
_1gdk_1window_1raise_FUNC,
_1gdk_1window_1remove_1filter_FUNC,
_1gdk_1window_1resize_FUNC,
+    _1gdk_1window_1restack_FUNC,
_1gdk_1window_1scroll_FUNC,
_1gdk_1window_1set_1accept_1focus_FUNC,
_1gdk_1window_1set_1back_1pixmap_FUNC,

Share

Avoid roaming with Network Manager and HSDPA/3G dongles

Today a friend of mine asked if I knew a way to avoid connection via his HSDPA/3G dongle when in roaming: he uses Italy’s Tre network, and sometimes the connection will fall back to TIM or Vodafone, which he wants to avoid because of increased costs.

I’ve discovered that in GNOME’s Network Manager connection editor you can force a network by inserting the MCC/MNC (Mobile Network Codes), a list of which can be found at http://www.flatbatt.co.uk/Unlocking/Network_codes/network_codes.html

Editing a mobile connection to Vodafone Italy
Editing a mobile connection to Vodafone Italy
Share

Canyon Core 0.5.1

I released Canyon Core 0.5.1 today. It is available either from the Dataforte Maven Repository at http://www.dataforte.net/listing/maven/releases/ and tagged in SVN at https://canyon.svn.sourceforge.net/svnroot/canyon/tags/canyon-core/canyon-core-0.5.1/

This is the first stable release of Canyon Core, and I’ve put quite a bit of work into it over the past few years. Releases of Canyon Echo2, Canyon Cooee and Canyon Echo3 will follow shortly.

Share