Monday, 29 December 2008

The week in review - 2008-52

I've just discovered that commons-transactions offers a transactional file service allowing atomic read and writes on a filesystem.

Theres a good write up here about the evolution of Wordpress. I love stories like this, because it reinforces the fact that software doesn't have to be perfect when it is released. Releasing early and often can work, and when you do it this way, you can end up with a better product - one that is shaped by the community that uses it.

Wow, notice the file size difference based on type here:

  • 22MB mp3 format file

  • 7MB ogg format file


I wonder if they sound the same? If I get time I'll download and compare, but in the mean time I'll just hope that OGG gets more support over time.

A new garbage collector is making its way into java 7.

An interesting discussion about the direction of java. Should we ditch backwards compatibility?

Releases:

Wednesday, 24 December 2008

SoundJuicer and MP3

I wanted to convert some CDs to MP3 - normally I'd use OGG, but you can't always rely on devices being able to play that format (i.e. DVD players). I was relieved to see it is easy in Ubuntu 8.10:

  1. enable multiverse and universe repos

  2. sudo apt-get install gstreamer0.10-plugins-ugly-multiverse  sound-juicer

  3. start sound-juicer and go to Edit/Preferences and switch the format to MP3


It was that easy. I seem to remember having to do a lot more with previous versions of Ubuntu.

Tuesday, 23 December 2008

Comment spam

I've been wondering for a while why people spam blogs with comments like:
Your site is so cool, thanks it really helped me!

Or any of the many variations. Its usually obvious for several reasons (spelling and just completely out of context) that this is spam.

But why bother?

It turns out that some blogging software is set up so that if a user has commented, and the administrator has approved that comment, then subsequent comments from that user will be published automatically (without requiring admin approval). That means, once approved, that user is trusted and can comment freely.

So, if you accidentally approve this spam bait (innocently believing it to be a genuine complement) expect much more less innocent comments to appear.

In Wordpress, this setting can be found in 'Discussion settings' under 'Comment author must have a previously approved comment'.

Monday, 22 December 2008

The week in review - 2008-51

I've had to disable MemoKeys because it interferes with Intellij. I often use ALT-F1 to locate a file in the project tree, but this doesn't work because MemoKeys is intercepting the F1.

There is some awesome goodness coming in Grails 1.1 - check out the release notes for the Beta.

I just had a requirement to open an EPS file, but I found that GIMP (on Windows) doesn't natively support EPS. As documented, you need to install GhostScript and set an environment variable (i.e. GS_PROG=C:\Program Files\gs\gs8.63\bin\gswin32.exe). Restart GIMP and you should be right.

Running a VPS costs money, so reducing the amount of ram required helps. Java applications have the disadvantage of using resources even when they are not being used, so I am interested to read about this strategy which may reduce not only the upload size but the memory footprint. I don't know if anyone has measured the effect on memory - I hope it helps.

MythFrontend for viewing media over the network

I've installed MythTV frontend on my laptop so now I can view TV and recordings, and play music across the network. I had to change the backend setup to serve from the ip address instead of 'localhost', and I also changed bind-address in /etc/mysql/my.conf to use the ip address. I'm not sure if I had to change mysql, but I assume so.

I've also edited fstab to mount my media over the network so that the path on the frontend machine is exactly the same as on the backend (this was recommended in the post I found about setting the remote frontend up):
//mythtv/media /home/paul/media/ cifs credentials=/etc/samba/user,noexec 0 0

My /etc/samba/smb.conf has a corresponding entry to share the directory:

[media]
path = /home/paul/media
available = yes
browsable = yes
public = yes
writable = no

mobiusly.com launches

A friend finally launched his company mobiusly.com - I expect great things to follow, so keep an eye on this space. I expect 2009 will be a good year for mobiusly.

Keep up to date with mobiusly:

Upgrade to Mythbuntu 8.10 broke nuvexport

I didn't notice until now, but nuvexport has stopped working since my upgrade to 8.10. I found the solution here, but I needed to add the Intrepid Medibuntu repository first. The full solution:
sudo wget http://www.medibuntu.org/sources.list.d/intrepid.list --output-document=/etc/apt/sources.list.d/medibuntu.list
sudo apt-get update && sudo apt-get install medibuntu-keyring && sudo apt-get update
sudo apt-get purge ffmpeg
sudo apt-get install libavcodec-unstripped-51 libavdevice-unstripped-52 libavformat-unstripped-52 libavutil-unstripped-49 libpostproc-unstripped-51 libswscale-unstripped-0 ffmpeg
sudo apt-get install mytharchive nuvexport

Tuesday, 16 December 2008

The week in review - 2008-50

A friend must have seen my comment about JDiskReport, and mentioned WinDirStat to me. I'd never seen it before. It's a similar product to JDiskReport but for windows only.

I recently tried installing 64 bit ubuntu on a spare partition on my laptop - it already had Vista and 32 bit Ubuntu dual booted with Grub. For some reason the install wouldn't complete and left grub broken so I couldn't boot into any OS. Easy solution - I used the 32 bit Ubuntu alternative disk which has a re-install grub option. This worked a treat. It correctly restored my boot options and the laptop was back in action.

I'm not sure why the 64 bit Ubuntu doesn't work on the laptop (Dell1525 Intel Core2 Duo Processor T5550). Looking at the comparison chart, I see that "All Intel® Core™2 Duo mobile processors feature: ... Intel® 64 architecture ... ". What gives? (The installer just fails part of the way through - no error, just freezes).

Saturday, 6 December 2008

The week in review - 2008-49

I've been looking for a convenient way to re-use some old harddisks for backup purposes. I think this cable is just what I'm looking for. It appears to support both IDE drives as well as SATA so it means I can get some extra life out of the old disks while still using it for new disks. I'm really only going to be using it for backups so it should be just the thing.

I've just upgraded my MythTV media center from MythBuntu 8.04 to 8.10. I downloaded the alternate CD rather than doing a network upgrade. The main reason for upgrading was to support my new Pinnacle Nano DVB tuner - support is built in to Ubuntu 8.10. Previously it required the drivers to be installed manually. I mounted the ISO file and ran:

  • sudo /media/cdrom0/cdromupgrade


Eventually it failed due to problems with flashplugin-nonfree and ia32-libs. I removed these packages and re-ran the upgrade and all was okay. After rebooting, the TV-out no longer worked - the NVIDIA drivers were not installed. I had to download and install them manually since the System/Hardware Drivers route didn't work. To install, you need to stop the X server:

  • Close all windows

  • Press CTRL-ALT-F1 to switch to a console

  • sudo /etc/init.d/gdm stop


Now, run the installer:

  • sudo sh NVIDIA-Linux-x86_64-177.82-pkg2.run


Following the defaults worked, and after rebooting I had TV-out working. I'm pretty happy with that - no real stress, but a bit of lost time getting the NVIDIA drivers working.

If you haven't seen JDiskReport, check it out. Its a great tool for finding out where your disk space has gone - and an even better example of how good a java application can be. It looks supurb and the webstart install makes running it seamless.

I was disappointed to see that MySQL Workbench hasn't been built on a platform independent framework (such as Eclipse or Netbeans). Thus we have to wait for different platforms (Linux & MacOS) to be supported. I'm not sure why anyone would build such a universal tool on platform specific technology these days.

I've said before what a pain dealing with commerical/licensed software is. Whenever something needs to be bought the following arguments go on for ages consuming much time and resource:

  1. how many licenses

  2. which licenses (when there are different levels of functionality)

  3. who needs them


This *really* makes me appreciate opensource. Thanks for all the great work that is being done by the community!

I have been trying to get more performance out of my Windows machine at work. After defragmenting the drive, I came across an interesting article about fragmentation and file systems.

