Saturday, May 12, 2012

Prerequisites for CFML on Tomcat Deep Dive at cf.Objective()

I just added the prerequisites for the Tomcat Deep Dive I'm doing at cf.Objective() this year to the session description page, but figured I'd summarize here as well in case people don't notice it over there.

This is designed as a "bring your own laptop" session and we'll actually be installing and configuring Tomcat, multiple CFML engines, and web server connectivity in the session, but it would be VERY helpful if you grab all the downloads ahead of time since the wireless can be sketchy at conferences. Also some of the downloads are large and that will not only eat up bandwidth but many hotels cut off downloads after they hit a certain size.

So here's the short list:

  • Java. Not just the stuff that ships with ColdFusion if you already have that installed, but a plain old JDK. (Don't worry, it won't conflict with anything ColdFusion-specific you already have installed.) Java 7 should work but to be safe grab the latest Java 6 (which at the moment is 1.6.0_32).
  • Apache Tomcat version 7. Grab the .tar.gz for GNU/Linux or OS X, or the appropriate .zip for Windows. I'd say don't grab the service installer for Windows for these purposes, but if you want to install Tomcat as a service on your machine that's fine too.
  • OpenBD. Grab the "J2EE Standard WAR" (any version)
  • Railo. Grab the "Railo Custom - WAR Archive" (any version)
  • ColdFusion. Anything version 8 or above will work (probably even older versions), including the CF 10 Beta, but main point here is you need the actual ColdFusion installer. So if you have ColdFusion installed on your machine already and don't have the installer, that won't work. To use ColdFusion in this context you'll be running the installer and generating a WAR file (and feel free to generate the WAR file ahead of time if you already know how to do this).
  • Apache Web Server, or if you're on Windows with IIS 7 we'll go over that as well. I won't be discussing IIS 6, both because it's horrendously more painful than 7 and also because it's ancient. Note that Apache runs on any platform so even if you're on Windows, or if you're on Windows with IIS 6, grab Apache.
Hope to see you there! It's going to be a lot of fun. Well, geek fun anyway.

Wednesday, April 25, 2012

Using "Online Accounts" With Ubuntu 12.04

One of the features I really like on Linux Mint is the "online accounts" that you can enable by clicking on your user name on the top right of the screen, which lets you integrate your Google (and other online account) contacts and calendar with the native OS applications.

I've been trying Ubuntu 12.04 RC2 on my System76 Lemur Ultrathin to see if I want to use it instead of Mint 12 on my main work machine once I get a new System76 Serval to replace my (still excellent!) three-year-old Serval, and I was a bit disappointed to see that the online accounts feature doesn't show up as an option when you click on your user name.

I was happy to discover tonight that it's in Ubuntu 12.04, just in a different place. If you go to the Contacts application you can add your online account from there.

Contacts seem to work fine, but what I don't yet see is how the calendar works (or doesn't work), and honestly I'm starting to think maybe the calendar functionality I'm seeing in Mint is by virtue of Evolution, which doesn't come preloaded on Ubuntu.

Having my calendar accessible right from the OS and having it pop up alerts is pretty darn handy so I'll have to dig into that further and see what my options are. I'm sure there's plenty of calendar applications available but the seamless integration is one thing I do like about Linux Mint.

If any of you Ubuntu users out there have suggestions on this I'm all ears.

Tuesday, April 24, 2012

CFML XMLTransform() and Character Encoding

Quick tip on using CFML's XMLTransform() -- if you see fun weird characters in the output of the transformation like  and you've checked to make sure the response headers from the web server are correctly returning UTF-8, you probably just need to specify the charset of the CFFILE operations when you read the XML and XSLT files from disk.

In my case I was seeing non-breaking spaces being rendered as   which outputs a capital 'A' with a circumflex before the non-breaking space. At first I thought maybe the response from the web server was ISO-8559 for some reason instead of UTF-8 but after verifying that was correct, adding charset="utf-8" to the CFFILE tags that read the XML and XSLT files from disk, all was right with the world.

Sunday, April 22, 2012

Detecting Date Range Conflicts

I'm working on an application for which one of the requirements is to not allow double-booking of rooms. Events in the system each have a start and end date and time, and when a new event is saved the system needs to tell the user if there are any overlaps with existing events in the same room.

This seems simple enough on the face of it but once I started thinking about all the possibilities around this I realized it was a lot more complex than I had initially thought. After some good old-fashioned "sledge hammer approach to get it working and to help gain understanding that will hopefully lead to eventual refinement" I think I have it licked.

