Pagina's

Wednesday, January 4, 2012

Hosting static sites using Play! and Heroku

I used to rent a virtual private server to host some blogs and static sites. Last year I hardly had any time to manage it and I also noticed a couple of times my server was not running. So, time to get rid of it and put everything in the cloud. The blogs were moved to Blogger, but what to do with my static sites?
I thought it would be fairly easy to create a Play! application for this and host it on Heroku. And ... it was!

Play! is a web framework with which you can very fast and easy build a web application, And Play! supports both Java and Scala!
Heroku is a Cloud Application Platform on which you can host your Python or Java application and they also have support for Play!.

Getting started
First, install Play! On a Mac, just install Homebrew and run:

brew install play

To create a new Play! application, run:

play new <appname>

This creates the whole appliction. Just start 'play run' and get rockin'.

Static sites location
Each static sites is put in it's own folder in the 'sites' folder in the root folder of the application. To be able to host static sites for multiple domain names, each folder has the fully qualified domain name of the site. E.g. 'www.mysite.org'

The application
The main application is in /app/controllers/Application.java. The default index method has been changed to accept both the domain name and the path. A File is constructed using these and then rendered binary so this also works for images and other binary files. If the file does not exist, a 404 - Not Found is returned.

public class Application extends Controller {

  private static final Logger LOGGER = Logger.getLogger(Application.class);

  public static final String SITES = "sites/";

  public static void index(String domainname, String path) {
    if("".equals(path)) {
      path = "/index.html";
    }
    LOGGER.debug("Request for domainname:"+domainname+" and path:"+path);

    File f = new File(SITES+domainname+"/"+path);
    if(!f.exists()) {
      if(!"favicon.ico".equals(f.getName())) {
        LOGGER.info("File not found: "+ f.getAbsolutePath());
      }
      notFound();
    }
    LOGGER.debug("Serving: "+f.getAbsolutePath());
    renderBinary(f);
  }
}

Routes configuration
In Play! a routes configuration defines how a url is mapped to a application method. For this application all requests have to route to the 'Application.index' method. It's also possible to capture values from the url and map these to method parameters. The index method takes both the domain name and path, so the route must map these. The name of the variables in the route must match the parameter names in the Java code.

# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~

# Ignore favicon requests
GET     /favicon.ico                            404

# All request
GET  {site}/{<.*>path}                          Application.index

A special regex is used to match all paths since {path} would only match '/index.html', but not '/dir/other.html' or '/images/logos/company/logo.gif'. {<.*>path} will match anything to the 'path' parameter.

{site} matches the fully qualified domain name. It would also be possible to use '{site}.mydomain.com' if you just wanted to match the subdomain name.

Note: even though this Virtual Hosts feature was introduced in Play! 1.1, it didn't work in Play! 1.2.3. So make sure you're using Play! 1.2.4 in which this feature does work. There is no need to install an additional module for this.

Deploying on Heroku
Deploying a Play! application on Heroku is extreemly easy. Details can be found on the Heroku Dev Center site, but it basically comes down to this:

# Setting up Heroku
- Create an account on Heroku
- Install Heroku app locally
- heroku login

# Create a Git repository
- git init
- git commit -am 'Init'

# Create a Heroku stack
- heroku create --stack cedar

# Deploy on Heroku
- git push heroku master

... and your done! Your application now runs in the cloud.

The next step is to add the 'Custom Domains' add-on to your application using the 'My Apps' administration of Heroku and add all the domain names of your static sites so Heroku will serve requests for these domain names.

DNS
The final step is to change your DNS settings and create a CNAME for each of your static sites and map these to the url of your application on Heroku.

The code
This code for this Play! app is available in this Git repository. If you're using this, you can skip the 'create a Git repository' step described in 'Deploying on Heroku'.

Wednesday, December 28, 2011

Retrospective on 2011

2011 has been an interesting year for me. I started on a new project at the Dutch national bank. Too many decisions were made which I did not support and the people not willing to even hear about something different. Since I was already almost 2 years at that customer, it was about time to go do something else.

I then created 2 iPhone apps. One has been delivered and is available in the appstore. Unfortunately the other one isn't yet, but I have been using it for 6 months now and I'm very content with it.

In august I started at Marktplaats, the biggest online 2nd hand market in The Netherlands, where we're currently working very hard to build a new application which will probably become publicly available in the next coming months.
At marktplaats I was introduced to git. I had already heart about git of course, but I was still a svn user and thought git was too difficult. How wrong was I!! I love git and I never want to go back to svn!


In august I also started to learn about Scala and in oktober I attended both the 'Fast Track' and 'Advanced Scala' courses at TypeSafe in Lausanne with 4 other colleagues to really get started with it. I love Scala and I'm lucky we're already using it in my current project. First only for testing, but we now also have the first services build in Scala.

