Simon Palmer’s blog

June 10, 2013

Deploying a Play 2 App to Amazon EC2 connected to RDS

Filed under: code, Uncategorized — Tags: , — simonpalmer @ 3:04 am

Some more fun and games with deployment of Play to EC2.  Just to set the scene, I have a Play 2 app which was built locally using Java 1.7.  I connect it to an Amazon RDS MySQL instance.  All this works just fine when running from localhost on my machine.

In theory, and according to the Play Documentation, I should be able to

  1. create a standalone Play distributable using play dist
  2. copy that up to my EC2 instance
  3. explode it
  4. run start

So that’s what I tried and it didn’t work.  For a start the standard Linux AMI at Amazon ships with Java 1.6 as the default, so I had to upgrade that (see here for how to do that).

Then I had to install a set of tools to give me access to my EC2 instance.  I like WinSCP which gives me a file browser and removes all the sweat of uploading and editing files on the Linux server, and does it through SFTP so I’m safe.  You can get WinSCP here.

I also needed PuTTY, or more accurately PuTTYgen to translate from the .pem file that EC2 creates for you when you make your security group in which your instances run, to a .ppk file which PuTTY and WinSCP need.  You can get the download from here but I confess I found that page very confusing.  Basically you want the one called “A Windows installer for everything except PuTTYtel“, and get the first one on the list since there seem to be two things with the same label.

Having done that using PuTTYgen is straightforward and you have a .ppk that you can use in WinSCP.  This blog has a nice write-up about that bit, in fact it’s worth a read in general.

Lots of steps to get to the basic point of being able to connect a file browser to my EC2 instance.  One thing to remember is that the DNS entry for your instance will change every time you restart it, so your saved connection in WinSCP will go stale as soon as you restart in EC2.  The way round that is to assign an Elastic IP address, but beware, that costs money.

Having connected I can very simply upload my Play distributable to EC2.  That distributable is just a zip file, so you need to unzip it when it gets there.  It doesn’t really matter where you put it on the server, but it’s simplest to put it in your ec2-user folder as you will have all the permissions you need to do that.

At this point you need a shell on your EC2 instance so you can run commands, including the start script that comes with your dist.  I tend to use the default shell that EC2 offers, but having done all that downloading you could (perhaps should) use PuTTY to do the same thing.  If you are like me (a bit lazy), then click on your instance in the EC2 console and choose “Connect” from the “Actions” menu at the top and then select “Use Java SSH client” and you’ll get a shell.

Now navigate to the folder in which you dropped your zipped dist file and unzip it.  That couldn’t be easier, just type “unzip your-file-name.zip” and it’ll explode it to the same folder you are currently in.

Now, in theory you should just be able to type ./start and your app should be running.

That didn’t work for me.  I spent many hours while the script was silently timing out in the background googling aimlessly trying to figure out what might be wrong.  It’s worth noting that a /logs folder is created with an application.log in it, which does give some clue.  In my case I was getting the error

2013-06-10 01:43:13,855 - [ERROR] - from com.jolbox.bonecp.hooks.AbstractConnectionHook in main 
Failed to obtain initial connection Sleeping for 0ms and trying again. Attempts left: 0. Exception: java.net.ConnectException: Connection timed out

This means “I can’t connect to your database, so I can’t get started”.  I was getting an exception thrown in the SSH client window after a very long timeout, but it actually took me quite a while to spot it.  That had a slightly less cryptic message and told me that I could not connect to my database [default].

That led me down a garden path of believing that it was not trying to connect to the right database and that the application.conf file packed into the dist was wrong or missing.  A few things on stackoverflow (this one and this one and this one and this one) helped, but they basically led me down the wrong path, although the experimentation was a useful learning curve.

So, the real problem was simply that I needed to make sure that my EC2 instance was allowed to talk to my RDS instance.  Turns out you can do this all through AWS.  I had a default security group on my RDS instance and a default security group on EC2, all I had to do was add the EC2 group to the RDS group, which you do through the RDS console by selecting Security Groups and adding an EC2 Security Group, and choosing the one you are using for your EC2 instance.

I re-ran my start script and it happily connected to the database and ran my app.

BUT…