I'm sure this is one of those classic problems that I just haven't had to deal with before which are always fun to think through, and whenever I run into one of these I resist the urge to search for a solution until I've wrapped my head around the problem and am ready to admit defeat. (And I really try never to admit defeat unless time constraints force me to.)

My first phase on solving this problem was to consider all the possible conflict states, which in plain english are:
  1. Since an event is assumed to have a non-zero duration, if either the start date/time or end date/time is exactly the same as the start date/time or end date/time of another event in the same room, that indicates a conflict. Note that one event's start date/time can be the same as another event's end date/time.
  2. If an event has a start date/time that is between the start and end date/time of another event, that indicates a conflict.
  3. If an event has an end date/time that is between the start and end date/time of another event, that indicates a conflict.
  4. If an event's start date/time is after that of another event but its end date/time is before that of another event, that indicates a conflict.
Granted some of these overlap, are redundant, or are the inverse of one another, but it was helpful as a first pass to simply think through all the scenarios to start forming a picture in my head of the various possibilities.

I'll spare you the messy middle step here and just say I then started coding all these scenarios (and anything else I thought of) and as I went through that exercise, I realized that this all boils down to some pretty simple logic.

Assume that we have two events and each one has a start and end date/time. We'll use start1 and end1 for the first event's dates, and start2 and end2 for the second event's dates. Here's what I came up with after a lot of head banging that I believe handles all the scenarios:

Consider yourself lucky I spared you the big hairy mess I had before I arrived at that solution. I believe that covers all the bases, however, and at least in the testing I did it certainly seems to.

The only other wrinkle in the case of this system is making sure that an event itself isn't detected as a conflict if someone updates the event and either doesn't change the dates or changes the dates in such a way that it would be considered a conflict with that event's state that's already in the database. To handle that case I still run the function to detect conflicts but if I only get back 1 and the ID is the same as the one I'm trying to save, I ignore it.

So that's how I spent more time than I care to admit this weekend. I'm curious if other people have solved this differently, and definitely would love to hear if this won't address some scenario I didn't consider.

Sunday, April 15, 2012

Setting Up Jenkins to Deploy CFML Applications as WAR Files

I finally got my act together a couple of weeks ago and set up a Jenkins server so we could start auto-deploying our applications to staging servers. Since we're doing agile/scrum on our projects now the product owners tend to like to see changes as they happen and we also have dedicated testers involved with some of our projects, so automating deployment to a staging server is saving us a lot of time and headaches.

We run all our CFML applications on OpenBD and Tomcat and for the most part deploy applications as self-contained WAR files, so the deployment steps in this environment are:
  1. Get latest code from Subversion trunk (we use trunk for ongoing development and branch for releases)
  2. Create WAR file
  3. Transer WAR file to target server for deployment