Last but not least this year was the Devoxx conference in Antwerpen. My third attendance already. I love the Devoxx, the informative university sessions, the excellent conference sessions, plenty of old and current colleagues and of course the excellent Belgian food and beer. After this Devoxx things on my 'want-to-do' list are : MongoDB, Cloud Foundry, Infinispan, Scala, Continuous Delivery, Play 2.0,  Spring-Data. Fortunately this year a Parleys subscription was included in the attendance fee cause there was a lot I was not able to attend. Just have to figure out how I can watch it via AppleTV on my telly :-D

For next year I have some great things planned so hopefully you're going to hear a lot from me.

scala> List(86,101,114,121,32,98,101,115,116,32,119,105,115,104,
101,115,32,102,111,114,32,37,100).map(_.toChar).foldLeft("")(_+_).format(2012)


:-D


Friday, November 18, 2011

Devoxx 2012

This year was again an excellent Devoxx conference. There was plenty of interesting topics. Because Google was not present at the JavaOne this year, Google was very much present at the Devoxx. There was one room almost exclusive with Google/Andoid sessions. Although the organisation tried to limit the number of attendees, the total amount was about the same as last year. After the registration closed Stefan noticed he suddenly had a lot of friends who still 'needed' a ticket.

One popular topic again this year was 'wifi'. Even though there was fibre connection, over a temporary 'bridge' over the parking lot, each room had 2 wifi antennas, and there were 10k ip addresses available, the wifi still had more downs than ups. In some rooms it was almost impossible to get a wifi connection. You had to be early in a room while there were still a few people, get a connection and hang on to it during the talk.

The Twitter wall was again beautifull this year. You can still see it at wall.devoxx.com. There were plenty of Android apps, but no native iPhone app and the iPad app was available just in time before Devoxx started. Maybe next year I'm going to develop an iPhone app cause I was really missing one and since the wifi was not that terrific, the mobile webapp did not work when needed.

So here some off the cool stuff I heard about:

Cloud Foundry
Chris Richardson, founder of Cloud Foundry, later bought by VMWare, gave a nice introduction into this new cloud platform and into MongDB and Redis, two db's available on Cloud Foundry.

MongoDB
A very good introduction into this document db and how to use it to store and query data.

Git & Gerrit
A talk mainly about the tool Gerrit which it both a git repository and a code review tool. Every push to Gerrit first must be reviewed before it's merged into the master branch. Nice session but I'm not convinced this concept works. Interesting to see that git branches are heavily used for this, because I also hear people complaining that merging is still difficult with git. Not that I agree with that btw.

Spring-Data
Again a talk from Chris Richardson about the new Spring-data module and how to use different NoSQL db's

Jenkins & Continous Delivery
Finally a talk about continous delivery which actually shows a working example of how to implement continous delivery. In this talk Jenkins is used. Each feature should be developed in it's own feature branch. Jenkins merges these branch into an 'integration' branch, runs tests and merges result back to feature branch. When feature is finished and test successful, the feature is merged into the master. Then a deliverable can be made and business choose to talk this into production by a simple click on a button.

Play 2.0
The evening session was very crowded but the talk a bit disappointing because it only was an intro into Play 1.x which I already knew. The next day was the real Play 2 talk which was very good. Play 2 is now build in Scala and is also becoming part of the TypeSafe stack.

Scala
There were several Scala session. Unfortunately not all that good and some at the same time. Did not miss Martin Odesky's talk of course who talked about the past, present and future of Scala.


Infinispan
Nice coding examples how to use this in-memory datagrid in an application.


Hibernate DSL with Scala
Extreemly bad presentation but a very interesting topic: using Scala to create a typesafe DSL for Hibernate. Don't know if this is very practical, why not use something like Squeryl instead, but it at least showed a very interesting feature of Scala of how to improve Java libraries.

Most sessions are already available on Parleys, so if you missed it this year, you can get a subscription and watch all sessions there.

Monday, August 1, 2011

Next iPhone app

After my first iPhone app was published, I contacted a client whether I could build a iPhone app for them. This client does in discounts for consumers. This new iPhone app lets you search on a map nearby gasstations by which you can get a discount when you're a member of this client. It's also possible to search by city or get the same info in a list. Selecting a gasstation displays a detail view with a closeup map. Finally the app also displays the current fuelprices.

Here are some screenshots:


Development
Development of the app was quite straightforward. It was mostly learning how to use the MapKit and designing the views since I had to create them self this time. Because the clients infrastructure would not be sufficient to serve data to many mobile clients, a separate backend app was created.


Backend
Daily data is downloaded from the customer and uploaded to a backend app from where it's distributed to the mobile clients. The backend app is build for Google App Engine. The data is persisted in the key-value datastore. Since the data structure is simple enough and using a key-value store is not that hard, the data is stored using the lowlevel API.

The data is process as XML but send to the mobile clients as JSON. A small comparison between GSON and FlexJSON showed that the latter was a bit faster, so that one is used. With FlexJSON it's easy to customize which properties to include in the JSON using a transformer or include or exclude clauses. This also gives good control over the object structure depth that must be put in JSON.