I still wasn’t done.  When I hit the page from the outside world (having assigned an elastic IP) I got a server connection error from the browser.  The last step is to make sure that the appropriate port is open to the wide world from your EC2 instance.  In the case of a Play app the default port is 9000, although you can change that, but I hadn’t, so I had to add it to the list of open ports in the EC2 security group.  You do that from the EC2 console, select Security Groups, choose the one you are using, select the “Inbound” tab and add a custom TCP rule typing 9000 as the port.

I tried to open this up on standard ports (80 and 8080) and then running the app using “./start -Dhttp.port=8080” but I couldn’t get that to work.  I suspect there are some internals of my Play app which would need to change to reflect the port change, and I was so happy to just see it all working up in the cloud I stopped there.

Advertisements

June 9, 2013

Upgrading to Java 7 on an Amazon Linux AMI

Filed under: code, Uncategorized — Tags: , — simonpalmer @ 2:37 am

OK, so I’m going to deploy a Play 2 app, backed by MySQL, into AWS.  I am using RDS for the MySQL instance, so I’m not expecting any trouble there, but my code does use Java 1.7, as does my Play 2 framework.

If you use the standard AWS AMI for 64 bit Linux (amzn-ami-pv-2013.03.1.x86_64-ebs (ami-05355a6c)) you will get Java 1.6 by default.  To be fair to Amazon, the AMI does include the Java 1.7 openjdk, but it doesn’t use it by default, you have to upgrade, and here’s how you do that after opening an SSH connection to your running instance:

sudo yum install java-1.7.0-openjdk 

All good so far, but then when I typed java -version it was still using 1.6.  So this is the little nugget I am recording in the hope that it might save you an hour of searching.  

To actually switch to using Java 1.7 you need to use the following:

sudo alternatives --config java

This will show both and you just choose 1.7.  Easy when you know how, impossible when you don’t.

 

February 10, 2011

Recruiting. Challenges.

Filed under: code, recruiting — simonpalmer @ 2:45 pm

We’ve been very actively recruiting for some time and I previously posted about the framework we’re using to assess people.  At the bottom of that post I alluded to the “programming challenges” that we developed so we could get an idea of people’s technical chops.  It’s turned into much more and I wanted to write about it because I absolutely rely on it and it is the best recruiting I have ever done.  I should give an appropriate credit at this point, I say “we developed” but they are really the work of Andrew Datars who is my VP of Architecture, I can only claim to have planted the seed, Andrew did all the really hard work of bringing them into being.

Aside from the back-patting, the other reason I wanted to write about them was because their positioning is as important as their content.  For posterity, and because I think it’ll help with the explanation, here they are:
Empathica new developer challenge
Empathica NET developer challenge
Empathica NET quality engineer challenge

I should also state up-front that we use TDD in our development work and are an Agile XP shop.  These things are important to the story because we are hiring into two roles, Developer and Quality Engineer.  We also hold true to the belief that we recruit against innate skills rather than learnt ones, and therefore place a much higher value on a person’s capacity than we do on their precise experience – although experience and knowledge are obviously highly valuable once acquired.

Given our hiring philosophy we realised we needed a way to objectively assess a person from a technical perspective and within a technical context.  We also wanted to give some flavour of the work that we do to people who may have programming skills but completely outside our domain, or little programming experience at all – and it turns out that is a pretty decent size pool of people.  We are a .Net shop and therefore wrote one for that, repeated but technology agnostic, and created a third for quality engineers which is based on a publicly available code base from Microsoft.

The process goes like this…
1) have the person in for a face to face interview
2) send them away for 10 days or so with one of the challenges
3) bring them back in and review what they have done

There’s a lot we learn through this process which has little to do with the technology:

  • Do they accept the challenge and with what sort of attitude?
  • How long do they take to come back with an answer?
  • What does their code look like (style, separation of concerns, factoring etc.)?
  • How do they respond to criticism of their code?
  • How do they interact with us as developers?
  • How well did they understand the requirements?
  • How do they think through issues and debug the code

On top of which there is the code itself and the finished application.  We position the challenges not so much as a technical test but as a topic around which we can jointly work when they come in for a technical assessment.  The objective is only partly about assessing their technical skills, and almost not at all about their knowledge and experience.  Instead we want to simulate working with the person on a concrete problem in a technology we use and a context which is close to our reality.