Pretty simple. I should note at this point that I will not be covering incorporating unit tests into the build/deploy process both because I want to focus only on the Jenkins stuff for this post, as well as because that aspect of things is covered quite well elsewhere. (And I'll be honest: we aren't yet doing unit testing consistently enough in our code that it can be part of our build process, but we're working towards that.)

I also won't cover installing Jenkins since there are many resources on that as well. In my case on Ubuntu Server it was a simple matter of adding Jenkins to sources.list, doing sudo apt-get install jenkins, and then doing a bit of Apache configuration to get up and running. You can read more about installing Jenkins on Ubuntu here, and if you have specific questions about that aspect of things I can answer I'm happy to try.

Step 1: Create an Ant Build Script

As for the specifics of setting this up the first step is to create an Ant script to tell Jenkins what to do when the job runs (we'll create the Jenkins job in a bit). This is key because without a build script Jenkins doesn't really do much, so we'll create a build.xml in the root of our project and then when we create the Jenkins job we can tell it which target from the build script to run.

Since Jenkins "knows" about Subversion you do not have to include anything in your build script to pull the code from Subversion. So given that our applications get deployed as self-contained WAR files, all our Ant script has to do is build the WAR file from the code Jenkins pulls from Subversion.

I should clarify that even though I'm explaining the Ant script first, Jenkins actually runs the build script after it pulls code from Subversion. I'm only pointing that out so you don't think the Ant script runs first even though I'm covering it first. Since you can specify an Ant target when you create the Jenkins job I figured I better explain that first.

Here's a sample build script.



The script isn't nearly as daunting as it may look so let's walk through it.

In the properties section at the top, that's declaring variables we'll use later so we don't have to hard-code those values in multiple places in the script.

The next section is the targets and these are specific tasks that can be executed. Note that these targets may have dependencies, so if you execute a target that has dependencies the dependencies will run first in the order they are declared, and then the target you specified will run.

In the case of this script we have three targets: build, war, and init. The war target depends on build, and build depends on init, so when we specify 'war' as our target in Jenkins later that means init will run, then build, then war, so let's look at these in order.

The init target at the bottom does basic cleanup by deleting the directories into which the source code is dumped and where the WAR file is built so we start with a clean slate.

The build target runs two copy jobs to get the application files into the build directory, which is just a directory to temporarily hold the files that will be included in the WAR. First the build target copies all the non-image files into the build directory, and then it copies all the image files into the build directory.

The reason for doing this in two steps is if you copy plain text and image files in the same copy job, the image files become corrupted in the process. As you can see the first copy operation excludes image files and the second includes only the image files as identified by file extension in the imageFiles property declared at the top of the script. If you have other binary files in your applications that may become corrupted (note that JAR files seem unaffected by this issue ...) you'll want to add those file extensions to the property that indicates which files in your application are binary.

Also note that I'm excluding the build and dist directories, the build.xml file, the .project file that Eclipse adds to projects, and all the .svn files so those aren't included in the build.

So at this point after init runs we have clean directories for doing our build, and then the build target copies all the files (other than those being excluded) from the root of the project into the build directory.

The last step is to create the WAR file, and this is (not surprisingly) done in the war target in the build script. Since Ant knows how to build WAR files this is pretty simple; you just point the war command to the directory where the application files are located (the build directory in this case) and tell it the target name and location of the WAR file, which we're putting into a dist directory.

To review, what we'll tell Jenkins to do in a minute is to run the war target (which in turn is dependent upon the init and build targets) in our build script, which will:

  1. Run the init target which deletes and recreates the build and dist directories so we start with a clean slate
  2. Run the build target which copies all the code and binary files from the root to the build directory
  3. Run the war target which creates a WAR file from the code in the build directory and puts it in the dist directory
Once you have your Ant script created, save it as build.xml in the root of your project and commit that to SVN so Jenkins will have it available when it runs the build.

Step 2: Create a Jenkins Job

With the hard part out of the way, next you'll need to create a job in Jenkins by clicking on "New Job" in the top left of the Dashboard.


Give the job a name, select "Build a free-style software project" and click "OK."

Step 3: Point Jenkins to Your SVN Repository

On the next screen you can configure some additional settings like whether or not to keep previous builds, if there are any build parameters you need to specify, etc., but we'll focus on the SVN configuration for the purposes of this post.


Select Subversion under Source Code Management and enter the details about your repository. This tells Jenkins where it's going to get the code to do the build.

Be sure to give Jenkins the full path to the appropriate directory in Subversion. For example if you build from trunk and your project name is foo, your URL would be something like http://subversionserver/foo/trunk not just http://subversionserver/foo

As a reminder, since we deploy our CFML applications as WAR files using OpenBD, our SVN repository includes not only our application's source code but also the OpenBD engine, so this is traditional Java web application deployment. This is a great way to do things because the application is truly self-contained and all the configuration such as datasources, mappings, etc. is all in SVN. This way you can pull down the project from SVN and be up and running instantly, and it makes deployment really simple.

Step 4: Set the Jenkins Build Trigger

At this point Jenkins knows where your code is but we need to tell Jenkins what triggers the build process to run. You can do this multiple ways but in my case I simply set up Jenkins to poll SVN every 5 minutes to check for new code. Another common way to do this is to use a post-commit hook in SVN to hit a Jenkins URL that triggers the build, but polling is working well for us.

Scroll down to the Build Trigger section of the configuration screen.


Check the box next to "Poll SCM," and then you can set the polling schedule using crontab style notation. Mouse over the ? next to the box if you need a refresher on the syntax, but in the example I have here that syntax tells Jenkins to poll SVN every five minutes to see if there are any changes in SVN. If there are changes the build will be triggered. We'll review what happens when the build is triggered at the end of this post.

Step 5: Set the Ant Build Target

Just a couple more steps in configuring the Jenkins job. Next we need to tell Jenkins which target in build.xml to run as part of the build. Calling build.xml is kind of an implied step with Jenkins since you don't have to explicitly tell it to look for build.xml. It's assumed you'll have an Ant script in the root of your project and that either the default target or a specific target will be run as part of the build process.


In the Build section of the configuration page, specify 'war' as the target to run from your build.xml file in the root of your project.

At this point Jenkins will:
  1. Poll SVN every 5 minutes to check for changes
  2. If there are changes, Jenkins will pull everything from SVN
  3. After everything is pulled from SVN, Jenkins will execute the war target from build.xml which will generate a WAR file that can be deployed to Tomcat (or any servlet container)
The last step is getting the generated WAR file to a target server.

Step 6: Configure the Post-Build Action to Deploy the WAR

One of the great things about Jenkins is the huge number of plugins available, and we'll be using the SCP plugin in this final step. There are also deployment plugins for various servlet containers but since in the case of Tomcat that involves hitting the Tomcat manager and uploading the WAR over HTTP, I found SCP to be much more efficient and flexible.

After you install the SCP Plugin you need to go to "Manage Jenkins" and then "Configure System" to configure your SCP target, user name, and password. These are configured globally in Jenkins and then you simply select from a dropdown in the post-build action section of the Jenkins project configuration.

In the post-build action section of the project configuration:
  1. Check the box next to "Publish artifacts to SCP repository"
  2. Select the appropriate SCP site in the dropdown
  3. Specify the artifact to copy to the server. In our case this is the WAR file, and you specify the path and filename relative to the root of the Jenkins project. For example if you check things out from an SVN directory called 'trunk' and use the same directories in the Ant script above, your WAR file will be in trunk/dist/foo.war
  4. Specify the destination relative to the path you specified when you set up the SCP server, if necessary. If you specified Tomcat's webapps directory as the root in the SCP server and all your projects live in that directory you may not need to specify anything here.
One more configuration issue to note -- in the case of Tomcat you need to make sure and have the host for your application configured to auto-expand WARs and auto-deploy. This way when the WAR copy is complete Tomcat will deploy the new version of the application.

Summary

As with most things of this nature it took a lot longer to write this blog post than it will to set this stuff up. The only even remotely involved portion of all of this may be tweaking the Ant script to meet your needs but the rest of the process is pretty straight-forward.

At the end of all of this we wind up with a Jenkins job that polls SVN for changes every 5 minutes and if there are changes, this triggers the build. The build process:
  1. Pulls down changes from SVN
  2. Runs the war target in the build.xml in the root of the project, which ...
    1. Dumps a clean copy of the application into the build directory
    2. Creates a WAR from the build directory and puts the WAR into the dist directory
  3. Copies the WAR file to a target server using SCP
Once the WAR file is copied to the target server, provided that Tomcat is configured to do so it will redeploy the application using the new WAR file.

There's of course a bunch of different ways to configure a lot of this but this is working well for us. If you have other approaches or if anything I'm doing could be improved upon, I'd love to hear how you're using Jenkins.

Monday, March 26, 2012

Google Cloud Print

One of my many first world problems stems from the fact that I have both Comcast/Xfinity and Verizon Frontier FiOS for Internet in my house. I use Comcast for all my home/entertainment junk and Frontier for work.

This is all well and good until I have to print to my network printer from my work machine, because the network printer is on the Comcast side, not to mention that I wouldn't be able to hit it while I'm on the VPN for work anyway, and I print so infrequently that it's definitely not worth having two printers. (I told you this was a first world problem.)

Luckily there's a solution for this: Google Cloud Print. Google Cloud Print lets you register any printer and it then can be printed to from anywhere. If you don't have a cloud-ready printer (which I don't) you can follow these instructions to register any printer.

Note that this does not allow you to print from any application to this printer. You have to be printing something from Google Chrome specifically from what I can tell, but of course any document you need to print this way can first be uploaded to Google Docs and printed from there.

Handy stuff. Mark this first world problem solved.

Setting Default umask for SFTP on Ubuntu Server

Much as described in this blog post by Jeff Robbins, I have a situation where two sftp users in the same group are both uploading files to an Ubuntu 10.04 server using Dreamweaver. The issue is that by default the permissions are 755, so even though both users are in the same group, only the file owner has write permissions. Since the users need to be able to overwrite each other's files I needed a way to have the default permissions be 775.

What is outlined in the blog post above is exactly what I was after, but for some reason on Ubuntu server if you use what is the final edit in that post:

Subsystem sftp /usr/lib/openssh/sftp-server -u 0002

That results in "Connection closed" messages when you try to log in. The solution above that one works, just note the minor modification of pointing to /usr/lib/... instead of /usr/libexec/...

Subsystem sftp /bin/sh -cumask 0002; /usr/lib/openssh/sftp-server’

Restart ssh and you should be in business.

Thanks to Jeff for that very helpful blog post, and to Thad Meyer for pointing it out to me just last week (coincidentally enough).