I'm thrilled to see that SQLDeveloper supports renaming columns! I don't know if it always supported it, but it has not always been so easy. This kind of refactoring in databases is great!

Released:

Sunday, 30 November 2008

The week in review - 2008-48

I've installed Ubuntu 8.10 on my Dell 1525. I had 8.04 and I could have upgraded but I like having a clean install, and because with Linux its so easy! When I'm done I'll share my backup and re-install scripts via google-code. I've got /home on a separate partition so the installation really just means running the installer from CD, and then re-installing all of my favourite software. This is just one place where Linux is nifty - all the software is in a repository and installing it can be done from the command line so it can be scripted. And you get the latest versions automatically. No 'download and run setup.exe and click through the wizards'.

I'm happy to report that suspend and resume is almost instant - even when disconnected from the network. I haven't installed any extra software yet, so we'll see if it regresses when I have the full compliment of wares (with 8.04 and all of my added software, resuming took ages when disconnected from the network). Unluckily, volume is still only audible above 50%, and I'm not having much luck with the microphone (required for skype).

Unfortunately Memokeys doesn't doesn't paste straight into DOS windows - you have to first push your key sequence to get the text into the clipboard, then right mouse click in the dos window to paste. Sooo close. Works as expected in text editors though (I only really wanted it for dos commands though).

Theres an interesting post about java packaging here. I hear what he is saying and it makes sense, but I think I've always worked in shops that package by type. What do you do?

I'm happy to see Netbeans 6.5 supports PHP and Python. This means in addition to using Netbeans for my Grails/Groovy/Java work I can now use it for Wordpress and Google App Engine applications.

I just noticed you can use WinSCP from the command line. I've never needed to do this before, but next time I'm using windows I can script uploading sites.

One of my favourite pet-peeves with commercial application servers is the restriction of the JVM. If I was using Tomcat or Glassfish I'd be using the very latest version of the JVM. But when running a commerical application server you always come up against the "Thats not a supported configuration" argument - and therefore it is vetoed.