We find this gives us an exceptionally good read on the person.  We allow enough time in the “interview” for them to overcome their nerves although that is an important consideration, especially if the person has only limited exposure to the technology.

We further request that they bring along a code base to which they have contributed significantly, ideally a hobby project to avoid NDA issues, and we spend the second half of the interview talking through and understanding their code.

This last part is important.  We found that we could be left wondering whether problems we saw in their approach or code in the challenge were to do with a fundamental lack of understanding of coding, or just unfamiliarity with the technology of the challenge we set.  Having them talk to us on their turf was a good way of finding that out.  It also gives other valuable insights such as how they are at expressing concepts to people with no domain knowledge, how motivated they are to code in their spare time, how curious they are about a problem, what sort of business sense they have, and the picture they have of where technical competence sits in the commercial world.

When it comes right down to it we end up not really caring too much about the technical aspects of the challenge, the human factors being much more relevant and harder to extract through a normal interview process.  We try and position it as being less about the technology and more about the opportunity to work together on some code, but as a candidate it is probably hard to see past it as technical test – which of course it is.

We have hired 3 people so far through this method and have a further 10 or so in our pipeline.  The results are stunning and we are in a hiring groove which is transforming our technical organisation.

If you are reading this and want to talk to me about a job please feel free to contact me by email at careers@empathica.com and make sure you mention this article and the challenges.

March 21, 2010

*Really* simple S3 persistence from Grails

Filed under: code, Grails — simonpalmer @ 10:16 pm

I recently posted about really simple file upload in my app and once I had that working I moved onto my next problem, which was in two parts, 1) making the persistence location flexible – and scalable – and 2) providing a public url to the images.

Taking the second problem first, I thought I was going to need to find some clever way of mapping a URI to a folder on the server and I investigated about 25 ways of doing that in tomcat, jetty, apache, and anywhere else I thought might work. There are solutions, but they normally mean an additional web server and subdomain, or some such configuration, to serve static content. There is also a grails plugin for serving static images. All of this felt like a lot of infrastructure and complexity, not to mention server load, which runs against my basic “do it elsewhere, not on the server” philosophy.

For the first issue (scalable persistence) I looked at where in the standard AWS AMI I was using I could place content and the choices are limited because I wanted sub-folders for each of my users and giving rights to processes on the server instance to create folders was also looking like a lot of non-standard config.

In steps Amazon S3. The solution is really very simple. Sign up for an AWS S3 account, create a bucket with a unique name for the app, add buckets for each user (they already have a UID to identify them) and back the asynchronous upload with a simple write to S3 from my controller. If you make the assets publicly readable then you can expose them through the regular s3.amazonaws.com url and you don’t need any other server infrastructure for your static file serving (*jumps up and down with glee*). Of course, there’s a Grails plugin for S3, so that’s where I started, and before I go much further I should say that I think that does the job very thoroughly and you should try that before you take my hack – at the very least download the code and study it closely, it is well written.

But… I didn’t want to involve my database and my file system in the upload process and I never anticipate needing a background process for doing the upload to the buckets, so it was breaking my self-imposed KISS rules.

So, “how hard could it be”? Here’s how.

First it is a good idea to grab the Jets3t library, which is brilliant. I found the install all a bit weird, but there is a jar file in the jets3t-XXX/applets folder – at least there was in the download I grabbed – and you basically need to stick that in your lib folder under your Grails app. If you are using the STS Eclipse plug-in you’ll need to add the jar as an external library to your project properties to have it compile, run, work, etc.

It’s a good idea to write a Grails Service for this, so you start by doing that

grails create-service AmazonS3

And here’s the code for the service… this is admittedly very simplistic and it needs some error handling, but you’ll figure that out…

import org.jets3t.service.S3Service
import org.jets3t.service.security.AWSCredentials
import org.jets3t.service.impl.rest.httpclient.RestS3Service
import org.jets3t.service.model.S3Bucket
import org.jets3t.service.model.S3Object
import org.jets3t.service.acl.AccessControlList

class AmazonS3Service {
	
