Sunday, 28 October 2007

No SilverLight for Linux?

I've just been to the MLB video site, and it tells me that I'll need to install SilverLight to view the videos! Following the links to install it takes you to the Microsoft site where I find out its only available for Windows and OS X. Searching Google it looks as though the Linux version is still in progress. Guess I'll have to skip the baseball until next year.

Upgrading to Ubuntu 7.10

I've been running Ubuntu on my laptop for a while now - I think I started with 6.10 and then reinstalled when 7.04 came out, and just now I've done a clean install of 7.10. It hasn't gone totally smoothly though. I've had problems with wireless, suspend and hibernate.

I was hoping 7.10 would resolve most of these problems, and I got quite excited when wireless worked straight out of the box. I set the laptop to suspend when the lid was closed, and when I closed the lid, it tried to suspend and failed- when I tried to use it again, it seemed to wake up but then immediately hibernated and powered off.

After resuming the machine, no surprise that the wireless no longer worked. It was the same problem as always, /var/log/dmesg revealing:
[ 17.004000] ipw2200: Radio Frequency Kill Switch is On:
[ 17.004000] Kill switch must be turned off for wireless networking to work.

(My laptop has a kill switch on the left hand side - this turns the wireless off hardware style)

I finally found something that helped here. So simple to get it going really:

  1. sudo modprobe acerhk

  2. echo 1 > /proc/driver/acerhk/wirelessled


My laptop is an ITC Millennia 6100 - I think this is essentially an Acer CL56 (I say that because it came with a CD-ROM labelled CL56 Users manual).

Suspend is still hit and miss. I tried it a few times just yesterday and both suspend and hibernate worked. I wasn't running many applications. However, today after leaving the machine alone for a while I came back to see that when I tried to wake it, suspend had failed and then it went and hibernated.

Oh well, its getting better. Maybe my laptop is too old. I bought it probably 3-4 years ago. I'm planning on moving to a desktop soon - cheaper, more powerful and brand new. I don't need to be super mobile at the moment anyway.

Saturday, 27 October 2007

What to do when your domain class won't save

When developing with Grails and GORM, if a domain class fails validation when calling the save() method, you won't get an exception - save() just returns false! This is mentioned in the Gotchas page and to find out what went wrong, it suggests looking in the errors.allErrors property of your domain class.

To do this, would go something like this:


if(book.save()) {
log.info("Book saved : ${book.title}")
} else {
log.info("FAILED: book save failed")
book.errors.allErrors.each { error ->
println error
}
}


If your book class had a constraint such as:



class Book {
String title static constraints = {
title(maxSize:50)
}
}


and you set the title to be more than 50 characters, you'd see an error message:
<the value of title> exceeds the maximum size of [50]

So, remember to check the boolean returned from save().

You can find out how to enforce constaints on your domain objects in the validation documentation - notice that some of these constraints are marked with 'influences schema generation'.

Saturday, 20 October 2007

Tomcat with Apache2 Virtual Hosts

Using Apache2 with named virtual hosts is standard, but what do you do when you want to put an application on Tomcat behind these hosts?

Thats simple too...

Lets say you have configured two virtual hosts in Apache:

  1. host1.javathinking.com

  2. host2.javathinking.com

and you have two java applications you want running in Tomcat behind these virtual hosts.

To configure Tomcat-5.5.20 with named virtual hosts, update <CATALINA_BASE>/conf/server.xml to look something like this:

<Server port="9281">
<Service name="Catalina">
  <Connector port="9282" proxyPort="80" proxyName="host1.javathinking.com"/>
  <Connector port="9283" proxyPort="80" proxyName="host2.javathinking.com"/>
  <Engine name="Catalina" defaultHost="localhost">
    <Host name="host1.javathinking.com" appBase="webapps/host1">
      <Context path="" docBase="" debug="1"/>
    </Host>
    <Host name="host2.javathinking.com" appBase="webapps/host2">
      <Context path="" docBase="" debug="1"/>
    </Host>
  </Engine>
</Service>
</Server>


Notice how there is a connector for both hosts (using different ports), and each host is configured with context path = "". The applications are deployed to "webapps/host1" and "webapps/host2" but you can change that.

Now, in the Apache configuration for each virtual host I use mod_proxy to forward the requests from Apache to Tomcat using the appropriate port number. Note the security warnings in the Apache documentation about enabling the proxy module.

To enable the proxy modules, use:
sudo a2enmod proxy
sudo a2enmod proxy_http

So inside the virtual host configuration for host1.javathinking.com:
<IfModule mod_proxy.c>
ProxyRequests Off

<Proxy *>
Order deny,allow
Deny from all
Allow from all
</Proxy>

ProxyPass /index.html !
ProxyPass /sitemap.xml !
ProxyPass / http://host1.javathinking.com:9282/
ProxyPassReverse / http://host1.javathinking.com/

</IfModule>

And likewise for host2 but with 9283 as the port number.

Tuesday, 2 October 2007

Developing with Grails and Apache2

In production I use Apache2 in front of Tomcat. The configuration for this is quite simple and standard. However, while developing Grails applications I wanted to run the same configuration, so that there are very few differences between my development and production environments. In Apache, I use named virtual hosts to forward to Tomcat, and Tomcat is configured with web applications corresponding to the virtual host name, with just '/' as the context path.

Grails uses Jetty, and when running 'grails run-app' a Jetty container is configured and started. This is fine for me, I don't think I really need to switch to Tomcat in development, but running Apache2 in front of it would be very nice. This way I don't need to worry about differences in URLs.

I'm not familiar with Jetty at all, so the simplest and fastest way to get this working was to make a copy of the RunApp.groovy script that comes with Grails and change it so that it looks for the context path definition in 'application.properties' in the root of the Grails project.

Update March 7 2008:
See the comments below - I have produced a better implementation:

- appContext is now defined in Init.groovy so it is available to all scripts
- RunApp.groovy and RunWar.groovy use the appContext to configure the server and display the url.
- RunAppHttps.groovy reuses RunApp.groovy so the only change here is for displaying the url.


This is now raised in JIRA as an enhancement.

So, in $GRAILS_HOME/scripts/RunApp.groovy add the following after the 'includeTargets' directive:


def props = Ant.antProject.properties
def appContext = props.'app.context' ? props.'app.context' : grailsAppName
if(!appContext.startsWith('/')) {
appContext = "/${appContext}"
}


Now change the webContext definition:
webContext = new WebAppContext("${basedir}/web-app", "${appContext}")

For completeness, update the StatusFinal event:
event("StatusFinal", ["Server running. Browse to http://localhost:$serverPort$appContext"])

Each Grails project has an application.properties file in the root of the project. If you want to change the context path from the default, define it in this properties file like so:
app.context=/mycontextpath

Now your application can be viewed at http://localhost:8080/<app.context>, or, with Apache in front of it, http://virtualhostname/<app.context>.

In my case I want to set the context path to merely '/' so in application.properties I define:
app.context=/

And with Apache2 configured properly, I view my application at http://virtualhostname/.

Download the modified Grails 0.6 RunApp.groovy here.

Download the modified Grails 1.0-RC1 RunApp.groovy here.

Download the modified Grails 1.0-RC2 RunApp.groovy here.

Download the modified Grails 1.0-RC3 RunApp.groovy here.

Download the modified Grails 1.0 RunApp.groovy here.

Download the modified Grails 1.0.1 scripts here: grails-1.0.1-context-path-mod.tar.gz