Apt-get is so cool. I've exceeded my bandwidth quota for this month so I'm throttled to a trickle - so apt-get is taking hours to complete downloads. But, I've been suspending and resuming during this process, and apt-get hasn't missed a beat. It just carries on like nothing happened! No broken connections, no re-tries. Suspend and resume is still working like it should (I've got mysql and mythtv-frontend installed now).

I'm using jQuery these days, and I wanted to display a spinner during ajax requests. I found the answer here.

I was using the jquery.ui.Dialog too, and found that when I closed the dialog I couldn't reopen it. The answer was here - you should only initialize it once with .dialog(options), and then use "open" to show it.

When new developers join a team, I always see them get given their predecessors machine, with all of their old files on it. What should be happening here is that IT support should re-image the machine with the Operating System, and then the development team reinstalls the required development tools. Thus the user gets a new machine that is clean and consistent with the others. Ideally, power uses should get the latest machines and this is a good oppourtunity to upgrade power users and pass the older machines on to non power users.

Hopefully installing the development tools is a one-click process (such as unzipping a zip file). I created ToolInstaller as a simple solution to installing preconfigured software, but unfortunately this is another one of my products that no-one uses!

For the first time I came across a requirement to run a java program and detect success or failure. This is easily done from a script if the program in question uses System.exit() correctly (so you can use %ERRORLEVEL% in DOS and $? in Unix to read the exit code). The problem is, the program doesn't use System.exit() properly and even worse, its a commercial closed-source product!

This is how it works:

[sourcecode language="java"]
public class ReturnCode {
public static void main(String[] args) {
System.out.println("Return code test");
System.exit(3);
}
}
[/sourcecode]

Now in your bat file:

java -cp classes ReturnCode
echo %ERRORCODE%


Working with ArcGIS 9.3 is much more fun than 9.2. The javascript and REST APIs make working with the map a lot eaiser. ArcSDE 9.3sp1 has been released : release notes.

I'm using the Geodatabase Designer extension for ArcCatalog to export a database as XML. We can put this in Subversion for version control and import this file to create our feature classes whenever we create a new environment. Unfortunately we need to use ArcCatalog to do the import. It would be good if we could script the import so it could be fully automated. Note, we also manually register as versioned with move edits to base.

With text fields in feature classes if you specify a length greater than 255 you'll end up with column type of NCLOB and a max length of 2147483647. This affected a query which was trying to order by the NCLOB column - apparently this isn't good (ORA-00932: inconsistent datatypes: expected - got NCLOB). Keeping the length less than equal to 255 results in an NVARCHAR2 column which is okay.

Released:

Monday, 24 November 2008

The week in review - 2008-47

It is a good time for releases:

Looking around the train platform today I wondered when telecommuting is going to make a significant impact. Everyone needs to be somewhere else - and that puts a lot of strain on the public transport infrastructure. I've had few jobs I couldn't have done from home effectively with decent video, voice and remote control software. Being in an office *would* be far superior if teams were effective, but from my experience most of them are dysfunctional. I think part of the problem here is that managers measure productivity by the time spent at your desk, not by your actual achievements.

Know any companies that have effective management, well run teams, good career path and its fun to work? Let me know, because I'm always looking.

I was just listening to an episode of Agile Toolkit and it just makes agile seem like a whole different world. I'd love to spend some time at some of these companies that are *really* doing agile development. I've encountered companies that pretend/claim they do it by:

  1. having meetings in which you cannot sit down

  2. using junit

  3. use the jargon (iteration/pairing etc)

  4. pair when there is a problem


In this podcast, they mention some of the reasons why agile doesn't get implemented properly and as a result fails.

Here are some interesting tips for MS Windows users. Notice the recommedation to use FireFox and VLC media player - these get my thumbs up. MemoKeys is something I've been looking for recently - I've been looking for some software that lets me store text snippets (sql, command lines etc) and paste them with a key stroke. Thanks Ruchir! Unfortunately I can't install it at work because the PCs here are configured to stop any set.exe installers running - thanks security. Security sooo good its hard to get your work done.

I like to do small pieces of work and commit often. But when tests take a long time to run you get put off doing this quickly - running lengthy tests frequently means you take a nose dive in productivity. So you start taking risks and commiting more code less frequently - and end up with a mess. Whats the answer? Don't create long running tests. Do more UNIT testing, and separate your integration tests out into a separate test suite. Unit tests that don't hit the database are fast.

I used to think it was okay to put a continuous integration server on any old PC - but now I'm thinking I want pretty fast feedback after commits. So I'd rather have it on decent performing hardware so I can know when something goes wrong minutes after the commit. And, after commiting a fix, I want to trigger a build and have the answer NOW. Not in 10 minutes. So, CI on fast hardware = GOOD.

I haven't been doing much coding at home lately, so when I do, I need to be careful to leave my 'heavy lifting' JSF attitude at work and switch into a more 'spritely' Grails attitude. Point in case, I recently typed this into a grails controller:
[sourcecode language="java"]
def id = request.getParameter('id')
def book = Book.get(Integer.valueOf(id)) // but what if id is null?
[/sourcecode]
It was then I thought I'd better do some null checking - and the little light bulb went on - this was getting too hard! So I replaced it with:
[sourcecode language="java"]
def book=Book.get(params.id)
[/sourcecode]
And thats all I needed. No null checking, no type conversion. Sweet, I love the productivity of Groovy and Grails! I would have thought the 'Enterprise' would have been the first to adopt such productivity - after all they want to lower costs and produce more! What is stopping them? Why does 'Enterprise' = HEAVY LIFTING?

Monday, 17 November 2008

The week in review - 2008-46

Something was using a port on my windows machine and consequently I couldn't run one of our applications - I came across this article which shows how to identify what application is using a port. This was extremely quick and useful and let me know which processes to kill via task manager. It worked without having to install any software.

Working with the ArcGIS Server 9.3 javascript REST apis is a breeze compared to the 9.2 JSF components. The Javascript API makes working with ArcGIS a simple Javascript exercise without huge proprietary knowledge required. To get started, you'll want to check out these resources:


Wow, SpringSource has acquired G2One! If I thought I wanted to work for SpringSource before, this doubles that feeling! Spring, Groovy and Grails has made Java development more enjoyable for me, and a heck of a lot more productive.

If you haven't seen StackOverflow yet, head over there and have a look. I like it a lot. This isn't a normal question and answer forum - see the about and FAQ sections for more information.

Another great product is Bamboo. When I first heard about it I didn't understand the need for ANOTHER continuous integration server, but now I've seen it I love it. As with all Atlassian products it is very well presented and feature complete. You can see it in action here.

I'd be quite happy to never see OC4J again. Its complete lack of IDE support has a few knock on consequences that make developing a chore at the moment. We have to run JDeveloper purely so we can edit JSPs in-place. I'm trying JavaRebel to avoid restarting for every code change, but its still a pain.

Likewise with Websphere - I still know people trapped in JDK1.4 land because they are running Websphere. The language and performance advantages of JDK 5 & 6 mean you shouldn't be running anything than JDK6! If you feel you can't migrate to JDK 6 then find out why and remove that obstacle! (How long did it take Websphere to come out with JDK5 support?)

Binary configuration files used by proprietary software which contain information such as database connection details are also a pet peeve. ArcMap MXD files are one such culprit. How am I supposed to generate configurations for different environments? At the moment I have to do it manually by copying the file, opening it, and then changing the connection details for each layer. Takes the 'automatic' out of 'automatic deployment'. I'm also having big fights trying to script the creation of feature classes and layers with the SDE. I can register point classes but I can't visualise them with SDE9.2. I'm hoping 9.3 will work...

Glasshfish v3 Prelude has been launched. I've heard good things about Glassfish, and its something I'd like to play with. I'm very keen to keep up with the latest JDK and JEE releases, an this is exactly what Glassfish does. Notice that this release offers a preview of JEE6, including JSF2.0. Even more noteworthy might be the Rapid Deployment Technology which allows you to 'edit code, save and immediately refresh browser with no loss of application state'. I'm running Netbeans 6.5 at home, so I'll have to try this out!

Apparently spam levels dropped significantly when a major spam ISP was taken offline. But it won't stay that way for long... I wonder why it isn't easier and quicker to detect them and taken them offline?

Wow, USB3 is going to be fast, but it won't be here until 2010!

For some interesting observations about software development, see Frequently Forgotten Fundamental Facts about Software Engineering. There in black and white are some observations we see every day, but might not consider formally.

Saturday, 8 November 2008

The week in review - 2008-45

When Firefox 3 came out, I remember reading a lot of fuss about the AwesomeBar - a lot of people complained about it. Well, I loved it when I first saw it, and I still love it. Occasionally I have to fire up IE6 to check some rendering and thats when I really notice how much I like the awesome bar.

Last week I mentioned disk performance and my attention has just been brought to this posting about kitting a developer machine out with SSD for great performance gains. The author compares several different machines and concludes that SSD is the way forward. Looking on the Dell site, it looks like 64GB SSD would add AUD$1000 - a bit rich for me, and for some reason you can't have both a hard disk and SSD. I'd be interested to know why, because it would be nice to combine cheap mass storage (7200 rpm hard disk) and expensive small fast storage.

On my personal projects it has become obvious that it isn't just about one language anymore (java, groovy, python, javascript etc). It also seems that with javascript libraries its not just about one library either. I'm currently using Prototype, Dojo, and jQuery in one application. If I spent enough time on it, I could probably drop one of them, but at the moment its not worth the investment.

New CPUs from Intel feature 4 cores and hyperthreading is back (and supposedly energy efficient) giving you 8 virtual cores!

I've just found http://snippets.dzone.com/. This looks like a great resource for those little pieces of code you need now and then. I'm particularly interested in the linux section - subscribing to the RSS feed might be a good way to learn new tricks!

I've been spoilt working on my personal projects using Grails and AppEngine. Back in the corporate world, restarting the app server after the smallest change in compiled code and waiting for JSPs to recompile seems unreasonable. In JSF, Facelets is the way to go, but I'll have to wait for a while before we can switch JSP to Facelets. To get around restarting the application server, JavaRebel might be an option. Anything that lets me build the application quicker would be welcome, and since I doubt I've got enough influence to make the switch to grails I'll have to investigate these options.

Doing most of my work offline (while travelling to/from the office) I appreciate offline documentation. Imagine how happy I was to find out about these cheatsheets.

What happened to http://www.savethedevelopers.org/ ? It used to be a site encouraging users to upgrade to the latest browsers, but now it redirects to a Microsoft site to download IE: http://www.microsoft.com/windows/internet-explorer/download-ie.aspx. Is this because of their campaign against IE6?

I was surprised to find that some companies block the SVN propfind requests. To check out from a remote repository you need to configure your svn tool with the proxy details, and use an HTTPS url since the firewall can't read encrypted packets. This makes it a bit difficult to check out opensource projects - looking at other projects code is a good way to learn so I'm surprised companies are this pedantic with firewalls/proxies. Unfortunately Google Code repositories only allow anonymous access over HTTP - but the Jakarta projects have an HTTPS url which doesn't require a username and password to read from (i.e. https://svn.apache.org/repos/asf/commons/proper/lang/trunk). Or, failing that you could attach the source jars from a maven repository in your IDE (i.e http://repo1.maven.org/maven2/commons-lang/commons-lang/2.4/commons-lang-2.4-sources.jar). Note, the Netbeans maven plugin makes this easy.

Monday, 3 November 2008

The week in review - 2008-44

I was happy to see 'Compile on Save' added to Netbeans. This is a feature I've always appreciated in Eclipse, its always worked and always made for a good experience. This was one of the top items preventing me from moving away from Eclipse. I want to play with it in Netbeans, and see if it measures up.

Speaking of Netbeans, the Maven plugin is awesome! It makes it easy to add a dependency to your project, through an easy to use autocompleteing dialog. With so many Java libraries around, this is the way we should have always been doing dependency management. The linked article doesn't really show how to add libraries, but try right clicking on the 'lib' directory in your project. Notice you can also download all javadoc and sources for your dependencies. So easy!!

I'm enjoying using Netbeans 6.5 for Grails development now. I haven't explored the functionality all that much, but using just the basics is effective. Hopefully this support will grow quickly. Netbeans 6.5 is now available as a release candidate.

I really would like to just start buying books as PDFs - to save space (on the bookshelf) and weight (while travelling) and trees. But what do I read them on? At the moment I'd have to use my laptop - overkill really - it gets heavy fast. I would expect that the Amazon Kindle would be ideal, but at USD 359 its a bit rich. You can buy entry level laptops for that price, and an ASUS EEE would cost less. But how comfortable is it to read on an EEE (1.1kg with a 10inch screen)?

I was disappointed to see that the Sun Tech Days conference is not coming to Australia this year. I went to the 2008 event and although I probably wouldn't be able to take time off for it in 2009 I'd like to think these kind of events are available to us.

I'm continually surprised by how bad at multitasking current multi-core computers are. If I kick off a build or launch an application, my computer is generally too unresponsive to do anything else with. I may be able to browse the web, but I can't do much more. I assume the problem here is being disk bound - I'm running windows XP on a dual core machine - Windows seems to aggressively swap to disk, even when you have lots of RAM. Perhaps RAID would help? I run Linux exclusively at home, so I'll have to compare performance for similar tasks. That'll be a bit harder, because at home I generally run lighter weight tasks than at work (smaller projects and lighter technologies i.e. Grails, Python).

I've been getting frustrated lately by the slowness of my computer at work. Its running Windows XP, and starting/restarting/reloading Intellij IDEA is a coffee break. I came across this article, and in the comments it is mentioned that an EXT filesystem would perform better than NTFS - I wonder if this would give me the boost I need?

Ubuntu 8.10 is here - I've been using 8.04 on my Dell 1525 since it came out, but have been a little inconvenienced by the odd quirk - such as intermittent failure of suspend/resume/hibernate. Sometimes after resuming it immediately hibernates. Sometimes it fails to suspend. And resuming takes an aweful long time if I'm not connected to the network. Not enough to make me switch OSes, but hopefully it will continue to get better and better.

Sunday, 26 October 2008

URI "file:./" is not hierarchical

Just recently I came across the following exception when deploying a simple Grails application to Tomcat:

URI "file:./" is not hierarchical


The application was so simple and ran locally on tomcat-6.0.16 - it had to be something environmental. Comparing the differences between machines showed that it was the JVM that was different.

The JVM that produced the error was:

java version "1.5.0"
gij (GNU libgcj) version 4.2.4 (Ubuntu 4.2.4-1ubuntu3)


while the Sun JRE 1.6 was okay:

java version "1.6.0_03"
Java(TM) SE Runtime Environment (build 1.6.0_03-b05)
Java HotSpot(TM) Client VM (build 1.6.0_03-b05, mixed mode)


Note that this occurred on Ubuntu 8.04 64 bit Linux:

Linux dev 2.6.24-21-generic #1 SMP Mon Aug 25 16:57:51 UTC 2008 x86_64 GNU/Linux

Tuesday, 21 October 2008

Somewhere to put the code

I've written a lot of code in the past, and lost a lot of code over the years too. To prevent losing anymore and to help organise things, I've set up a repository at http://code.google.com/p/javathinking/source/browse/#svn/trunk.

There's not a lot there at the moment, just a linux script to extract the audio from an MP4, and a groovy script to extract a specified database from a mysqldump file:

I've tried to keep everything self contained - documentation is in the code - and hopefully someone else will find the contents useful. I also hope it will grow and become more useful over time, but time is the problem - there is so little of it...

Saturday, 18 October 2008

ST_Intersects performance

I was just using a query which made use of the ST_INTERSECTS function:
select * from table1 where st_intersects(st_point( ?, ?, 1),shape)=1
With the data I had, this query took 30 seconds! Before launching into an investigation to find out why, I just decided to swap the parameters - this made all the difference:
select * from table1 where st_intersects(shape, st_point( ?, ?, 1))=1
Now the query returns instantly! I'm no database expert, so investigating why the first version of the query took so long would have been a waste of valuable time - when such a simple solution was at hand.

Saturday, 11 October 2008

Finding table differences in Oracle

Often there is a need to compare two databases and see the differences. I come across this a lot when releasing a new build into an existing environment - the new code runs on the development database, but the test environment needs a schema upgrade before the code will run.

There are tools that will compare schemas for you, but sometimes I just need to quickly find out what columns are missing from the target schema (this is particularly useful when comparing different development schemas and you want to quickly implement changes - production releases need much better quality control than this).

The sql below provides one solution - showing the columns that are missing from 'owner1' when compared to 'owner2' for tables that match the prefix:



This will ofcourse identify missing tables. It's primative, but its an easy way to see basic structural differences using SQL - without the need for expensive tools. Since it is basic sql, you could include this as part of an environment verification test suite, or include in your application startup procedure - providing you have access to a reference schema for comparison.

Friday, 26 September 2008

grails-jsunit-0.3

I've just released grails-jsunit-0.3 - a plugin which adds jsunit support to grails applications.

This release changes the download url for the jsunit binaries to http://internode.dl.sourceforge.net/sourceforge/jsunit/jsunit2.2alpha11.zip, and is upgraded to grails-1.0.3.

When you install the plugin, it will download the jsunit binaries from the url above to $GRAILS_HOME/downloads - if it fails, you can manually download it and put it there.

Hopefully this release fixes some problems described on the forums.

Note though, that I haven't had any luck running jsunit with FireFox 3 - a problem that is referenced here.

Thursday, 18 September 2008

Built with AppEngine and Groovy

I've just released http://blogs.morehappydogs.com/ - this is a AppEngine/Groovy blend - the application aggregates blog posts about dogs. If you are interested in dogs, check it out.

The web tier is build with AppEngine in Python. AppEngine supplies the database via Datastore. Since you can't run jobs within appengine, I wrote services in Groovy which process the feeds and upload new entries. This groovy code runs as a script on my linux server, scheduled with cron.

This approach suits me well, since I'm no Python expert, and I do like groovy. This keeps the appengine (python) minimal and essentially just the web/presentation layer. Using groovy for the backend services means I can use my Java experience and benefit from the productivity of groovy.

Tuesday, 16 September 2008

grails-selenium-0.5

I've just released a new version (0.5) of the selenium plugin, which fixes compatibility problems with Grails 1.0.3. Hopefully all is well now and I'd like to apologise to all the users out there who ran into problems. If you encounter any more issues, you can email me at paul@javathinking.com.

On another note, it would be cool to know how much a plugin is being used. For example, I've got no way of knowing if anyones actually using any of the plugins I've written so its hard to prioritise work. Perhaps we need a download counter to give a rough indication... ?

Friday, 5 September 2008

Displaying dates and times with Oracle

I use SQLDeveloper when interacting with Oracle. When viewing tables with date columns it can be frustrating that the default display does not show time (just day, month and year).

To change this behaviour, you can set the date format for your current session:
alter session set NLS_DATE_FORMAT='DD-Mon-YYYY HH24:MI:SS'
Now, when you view tables or resultsets, you'll have a more precise view of the data:
04-Sep-2008 09:07:51

Friday, 22 August 2008

MyOnlineProfile.net launches

MyOnlineProfile.net has launched - as a Google AppEngine application.

MyOnlineProfile lets you catalog your public online profiles in one place - leaving you with just one link to give your friends and one link in your email signature.

I first wrote MyOnlineProfile as a Grails application - its a small application at the moment, so it didn't take long. However I did over-engineer it. I made the classic mistake of trying to solve the wrong problems and over-optimising. Luckily with being a small application and written with such a productive framework, I'm only talking about wasting hours rather than months.

I deployed it to my Linux VPS, but unfortunately, Java based applications take up quite a bit of resources just starting up and memory on a VPS costs money (recurring money). So there just wasn't room for it.

Hence re-writing it in Python for AppEngine. Being exposed to Python has been good for me - and relatively easy since Groovy opened my mind significantly and I was ready for the experience.

In addition to the language, the AppEngine environment is very much like Grails in that infrastructure is taken care of for you - just like database access is so transparent in Grails, it is in AppEngine.

These things make writing the application about the application rather than the technology or infrastructure - just the way I like it.

Monday, 11 August 2008

Converting from Flash to AVI

If you want to convert from Flash to AVI (on linux) there is a good script here. It uses mencoder to convert files specified on the command line to XVID or DIVX - files are created using the same filename, but with an avi extension.

Thursday, 7 August 2008

Prototype, JSON and Appengine

I am using prototype in a Google Appengine project, and while it worked on my development machine, after deploying it onto the Google infrastructure prototype wasn't parsing the JSON responses anymore.

In my code, I was returning the JSON in the response text (as opposed to using X-JSON response header). The Content-Type response header was set as application/json and my javascript code used Ajax.Request() with the parameter evalJSON:true so as to parse the response text.

Running locally with the dev_appserver.py everything worked okay. However when running the deployed app, the Content-Type header was no longer being set - meaning that prototype would never parse the response text.

I'm not sure why Content-Type doesn't get set when running on the Google infrastructure yet it works on the development server. But, luckily when using Ajax.Request, you can specify evalJSON:'force' so that prototype parses the response regardless of the content-type.

Server ajax response code:
result = func(args)
# content type doesn't work when deployed
self.response.headers.add_header("Content-Type", 'application/json')
self.response.out.write(simplejson.dumps(result))
Javascript Ajax request:
new Ajax.Request('/rpc',{parameters:{action:'add'}
,method:'post',evalJSON:'force',onSuccess:function(transport) {
var result=transport.responseJSON;
...
}
}
Response headers from Google:
Content-Type:    text/html; charset=utf-8
Cache-Control:    no-cache
Content-Encoding:    gzip
Date:    Wed, 06 Aug 2008 09:56:05 GMT
Server:    Google Frontend
Content-Length:    82

Saturday, 2 August 2008

Oracle types

It frequently surprises me when seemingly simple things are missing from mature products. For example, Oracle doesn't have a boolean type. Strange but apparently true.

Never mind, this article describes how to work around this.

Friday, 1 August 2008

Rename mythtv recordings

The files Mythtv records are saved with a timestamp as a file name, making it pretty hard to figure out which file is which.

To easily identify the files, you can use mythrename.pl - I couldn't find it in my Mythbuntu installation, so I had to download it from http://svn.mythtv.org/svn/trunk/mythtv/contrib/user_jobs/. It ran okay, without any dependency problems.

This post has some useful comments on how to run it. The idea is that you can schedule it with cron to run at regular intervals so as to stay current. I'm running it so it doesn't actually rename the original files, but it makes sensibly named symbolic links to the originals:

mythrename.pl --format "\%T/\%Y-\%m-\%d \%H\%i \%- \%T \%-\%S" --link /home/paul/TVShows

For help with the options, see the wiki page or run with the --help option.

Thursday, 31 July 2008

Oracle version information

When making support requests it is always helpful to include version information about the product in question. Rather than just stating 'version X' I like to get the software to display the version information and just copy and paste it - this way there can be no confusion, and there may even be extra useful information.

So, how to display the oracle version information? I came across this useful post which suggests:
select banner from v$version;
which on the instance I'm looking at produces:
BANNER----------------------------------------------------------------
Oracle10g Enterprise Edition Release 10.2.0.3.0 - Production
PL/SQL Release 10.2.0.3.0 - Production
CORE    10.2.0.3.0       Production
TNS for Solaris: Version 10.2.0.3.0 - Production
NLSRTL Version 10.2.0.3.0 - Production
Being an SQL query is even more useful than a command line, since you can run this within your applications if you need to display such data.

Wednesday, 23 July 2008

Media center with MythTV

Last November I upgraded my desktop PC. Recently I've repurposed it as a media center running MythTV (and also for print serving/file serving etc).

The hardware is as follows:

  • Sonata III 500 W case

  • Gigabyte GA965P-S3 motherboard

  • Core2 Duo E6550 CPU

  • Gigabyte 8400GS Nvidia video card

  • WinFast DTV1000 digital tuner card

  • 320MB SATA disk

  • Kingston 1Gig DDR2 800MHz memory


Since then, I've added a 1Terabyte SATA disk - prices keep coming down every week. You can get a 1T disk for just over AUD200 now.

I installed MythBuntu 8.04 and found it a very simple process. I had to configure it for TwinView (Clone) so I've got the same output on my TV as I have on the LCD monitor. Then I had to get sound via the SPDIF optical output. To do this you have to:

  1. Unmute the ICE958 channel via alsamixer

  2. Configure MythTV to use ALSA:SPDIF and AC3 + DTS to SPDIF passthrough

  3. I also had to change my video player command to 'mplayer -ao alsa:device=spdif -fs -zoom -quiet so -vo xv %s' so that video with only stereo sound would use the SPDIF


I haven't set up a remote control yet. The TV card I have doesn't look like it is supported under LIRC. So I might look at getting a dual tuner sometime, hopefully one that has a supported remote.

The video has a slight defect when fast moving action is displayed - horizontal splits in the picture appear, but it hasn't proved too bad so far. I haven't had time to look into this one, hopefully sometime soon I'll start looking around the forums. I hope the solution isn't a better video card!

Sunday, 1 June 2008

Grails, favicon, and urls

I've just spent a little too much time trying to get my favicon working properly on a new grails application.

The issue I encountered was due to the fact that I wanted users to be able to access their accounts using '/[username]' - i.e. /paul

To accomodate this, I used a UrlMapping:
"/$id" {
  controller='display'
  action:'index'
}

Now, this meant that /favicon.ico would hit the controller, and not server the icon file. I first thought I could get around this by constraining the above mapping - so I tried:
"/$id" {
  controller='display'
  action:'index'
  constraints {
    id(notEqual:'favicon.ico')
  }
}
It seems though that the only constraint you can use is 'matches'. At least 'notEqual' resulted in a compile error, and all of the examples use 'matches'.

So I thought I'd use matches with a regular expression of to exclude the word 'favicon.ico' - turns out that matching a word is simple, but negating it is not - I couldn't find an expression to negate a word.

Anyway, I've noticed that when requesting '/favicon.ico', the $id parameter resolves to 'favicon' - the extension has been stripped off! Luckily I stumbled across a forum post pointing me to the Content Negotiation section of the user guide. You can turn off this behaviour with
  grails.mime.file.extensions = false

Luckily for me I'd restricted usernames with the constraint
matches:"[a-zA-Z0-9_-]+"

So now, I can use the same constraint on the controller:
"/$id" {
  controller='display'
  action:'index'
  constraints {
    id(matches:/[a-zA-Z0-9_-]+/)
  }
}
Since the request for '/favicon.ico' contains a dot, it fails this constraint and the controller no longer handles the request.

I wish I'd come to this conclusion more quickly (I also investigated what I could do on the Apache side of things, but didn't get anywhere), but I'm glad I've learnt what I've learnt.

Note, you don't necessarily need to do this - you can use the following code to specify an alternate url to the icon:
<link href="/common/apps/op/favicon.ico" rel="shortcut icon" type="image/x-icon"></link>

Tuesday, 13 May 2008

Firefox 2 on Ubuntu 8.04

I've been a little frustrated with the lack of my usual Firefox plugins due to most of them not being available for Firefox 3, so I've decided to install Firefox 2.

It seems apparently easy:
sudo apt-get install firefox-2

Now, I can run Firefox 2 from the command line with
firefox-2

Firefox 3 still works, by running 'firefox' - so while I can use 3 for browsing, I can use 2 for developing.

Note, I had to create a new profile for FireFox 2, because it didn't seem right to run it with the version 3 profiles (and the extensions had a few issues) - but this is fair enough. See Firefox Profiles for more information.

Wednesday, 23 April 2008

No Dialect mapping for JDBC type: -1

This Hibernate error came at me out of the blue while working on FilmSuggestions.com - I innocently added a constraint to one of my Grails domain models, setting the maxSize of one of the fields to 2000. This changed the table schema making the column type TEXT instead of VARCHAR.

The problem came from a native query:
sessionFactory.getCurrentSession().createSQLQuery(mostPopularFilmsSQL).list()

This selects the TEXT column which results in the error (as described here). Setting the dialect didn't seem to make any difference, so for now I've changed the constraint so it's back to being a VARCHAR.

Sunday, 20 April 2008

Recycling electronic waste - www.thegreenpages.com.au

I've got a couple of old computers and a collection of components that are good for nothing in todays world. But I've had trouble finding somewhere that will take it off my hands and dispose of it in an environmentally friendly way. Imagine my surprise when I saw a google advert on my own blog for http://www.thegreenpages.com.au/ - a directory of Eco friendly organisations which includes a category on recycling.

Hopefully it won't be long before I can clean out some of the rubbish.

Rhythmbox

I've just been playing with RhythmBox for the first time, and am very pleasantly surprised. This application so far takes care of my music and podcast requirements, and also supports the iTunes links you see on so many sites.

You can either copy the iTunes link and add it manually, or in FireFox, clicking on the link pops up a dialog asking what application should be used - specifying /usr/bin/rhythmbox achieves the desired result, and the podcast is added just like that.

Rhythmbox also supports my wifes ipod, which is great for managing that. Although I don't use internet radio, I'd like to and it takes care of that too.

I've still got more to play with, but so far I'm happy and will be sticking with it for the foreseeable future.

(Ubuntu 8.04Beta, Linux Dell Inspiron 1525 Laptop, 2.6.24-16-generic #1 SMP Thu Apr 10 13:23:42 UTC 2008 i686 GNU/Linux)

Saturday, 5 April 2008

Wordpress error - Allowed memory size of ## bytes exhausted

I just came across a problem using wordpress that stopped everything working - any request to the Wordpress site resulted in a blank page. In the log file for the host, I could see:
PHP Fatal error:  Allowed memory size of 8388608 bytes exhausted (tried to allocate 14592 bytes) in <path to a plugin php file>

Removing the plugin specified just meant that the error was reported for the next plugin.

Searching Google showed many discussions about this problem. Luckily the solution for me was easy enough - as described in this topic:
In <wordpress root>/wp-includes/cache.php I just added:

ini_set("memory_limit","12M");


Saturday, 22 March 2008

grails-selenium-0.4

This information is out of date - please see http://www.grails.org/Selenium+plugin



Version 0.4 of the grails selenium plugin is now available.

This version adds:

  • scripts to create and run tests

  • a postResults url for displaying the final test results


Details are as follows:

run-selenium
Runs Selenium in the specified browser.
Specify the path to your browser as a command line parameter i.e.
grails run-selenium /usr/bin/firefox

or, if the executable is on the path you would just need
grails run-selenium firefox

In your application.properties, you can specify:
selenium.auto=true
selenium.close=true
selenium.multiWindow=true
selenium.highlight=true
selenium.resultsUrl=/your/url/here (defaults to ${appContext}/selenium/postResults)
selenium.runInterval=1000
selenium.baseUrl=

See http://selenium.openqa.org/installing.html (section titled Continuous Integration) for more information on selenium and continuous integration.
create-selenium-test
Generates a new empty selenium test.

Supply the path of the test you want to create, relative to 'web-app/selenium/tests'. The extension of this must be one of html, psv, gsp. The test file will be created using the syntax based on the file extension.

Example use:
grails create-selenium-test registration/errors/InvalidUsername.gsp

creates
web-app/selenium/tests/registration/errors/InvalidUsername.gsp

create-selenium-domain-test
Generates a new selenium test for the given domain class.

Supply the name of the domain class you want to test, followed by and extension that identifies the sytax to use. The extension of this must be one of html, psv, gsp.

Example use:
grails create-selenium-domain-test book.gsp

creates
web-app/selenium/tests/book.gsp

The generated test exercises the default grails scaffolding for CRUD functionality.

postResults page
A basic postResults page is provided, and if required the results can be saved to xml.

When using grails run-selenium, you can add properties to application.properties:

  • selenium.auto=true

  • selenium.resultsUrl=/your/url/here (defaults to ${appContext}/selenium/postResults)

  • selenium.saveXmlTo=/tmp/selenium.xml


By default resultsUrl is set as  ${appContext}/selenium/postResults which is provided as a basic HTML implementation. Nothing fancy.

Download here or install with
grails install-plugin http://www.javathinking.com/grails/grails-selenium-plugin/0.4/grails-selenium-0.4.zip

Friday, 21 March 2008

grails-jsunit-0.1

This information is out of date - please see http://www.grails.org/jsUnit+plugin


grails-jsunit provides an easy and convenient way to utilize the JsUnit framework to your grails application. JsUnit allows you to unit test JavaScript functions in a similar way to using JUnit for Java.

To install the plugin, use:

grails install-plugin http://www.javathinking.com/grails/grails-jsunit-plugin/0.1/grails-jsunit-0.1.zip

This plugin adds the following new scripts:

create-jsunit-test
Generates a new empty jsunit test. Supply the path of the test you want to create, relative to 'test/jsunit/tests'.
Example use:
grails create-jsunit-test registration/mytest

creates
${basedir}/test/jsunit/tests/registration/mytest.html


run-jsunit
Runs JsUnit in the specified browser. Specify the path to your browser as a command line parameter i.e.
grails run-jsunit /usr/bin/firefox

or, if the executable is on the path you would just need
grails run-jsunit firefox


In your application.properties, you can specify:
jsunit.autoRun=true


When executing this script, it overwrites ${basedir}/test/jsunit/suiteAll.html to build a suite that references all tests in ${basedir}/test/jsunit/test.

Sunday, 16 March 2008

Firefox profiles

If you share a login with someone else (ie. family) Firefox profiles can be very useful. Likewise, if you are a developer and you have several different contexts or modes of operation, profiles can make life a lot easier.

I use them at home with family members - you can set each person up with their own profile, so all you have to do is restart Firefox (rather than logging out out of the operating system and then back on as someone else). Firefox will prompt you - asking who you want to be right now.

At work, how many times have you cleared all of your private settings while debugging, just to see if the problem is related to caching or some other previous state. Creating a profile is much easier - especially since you probably want to stay logged in to all of those websites you use every day.

Just start firefox from the command line with the parameter '-profilemanager' - you'll be prompted with a dialog so you can mange your profiles.

Read more about it here :

Looking for IT work in Australia? JobReel.com.au!

I'm currently looking for contract work, and all of the usual places offer vague job descriptions that makes it hard to differentiate one from the other. This makes it hard to decide which ones to apply for, and almost always mean that you end up applying for jobs that are totally inappropriate.

Now there is JobReel.com.au - much along the lines of jobs.joelonsoftware.com, positions must display the employer.

I'm still looking for a site that lets me specify location, price range, responsibilities and technologies - but JobReel is closer than any of the others, and from what I've seen so far, the job descriptions are more useful and realistic.

It looks relatively new to the scene - good luck!

Ohloh.net

I just discovered http://www.ohloh.net/ - this is a great site, I think the easiest way I can describe it is by saying it is like linkedin.com, but based on opensource projects. You can create an account, and then add opensource projects to your 'stack'.

You can:

  • see geographically where people with a particular project on their stack are located

  • add your experience to your profile to build your resume

  • view statistics for different languages and projects.


This is a very interesting site, and it will be interesting to see where it goes. Check out my profile.

Friday, 14 March 2008

grails-selenium-0.3

Version 0.3 of the grails selenium plugin is now available.

This version:

  • Adds GSP support for writing tests

  • Fixes bug where hidden directories were shown as suites

  • Fixes bug on windows with invalid URIs to html tests


To use GSP to generate the tests, use the <sel:test> tag, followed by nested <sel:row> tags.

<sel:row> can take either:

  • one 'line' attribute where the command, target and value are pipe separated as per the pipe separated value files

  • or separate 'command', 'target', and 'value' attributes.


Because this is a normal GSP file, you have full access to the normal variables and you could call other classes for utility methods.

An example GSP test:

<g:set var="bookTitle" value="book0d"/>
<sel:test name="MyTest">
<sel:row command="open" target="${request.contextPath}"/>
<sel:row line="clickAndWait|link=BookController"/>
<sel:row line="clickAndWait|link=New Book"/>
<sel:row command="type" target="title" value="${bookTitle}"/>
<sel:row line="clickAndWait|//input[@value='Create']"/>
<sel:row line="clickAndWait|link=Book List"/>
<sel:row line="verifyTextPresent|${bookTitle}"/>
</sel:test>

Download grails-selenium-0.3.zip

Also see:

Wednesday, 12 March 2008

grails-jttaglib-0.1

grails-jttaglib plugin is a small collection of convenience tags.

The sample code below assumes you have a domain class that looks like this:
 class Book {
String title="my new book"
String content

static def constraints = {
title(maxSize:20)
content(maxSize:200)
}
}

When using these tags, you must have the following in the page - normally in the head block:
<g:javascript library="prototype"/>

<jttext:script />

textArea

Creates a TextArea HTML element, where the maximum number of characters is
limited by the constraints on the domain object, and tabs can be allowed if
desired.

Sample use:
<jttext:textArea object="${new Book()}" name="content" allowTabs="true"/>

<jttext:statusDiv for="content" />

The number of remaining characters available are displayed in the status div.
If allowTabs is set to true, tabs can be entered in the text area.

textField

Creates a text input type using maxlength from the objects constraints.
Sample use:
<jttext:textField object="${book}" name="title"/>

Generates:
<input type="text" name="title" maxlength="20" value="my new book" id="title" />

Download grails-jttaglib-0.1.zip

Regression testing grails plugins

For regression testing the grails plugins I've released, I have a shell script that:

  1. cleans up any previous runs

  2. packages the current code for the plugin OR downloads a release from my web site

  3. creates a new grails app

  4. copies preprepared resources into this new grails app

  5. installs the plugin


Now all I have to do is run the application and test it through the browser (potential for selenium to help here?). This is great for testing the plugin against a new grails version, or just for testing code changes to the plugin itself.

I put the script in <project_home>/test/regression/run.sh and the resources in <project_home>/test/regression/resources. The resources directory contains files like domain objects etc in the same directory layout as a normal grails project. This way I just need to copy the contents of the resources directory over the top of my newly created project.

I should have written it as an ANT script though (what was I thinking?) - then it would be platform independent. I'll migrate it to ANT soon.

I'd appreciate any comments about the process though - is it useful to you?

Download the script here. Use it with care, it does delete some directories.

Regression testing grails plugins

For regression testing the grails plugins I've released, I have a shell script that:

  1. cleans up any previous runs

  2. packages the current code for the plugin OR downloads a release from my web site

  3. creates a new grails app

  4. copies preprepared resources into this new grails app

  5. installs the plugin


Now all I have to do is run the application and test it through the browser (potential for selenium to help here?). This is great for testing the plugin against a new grails version, or just for testing code changes to the plugin itself.

I put the script in <project_home>/test/regression/run.sh and the resources in <project_home>/test/regression/resources. The resources directory contains files like domain objects etc in the same directory layout as a normal grails project. This way I just need to copy the contents of the resources directory over the top of my newly created project.

I should have written it as an ANT script though (what was I thinking?) - then it would be platform independent. I'll migrate it to ANT soon.

I'd appreciate any comments about the process though - is it useful to you?

Download the script here. Use it with care, it does delete some directories.

Tuesday, 11 March 2008

Allowing tabs in a text area

In addition to controlling the maximum number of characters in a text area, I also want to allow the user to enter tabs. But default, hitting tab would move out of the text area to the next control on the page.

Overriding this behavior can be done by using the onKeyDown event controller so you can:

  1. check if the tab key has been pressed

  2. if it has, insert a tab at the current cursor location

  3. put focus back into the text area


I've extended my little TextAreaTagLib to handle an 'allowTabs' attribute. Now you can allow tabs to be entered just by using allowTabs="true". I've also incorporated the work from the TextField modification so that the number of characters can be limited based on the maxSize constraint on the object.

Sample use:
<g:javascript library=”prototype”/>
<jttext:script />
...
<jttext:textArea object="${new Book()}" name="content" allowTabs="true"/>
<jttext:statusDiv for="content" />

Please note: I've now called the tag lib JTFormTagLib.groovy, and it has both the TextArea and the TextField code in it.

Download here.

Also, I've thought about creating it as a plugin, but it's kind of small to warrant a plugin by itself - what do you think?

Allowing or denying self registration with grails-acegi plugin

The grails-acegi-0.2 plugin is great - it adds login, user management, and user registration capabilities to your application in seconds. However, I'm building a web application where I want to be able to let the deployment team decide whether users can register themselves or alternatively, have an administrator create users. I want provide these settings without the deployment unit (the WAR file) having to be modified.

I currently have a properties file for each server (DEV, STAGE, PROD) which defines properties specific to the environment - such as the email server and username/password etc. In this properties file, I also have application settings which are relevant to that environment. So, this is a good place to define a property:

myapp.registration.enabled=false


Grails has an excellent configuration strategy, and in my applications Config.groovy all I have to do is specify the external config locations:

grails.config.locations = ["file:${System.getProperty('myapp.properties')}"]


I've referenced a system property, so anyone deploying my application just needs to use the -D jvm option - when running with grails all we have to do is:

grails -Dmyapp.properties=/server/env/prod/server.properties


Now I just need to modify the RegistrationController.groovy to check this property:

def index = {
//if logon user.
if(authenticateService.userDomain()!=null){
log.info("${authenticateService.userDomain()} user hit the register page")
redirect(action:"show")
return
}

if(!(grailsApplication.config.jtchat.registration.enabled=='false')) {
def person = new Person()
person.properties = params
return ['person': person]
} else {
redirect(uri:'/')
}
}


And that's it. An easy way to provide settings to an application without modifying the WAR. Grails rocks!

Friday, 7 March 2008

Maxlength HTML attribute for domain objects

With Grails domain classes, constraints can be specified - including the maximum size of a String. For example:

class Book {
String title

static def constraints = {
title(maxSize:20)
}
}

When using 'grails generate-all' to create scaffolding, you'll notice that create.gsp and add.gsp hardcode the maxlength attribute:
<input type="text" maxlength="20" id="title" name="title"
value="${fieldValue(bean:book,field:'title')}"/>

It is possible to directly reference the constraint, meaning that the maxlength attribute is not hardcoded - and thus only defined once (in the domain object):
<input type="text" maxlength="${Book.constraints.title.getMaxSize()}"
id="title" name="title"
value="${fieldValue(bean:book,field:'title')}"/>

In fact, we can go even further and create a tag where we pass in the object itself, and the name (which matches the property name) and we can dynamically generate the maxlength and value attributes.

So when editing a book with the title set to 'my new book', the following code:
<jttext:textField object="${book}" name="title"/>

produces the following HTML:
<input type="text" name="title" maxlength="20" value="my new book"
id="title" />

The tag library to produce this is as follows:

import org.codehaus.groovy.grails.plugins.web.taglib.FormTagLib

class TextTagLib extends FormTagLib {
static namespace = "jttext"

def textField = {attrs ->
attrs.type = "text"
attrs.tagName = "textField"

def object = attrs.remove('object')
def maxlength = object.constraints."${attrs.name}".getMaxSize()
if(maxlength) {
attrs.put('maxlength', maxlength)
}
attrs.put('value', fieldValue(bean:object,field:attrs.name))

def result = field(attrs)
if (result) {
out << result
}
}
}

It makes sense to me that the tag does all of the work - it reduces duplication and makes the code more readable.

What do you think?

Thursday, 6 March 2008

Limiting the content of a TextArea

Being able to limit the length of the content entered into a TextArea can be useful for various reasons. Although not supported natively by HTML, you can achieve the same effect using Javascript - on KeyUp and KeyDown events, check the length of the textarea value and truncate if necessary. We can also display how many characters are remaining if we want to provide user feedback.

Because I've used this technique in several Grails applications, I've created a simple TagLib - you may want to customize it to your requirements.

To use it:

  • include the prototype library with <g:javascript library="prototype"/>

  • use <jttext:changeScript /> once on your page for the utility script

  • define your textarea including the maxlength attribute with <jttext:textArea id="messageField" maxlength="20" />

  • use <jttext:statusDiv for="messageField" /> to display the status message showing how many characters are left


So, a simple GSP would look like:

<html>
<head>
<g:javascript library="prototype"/>
<jttext:changeScript />
</head>

<body>

<jttext:textArea name="messageField" class="sized" style="width:320px;height:60px;" maxlength="20" />
<jttext:statusDiv for="messageField" />

</body>
</html>

Effectively what you get looks like this (the HTML code has been slightly modified to work in this post):


 


Download TagLib here.

mappings closure does not exists for class UrlMappings

I've just started working on a new grails application, and early in the piece I hit this error:
2008-03-05 18:39:20.715::WARN: Failed startup of context org.mortbay.jetty.webapp.WebAppContext@1fcb845{/jtchat,/home/prule/workspace/jtchat/web-app}
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'grailsUrlMappingsHolder': Cannot resolve reference to bean 'urlMappingsTargetSource' while setting bean property 'targetSource'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'urlMappingsTargetSource': Cannot resolve reference to bean 'grailsUrlMappingsHolderBean' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'grailsUrlMappingsHolderBean': Invocation of init method failed; nested exception is java.lang.RuntimeException: mappings closure does not exists for class UrlMappings

I'd not done much except for adding a domain class, controller, view and a test. Certainly I hadn't done anything with UrlMappings. I did have a failure installing a plugin (the converter plugin which apparently is not needed anymore?), and I am editing the project in Eclipse with the Groovy plugin.

I've no idea what caused it, but doing a 'grails clean' resolved it.

Wednesday, 5 March 2008

Sun Tech Days 2008

I'm currently attending the Sun Tech Days conference in Sydney. These events can be good for exposure to things not already on your radar, and also for catching up with colleagues you haven't seen for a while.

Some of the presentations are online if you are interested.

There is a session on 'Grails as an application framework: pros and cons' tomorrow - but so far there has no mention of Groovy or Grails (but plenty of references to JRuby, Ruby, Python, PHP, Javascript).

Update 1 :

  • Mike Cannon-Brookes presented Grails - this was a good introduction for anyone new to Grails. It appears he is very enthusiastic about it and Atlassian are using it to some extent internally.

Saturday, 1 March 2008

grails-selenium-0.2

I've just uploaded a new version of my Selenium plugin for Grails. You can download it from http://www.javathinking.com/grails/grails-selenium-plugin/0.2/grails-selenium-0.2.zip. The only significant enhancement is to support tests nested in directories.

Now, the suite page displays a list of all of the directories in the tests location. The default (top level) suite shows all tests in all directories. You can click anywhere in this suite heirarchy to load only those tests in that directory.

Let me know what you think of this implementation. There are probably several different ways to go about handling the directory structure, and this is just one implementation. I hope you find it useful!

(for more complete information about this plugin, see grails-selenium-0.1.

Thursday, 28 February 2008

grails-selenium-0.1

This release has been superseded - Please see http://grails.codehaus.org/Selenium+plugin for the latest release information.

I'm a big fan of Selenium - it lets me test my web applications easily, quickly, and inside the browser. Now I've created a Grails plugin to bring the efficiency of Selenium to Grails projects easily.

When you install this plugin, it will download the Selenium-Core distribution (currently version 0.8.3 - 1.5MB) and extract it into your grails application (into <grails project>/web-app/selenium/core). Now you simply create your Selenium tests - putting them in <grails project>/web-app/selenium/tests.

This plugin will automatically generate your test suite by listing all of the files in the selenium/tests directory. You can create tests as standard HTML as per the selenium documentation (and easily created using SeleniumIDE). Or, you can for-go the HTML for pipe delimited text files (*.psv) - this plugin will convert the pipe delimited files on the fly to HTML.

Once you have your tests in place, you can run them using the Selenium Test Runner - at http://localhost:8080/<CONTEXT_PATH>/selenium/core/TestRunner.html?test=..%2F..%2Fselenium/suite.
NOTE: Using Selenium-core means that selenium and your tests are part of your web application - if you do not want your tests packaged in your WAR when using 'grails war' you must add this to your applications Config.groovy:
grails.war.resources = {stagingDir ->
delete(dir: "$stagingDir/selenium")
}

This will remove the 'selenium' directory from the war - removing selenium-core and your tests. The SeleniumController class files are still included in your war - I haven't found a cleaner way to completely remove the plugin yet.

To test-drive this plugin, you can follow this procedure (here is a shell script which does the same):
grails create-app selenium-test
cd selenium-test
grails install-plugin http://www.javathinking.com/grails/grails-selenium-plugin/0.1/grails-selenium-0.1.zip
grails create-domain-class book
grails create-controller book

Now, modify the domain class and controller:
class Book {
String title
static constraints = {
title(unique:true)
}
}

class BookController {
def scaffold = Book
}

Now create the tests:
/web-app/selenium/tests/test1.html:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>test1</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td colspan="3">test1</td></tr>
</thead><tbody>
<tr><td>open</td><td>/selenium-test/</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=BookController</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=New Book</td><td></td></tr>
<tr><td>type</td><td>title</td><td>book1</td></tr>
<tr> <td>clickAndWait</td> <td>//input[@value='Create']</td> <td></td></tr>
<tr> <td>clickAndWait</td> <td>link=Book List</td> <td></td></tr>
<tr> <td>verifyTextPresent</td> <td>book1</td> <td></td></tr>
</tbody></table>
</body>
</html>


or alternatively as pipe delimited /web-app/selenium/tests/test2.psv:

open|/selenium-test
clickAndWait|link=BookController
clickAndWait|link=New Book
type|title|book2
clickAndWait|//input[@value='Create']
clickAndWait|link=Book List
verifyTextPresent|book2


Now run your application with grails run-app and point your browser to http://localhost:8080/selenium-test/selenium/core/TestRunner.html?test=..%2F..%2Fselenium/suite

At the top left, you'll see your test suite - on the right, you'll see the 'execute tests' where you can run the entire suite or just the selected test.

For more on Selenium, see:

Wednesday, 27 February 2008

Installing Grails on Linux

I run Linux (Ubuntu 7.10) as my desktop operating system, and it's working out well. However, every time I upgrade Grails I forget to make the script in $GRAILS_HOME/bin executable and get this error:
prule@dev2:~/workspace/film-suggestions-grails$ grails clean
Exception in thread "main" java.lang.NoClassDefFoundError: org/codehaus/groovy/grails/cli/support/GrailsStarter

So, if you find yourself with this cryptic message, it is time to RTFM - the installation instructions actually point out:
If you get an error message, try to chmod +x the grails script inside the bin directory.

When I googled this exception I got unrelated stuff. Hopefully now if you search for this you'll find this post and be up and running fast.

Note:  I experience this problem because I always download the zip distribution. If you get the tar.gz binary, extracting this will preserve the correct file permissions.

Friday, 22 February 2008

Linux VPS - RimuHosting.com

Looking to host an application on the web? The most flexible solution is to have a virtual server - JavaThinking.com and FilmSuggestions.com are hosted on a Linux VPS from RimuHosting.com. This gives me root access to my very own Linux installation where I can install anything I want and configure it any way I want.

I can recommend RimuHosting (although they are the only provider I've tried) - they have been very helpful and quick to respond to questions. Their services seem complete and appropriately priced, and the service is excellent.

They've got very useful information about Linux and Java hosting on their Bliki and in their HOWTOs.

Our VPS Hosting By RimuHosting
Java and Linux VPS Hosting by RimuHosting

Wednesday, 23 January 2008

Ubuntu mysql update

I recently tried a system update (Ubuntu 7.10), and everything but mysql get updated. Every time I tried, Update Manager reported that the mysql update failed. I found this post, which essentially says that you need to stop mysql before trying the update.

I've successfully done this, and now my update has been applied successfully.