	static String accessKey="PUTYOUROWNONEINHERE"
	static String secretKey="PUTYOUROWNONEINHERE"
	static RestS3Service s3 = new RestS3Service(new AWSCredentials(accessKey, secretKey))
        boolean transactional = false
	String rootBucketPath="yourbucket/subbucket/whatever/"
	String defaultBucketLocation=S3Bucket.LOCATION_EUROPE
	
	Map mimeExtensionMap = [
			"png" : "image/png",
			"jpg": "image/jpeg",
			"gif": "image/gif",
			"tiff": "image/tiff",
			"pdf": "application/pdf",
			"mpeg": "video/mpeg",
			"mp4": "video/mp4",
			"mov": "video/quicktime",
			"wmv": "video/x-ms-wmv",
			"html": "text/html",
			"xml": "text/xml",
			"mp3": "audio/mpeg",
			"flv": "application/octet-stream"
	]
	
	S3Bucket makeBucket(uid)
	{
		S3Bucket bucket = s3.getOrCreateBucket((rootBucketPath + uid), defaultBucketLocation)
		bucket.setAcl AccessControlList.REST_CANNED_PUBLIC_READ
		return bucket
	}
	
	void put(inputstream, name, uid, ext, length)
	{
		if (mimeExtensionMap.containsKey(ext.toLowerCase()))
		{
			String mime = mimeExtensionMap[ext.toLowerCase()]; 
			S3Bucket bucket = makeBucket(uid)
			S3Object up = new S3Object()
			up.setAcl AccessControlList.REST_CANNED_PUBLIC_READ
			up.setContentLength length
			up.setContentType mime
			up.setDataInputStream inputstream
			up.setKey name
			up.setBucketName bucket.getName()
			s3.putObject bucket, up
		}
	}
	void putXML(text, name, uid)
	{
		String mime = mimeExtensionMap["xml"]; 
		S3Bucket bucket = makeBucket(uid)
		S3Object up = new S3Object(bucket, name, text)
		up.setAcl AccessControlList.REST_CANNED_PUBLIC_READ
		up.setContentLength text.length()
		up.setContentType mime
		s3.putObject bucket, up
	}
}

This gives you a single API entry point (well, two, put and putXML) and will give you read-only assets on your S3 bucket that follow this sort of path…

yourbucket/subbucket/whatever/an-identifier-of-your-coice/image1.jpg
yourbucket/subbucket/whatever/an-identifier-of-your-coice/image2.jpg
yourbucket/subbucket/whatever/an-identifier-of-your-coice/image3.jpg
yourbucket/subbucket/whatever/82757c2a-cfa9-49bf-89fa-9efdaf9bf418/image1.jpg
yourbucket/subbucket/whatever/82757c2a-cfa9-49bf-89fa-9efdaf9bf418/image2.jpg
yourbucket/subbucket/whatever/82757c2a-cfa9-49bf-89fa-9efdaf9bf418/image3.jpg

These can then be got at via urls which reference these buckets via the normal s3 url…


To call this from a controller used to manage the asynchronous file upload you just need to know about one thing, which is how to get from a Spring MultipartFile to something which the JetS3t API can consume.

def amazonS3Service;
def uploadfile = {

	if(request.method == 'POST') 
	{

		Iterator itr = request.getFileNames();

		String vloc = "";
		while(itr.hasNext()) 
		{
			MultipartFile mpFile = request.getFile(itr.next());
			if (!mpFile.isEmpty()) 
			{
				// success
				String _file = mpFile.getOriginalFilename().replace(" ", "_");
				vloc += h.uid + "/" + _file;
				String ext = _file.substring(_file.lastIndexOf(".")+1);
				amazonS3Service.put (mpFile.getInputStream(), _file, h.uid, ext, mpFile.getSize())

			}
		}

		render vloc
	}
}

Basically mpFile.getInputStream() will give something which can be sent directly to S3 without being persisted to the local file system – which is what pretty much every other example I came across does. A couple of things to point out at this point, first is that h.uid is not visible in this code, it is just a unique value I ascribe to each user in my system and you should choose your own. It forms the rightmost bucket name in my S3 key structure. Second is that I use the file name as the key and I modify it to replace the spaces with underscores to avoid any nasty problems with filenames.