Status (update 1/12/2011)
Even though the app is more or less finished it is unfortunately not available in the AppStore yet. Beforehand was agreed with the client they would supply all needed graphics. Until now however the client has not delivered all images necessary to create a beautiful, high quality app. So for now I am the only and happy user of this app. Hopefully I will be able to submit this app next year.

Wednesday, June 1, 2011

First iPhone app live !!

Today my first iPhone app is available in the AppStore. This app was created for Zakelijk Rijden which is an online app for car milage administration. In the Netherlands if you drive a car for business you have to keep an administration if you don't want to pay additional tax.

Development
This app was developed in 5 weeks and was approved by Apple without any comments. Not bad for my first app. The only specifications I had was an almost finished Android app which I had to 'copy' to the iOS platform. All 6 screens were made in 1 day. Implementing the functionality took approximately 13 days. When testing the app I found a bug which caused the app to crash. After debugging for 2 days I still had not found the exact cause of the bug. It was clear however that it was CoreData related, so I decided to rewrite the whole CoreData interaction which took another another 3 days. Another few days to add the final images and fix a few issues and the first release was ready to be published.

Keeping to iOS UI Guidelines
Since I was just 'copying' an Android app to iOS, I also had to copy the Android design. Apparently for Android there are no strict UI guidelines, but I wanted to keep to the iOS guidelines which ment I had to change the design on some places. For example, the Android app has a row of 8 buttons for favorite locations. I wanted to keep the button size the required minimum of 44x44 pixels so these buttons did not fit on the same row for the iPhone. Although now beautiful, I solved this by placing the buttons in a horizontal UIScrollView so I did drastically had to change the design.
Since iOS does not have a checkbox component, I also had to change this into a segmented control which took a lot more space then the checkbox on the Android.

Custom TableView cells
The TableView shows all registered trip with startpoint, endpoint and any number of waypoints. This ment that the cell height would depend on the number of waypoints. It took quite a big of googling and trail and error testing to get this done, but in the end I got it working by calculating the height of all lines in the cell and even support line wrapping. The clue here is that you need the text, a font with a size and the bounds in which the text must be put. You can then calculate the number of lines needed and use this with the font height to determine the height of the text.

CoreData bug
A CoreData problem was causing the app to crash. It occurred when the location was changed multiple times before continuing to the next screen. Each time a new location entity was created, but in the end only 1 entity set on either the trip or waypoint entity. In iOS however, the CoreData entity is already created in the db when an entity is created. Unlike in Java when the db record is only created when the transaction is committed. Somehow creating all these Location entities confused CoreData and the app crashed when saving the context. I could not find anything in the iOS docs or on the net about this constraint. In the end I rewrote the whole location setting so the location entity would only be set when the user goes to the next screen.

Unittesting
I'm very much a TDD practitioner. For iOS however I found it difficult to find good resources how to do and setup unittesting. Even though I started with several unit tests which tested the server interaction implementation, at the end I wrote less and less tests. Because I did not have a continuous integration environment (at the time I could not find anything about setting up Jenkins/Hudson/Teamcity/Bamboo to run iOS unittests) I had to run the tests manually and well ... in the end you forget or you just don't want to because it takes too long. An after a while and after some refactorings lots of tests did failed. Because of the deadline I did not fix them anymore.
I wonder why the iOS unittesting knowledge is so scarce on the net. Is it so complicated that everyone want to keep this knowledge for himself, does it give a good iOS developer/company an advantage so they won't share it or is there really so little people around who know how to do this?

Monday, December 20, 2010

SSL negotiation fails after Apache and OpenSSL update

Today I updated many packages on my server to the latest version and also build and installed the latest Apache server. After the update however, I was not able to connect to my server anymore using SSL. The browser reported it could not establish a secure connection with the server and on the server the logs showed this error:
[Mon Dec 20 16:18:20 2010] [error] [client xx.xx.xx.xx] Re-negotiation request failed
[Mon Dec 20 16:18:20 2010] [error] SSL Library Error: 336068931 error:14080143:SSL routines:SSL3_ACCEPT:unsafe legacy renegotiation disabled

Googling around I finally found this post in the openssl-users mail archive which described the problem. Apparently the latest openssl package fixes a renegotiation bug which allowed a man-in-the-middle to intercept negotiation traffic. This was fixed by extending the ssl protocol. Some browsers like IE 7 and 8 and Safari (!) however still do not support this new extension so cannot connect over ssl anymore to the server.
In the Apache server a new option was added (SSLInsecureRenegotiation) which allows you to disable this bugfix so older browser can still connect. This means however that you are still vunerable to man-in-the-middle attacks !

Friday, November 19, 2010

JBPM4-Spring-integration update

I got some remarks about the released JBPM4-Spring-integration sources since I didn't include the test sources. So I just released a new version which now also contains an assembly of the whole project so all resources including the test classes and test resources are included in this.

Update 28-12-2011:
Both documentation and sources can now be found in this git repository. It also contains the pre-git releases and snapshots of previous versions. Latest version is 4.3.2.