Eh voila, you have static image persistence to an almost infinitely scalable server infrastructure (at reasonable cost) and serving via the cloud. Normal caveats apply, and this is far from perfect code, but it works and I hope it helps you get started.

March 12, 2010

*Really* simple Mail service for authsmtp in Grails

Filed under: code, Grails — simonpalmer @ 2:37 pm

OK, after A MONTH of trying to figure out how to get the Grails mail plugin to talk to authsmtp, and *utterly* failing, in a puddle of tears this afternoon at my 1,745th attempt at finding out anything about this on the web, I went into deep hack mode and cracked it in 15 minutes flat.

The answer… write my own f*!%$ing email service.

If you can bear to read to the end I have a bigger Grails lesson, but here’s the solution for any poor person who may be following me down this path.

First off, why AuthSMTP.com? Well, in a production envronment, for a real world application which is going to be generating email in response to user actions (such as notifications), then your gmail account will not cut it and your local ISP will almost certainly block the IP address of your server – especially if you deploy into the cloud at either Google or AWS. That means you have to have a real SMTP host to take care of the relaying and send. AuthSMTP is one of many out there, but their pricing policy is reasonable and they are production strength. I have used them for personal accounts for POP3 and they have been good, although their technical support demonstrated the worst sort of brainless responses possible and was deeply disappointing.

So, following the mantra which got me here, of “how hard can it be?”, here’s the answer…

First off go to your grails prompt and create a service with a name of your choice using

grails create-service Mymail

Next in the scaffolded code, put the following – I decided that I would just use old fashioned Java since I sort of felt I know what I was doing and I am still not comfortable enough with Groovy that I would risk chasing my own stupid errors for another month.

import java.util.Properties;
import javax.mail.internet.*;
import javax.mail.*;

class MymailService 
{
    boolean transactional = false

    public boolean sendMessage(String to, String msgSubject, String msgText) 
    {
		String host = "mail.authsmtp.com";
		String username = "ac99999"; // your authsmtp username
		String password = "xxxxxxxxxx" // your authsmtp password
		String from = "no-reply@yourdomain.com";
		
		Properties props = System.getProperties();
		props.put("mail.smtp.host", host);
		props.put("mail.smtp.user", username);
		props.put("mail.smtp.password", password);
		props.put("mail.smtp.port", "2525"); // thish is the port recommended by authsmtp
		props.put("mail.smtp.auth", "true");
				
		Session session = Session.getDefaultInstance(props, null);
		MimeMessage message = new MimeMessage(session);
		message.setFrom(new InternetAddress(from));
		
		InternetAddress to_address = new InternetAddress(to);
		message.addRecipient(Message.RecipientType.TO, to_address);
		
		message.setSubject(msgSubject);
		message.setText(msgText);
		Transport transport = session.getTransport("smtp");
		transport.connect(host, username, password);
		transport.sendMessage(message, message.getAllRecipients());
		transport.close();
		return true;
	}
}

It’s worst fault is that the thread waits for a response form the server and I confess the error handling could be added improved, and OK, you can’t attach files and you can’t send to multiple recipients, although adding that would be really simple, and you can’t do back-flips and set properties on the fly and blah blah. BUT… you can send a basic message from one email address to another, which I am betting is what 99% of automatically generated email does.

Now for the lesson, and look away if you have already been baptised by a Grails evangelist. The conclusion I am quickly coming to is that all the benefit I got on the swings of a rapid start with Grails I have more than lost on the ugly, nasty, dizzying, vomity, downright dangerous roundabout of debugging it when something doesn’t work.

Even having gone as far as downloading and installing the STS Eclipse IDE – which remains the slowest piece of software on my desktop by a factor of 5 – and figuring out how to actually debug a session, stepping through the code I found myself in a completely impenetrable marass of codeless call stacks as deep as the mariana trench. It remains about as bad a development experience as I have had in the 20-some years I’ve been doing it. The only worse thing is the silent fail of a Javascript library as the browser refuses it. It’s about time the browser was replaced with something better, but that’s a whole other rant.

March 5, 2010

*Really* simple asynchronous file upload in Grails

Filed under: code, Grails — simonpalmer @ 4:11 pm

I spent ages trying to decide which was the best way for me to implement file upload in my grails app. What I wanted was the ability for a user to select an image from their local machine and for it to be uploaded into a tag on my page. The biggest issue I faced was that the upload button, and in fact the whole DIV that contained the image and other stuff, is generated at runtime. The other mandatory condition was that it had to happen asynchronously and without re-loading the page.

I tried out 3 or 4 solutions, including several grails plug-ins (google for “grails file upload” and you’ll find them), several ajax javascript solutions, which I have now lost, and a couple of Flash uploader implementations. The trouble with all of them was a combination of complexity and size. In the end I found a really simple alternative which seems to work just fine and builds on adding the Grails UI plugin into my application.

My solution was in two parts, first was to give myself the ability to have a modal dialog box on my page and second was to utilise the Yahoo GUI library to make an asynchronous connection back to the server.

The modal dialog came directly from the Grails UI plugin, which has a very rich set of excellent features and I recommend it. Installing that plugin gave me a dialog box, which was as simple as including a resource reference and a GSP tag in a hidden div on my page…

        <gui:resources components="['dialog']"/>
        <div>
            <gui:dialog
                id="dlgFileUpload"
                title="Upload Image"
                draggable="false"
                modal="true"
                buttons="[[text:'Upload', handler: 'onUploadButtonClick', isDefault: true],[text:'Cancel', handler: 'function() {this.cancel();}', isDefault: false]]">
                <form action="uploadfile" enctype="multipart/form-data" method="post" id="uploadForm">
                <input type="file" name="testFile"/>
                </form>
            </gui:dialog>
        </div>

The important thing to notice in here is that the dialog box contains a form which defines the multipart enctype, the method as POST. The action refers to the code in my Grails controller which handled persistence of the file. The gui:resources tag is exploded by Grails into a set of script includes for the Yahoo UI libraries. This is important because the YUI library is very large and there are many interdependencies, and this single tag hides all that, which is a major time saver.

The other thing that the Grails UI plugin gave me was the whole of the YUI library, so the next bit was to write some code to handle the file upload itself. Rather than lots of fancy components I realised that I could just use the YAHOO.util.Connect object to make an asynchronous call back to the server, in much that same way that I might otherwise have used an XMLHTTPRequest object in Javascript. Because the whole YUI library is included with the plugin I already had the code. To get at the Connect object I had to include the appropriate script because the gui:resources tag seemed not to add it as a dependence…

        <script type="text/javascript" src="/js/yui/2.7.0/utilities/utilities.js" ></script>

From that point it was a simple matter of writing a function to handle the click on the upload button in my dialog which made the request back to the server, and handled the response…

        function onUploadButtonClick(e)
        {
            var uploadHandler =
            {
                upload: function(o)
                {
                    refreshActiveImage(o.responseText);
                    setDirty();
                    hideWaitCursor();
                }
            };
            showWaitCursor();
            //the second argument of setForm is crucial,
            //which tells Connection Manager this is an file upload form
            YAHOO.util.Connect.setForm('uploadForm', true);
            YAHOO.util.Connect.asyncRequest('POST', 'uploadfile', uploadHandler);
            this.cancel();
        }

The important thinhg to notice in here is that the setForm call requires the second argument to be set to true so it recognises the form settings for the POST. Otherwise, the two lines of code invoking YAHOO connect do everything you need to send a file back to the server.

My server side code processes the multipart file upload and persists the file into Amazon S3 (see my other post about that). I then render the file as a virtual location relative to the current page back into my page so I can simply update the src property of the right IMG tag on my page – that’s what refreshActiveImage(o.responseText); does.

Eh voila! A common plug-in, a great utility library, some really basic Javascript and a form and I have the simplest file upload I could imagine.

March 2, 2010

Hallelujah. Code formatting in my wordpress blog!

Filed under: code — simonpalmer @ 10:15 pm

How did I not know about the Sourcecode tags? I have spent years trying to figure out how to post nice looking code to my blog and was misled by all the plug-in nonsense which only applies if you are hosting your own wordpress instance – which I’m not. Here is the link to the docs for formatting source code in your wordpress.org or wordpress.com hosted blog.

I’m a bit disappointed that there is not an HTML language definition, but that’s OK, I write XHTML in any case so XML works just fine.

function makeRooms(edit)
{
	var t = getTag("roomsBody", "div");
	if (t != null)
	{
		var div = "<div id='rooms'>";
		
		//if (rooms === undefined) rooms = [];
		for (var i = 0; i &lt; rooms.length; i++)
		{
			if (edit)
			{
				div += makeRoomDivEdit(rooms[i], imgpath, i);
			}
			else
			{
				div += makeRoomDiv(rooms[i], imgpath);
			}
		}
		div += &quot;</div>";
		if (edit) div += "<a style='padding:5px;' class='instruction' href='addRoom()'>Add Room</a>";
		t.innerHTML = div;
	}
}

Styling grails-ui elements

Filed under: code, Grails — simonpalmer @ 10:05 pm

The grails-ui plugin has a very rich feature set, being based on the Yahoo’s YUI library.  I have been trying to avoid it, but eventually I have caved and I need a modal dialog box for my web page.  I say caved because I think that it is not an intuitive element of a web application and there are enough cross-browser coding issues to make the introduction of a modal window on a web page a bit of a nightmare.  Of course that’s all taken care of by libraries such as YUI, but they come at a price; there’s a lot of code to download.

Anyhow, I caved and decided I would install the ui plugin to my project and use the dialog box.  It still feels like a bit of a sledgehammer to crack my little nut, but it works and it is not as buggy as the modal DIV I started writing myself.

The trouble is that out of the box you get none of the default styling from the YUI skins.  According to the grails documentation it should be sufficient to enclose your dialog in a tag and set the class of that tag to refer to the YUI skins…

    <body>
        <div class="yui-skin-sam">
            <gui:dialog blah blah></gui:dialog>
        </div>
    </body>

However, this doesn’t work. And neither does this…

    <body class="yui-skin-sam">
        <div>
            <gui:dialog blah blah></gui:dialog>
        </div>
    </body>

In fact the only way I could get this to work was by adding the “yui-skin-sam” class reference to the body tag in layout/main.gsp.

But that comes with a set of problems of its own, not least of which is that styling the body tag in the main layout means that every generated page gets that styling. If, like me, you had gone to some lengths to define your own styling, that is a real pain because the chance of you not having weird clashes in styles – and yui-skin-sam not overriding them – is almost nil for any semi-serious web app.

So, some words to the wise:

  • If you are starting out on your new shiny Grails app, and you want to style it yourself, imply a namespace in your style names when you are making them by prefixing them all with a code.
  • If you think you might want some exoteric UI feature from the grails UI plug-in – and you almost certainly will – then install it early and declare the style class on the main layout body tag from the start. That way you won’t have a lot of re-factoring of style code to do later.

January 19, 2009

Sorting flex Arrays by Date

Filed under: code, Flex — simonpalmer @ 2:11 pm

I have been wanting to figure out a reliable way of doing this for a while, and suddenly the necessity arose for me to do it, so I have a solution. As far as I can tell if you have a date field in an object and an array of those objects, then the results of sorting the array are indeterminate.


public class myClass
{
    public var some_date: Date;
}

var myArray:Array = new Array();
myArray.push(new myClass);

myArray.sortOn("some_date");
myArray.sortOn("some_date", Array.NUMERIC);

The above code (so long as the some_date field was populated) never gave me reliable result for the sort order. I googled in vain for a solution and found a couple, but was never really happy with them. I had a flash of inspiration this morning which is really very obvious now I have done it, but is a nice elegant way of handling this situation.

Basically I add a public getter for a new field which just returns the Date objects time value as a Number, e.g.

public class myClass
{
    public var some_date: Date;
    [Transient] public function get some_date_time():Number
    {
        return some_date.time;
    }
}

var myArray:Array = new Array();
myArray.push(new myClass);
myArray.sortOn("some_date_time", Array.NUMERIC);

This works a treat and gives me reliable sorting results every time.

In case you are wondering why I use [Transient] it is because I am using RPC and remote objects for the connection back to my server and my classes are generally [Managed]. Without the (undocumented) [Transient] metadata some_date_time would be treated as a legitimate field and an attempt would be made to serialise it back to the server across the RPC boundary. This causes a warning to be thrown in the Flex server framework code which clogs up my logs and feels unprofessional.

Create a free website or blog at WordPress.com.