August 21, 2010
2010-08-21 14:08:25.579550

I was testing the support for CouchDB in Lift 2.0 when I noticed that it's not possible to add records to CouchDB when calling method CouchRecord.save. For some reason CouchDB 1.0 and newer (1.0.1 is the most recent release), expect the calling application to use application/json as the content type for the REST request, but Lift 2.0 is not doing that (yet)

The fix is very straightforward in net.liftweb.couchdb.DispatchJSON.scala, add the following to methods put and post:

// required for couchdb 1.0.x and newer	
val strEntity = new StringEntity(Printer.compact(render(jvalue)), Request.factoryCharset)
strEntity.setContentType("application/json")
m.setEntity(strEntity)

Make sure you replace this line with the ones above:

m.setEntity(new StringEntity(Printer.compact(render(jvalue)), Request.factoryCharset))

(note that it's the same code for both methods)

Hopefully this will be addressed in a future release of the Lift framework.

August 20, 2010
2010-08-20 12:40:16.052752

I recently had the opportunity to work with Scala and Lift to develop a little demo/sample application to showcase their capabilities. We built a Scala 2.7+Lift 1.x application that used the REST interfaces of a Java-based server that was running on SAP NetWeaver CE 7.2 to run a webshop e-commerce scenario. Since Scala has been gathering a lot of attention lately, I have written down some of observations below, from the point of view of someone who isn't a Java nor a Scala expert (I work in IT consulting but I don't do development)

Regarding Scala:

  • Scala as a language is more concise and expressive than Java in some areas, so that you write less to achieve the same or more than in Java.
  • Closures and nested functions are rather useful 
  • The fact that Scala is a functional language also helps to write shorter code; something that would be a loop in Java with a bunch of lines of code inside the loop can be solved with a call to a function over a set/list with a closure or function as one of the arguments (e.g.: List.flatMap, which you'll be using a lot in Lift)
  • Traits as first class citizens are nice if you're used to mix-ins in Ruby or Python (more information: http://www.scala-lang.org/node/126)
  • Scala code can seamlessly call Java code. However, due to some of the extra features that Scala has over Java (traits, generics, methods with any name, etc) it may not always be straightforward to call Scala code from Java. 
  • Actors as a lightweight pseudo-thread implementation are nice, and Lift makes some good uses of them
  • Existing classes/libraries can be extended with new functionality without accessing their source code or even extending existing objects or interfaces, the so-called "Pimp my library" pattern, implemented using Scala's support for implicits

While some of these could be placed in the "syntatic sugar" bin, I found that during development they add an additional level of convenience to the language. It'll be interesting to see if Java adopts any of the key features from Scala over the next releases.

If interested in more details, there's a nice tour of the language features here: http://www.scala-lang.org/node/104

Lift is a web development framework that has been gathering some attention lately. Not only because it is built on top of one of the "hot" languages at the moment, but also because it adopted some of the best features of a bunch of different frameworks. Our application was started on top of Lift 1.1, but was moved later on to Lift 2.0 even though we only used one very small feature from the framework.

  • Lift uses a "view first" approach so most the program logic will go into the so-called "snippets", which are nothing more than Scala classes that are called from XHTML templates. It takes some time to let go of the concept of "where is my controller??" but after that it works well 
  • Lift comes with its own data persistence layer, Mapper, and provides some nice functionality over it such automatic validation and the CRUDify trait, which automatically gives your model classes create/read/update/delete pages and functionality. It is also possible to use JPA but then you're somewhat on your own. There's a good example of a Lift application using JPA for their persistance layer here: http://github.com/rmuri/TravelCompanionScala 
  • There's a lot of ready-made functionality available in Lift out of the box: user handling and authentication (based on Mapper), sitemaps, permission-based application menu creation and handling, etc 
  • It is ridiculously easy to add Ajax functionality to your applications without writing a single line of Javascript code; all the plumbing behind the scenes is taken care of by Lift. On the other hand, adding custom Javascript functionality to a Lift application may take some time
  • Comet functionality based on Scala's Actors, where specific areas of your page can update asynchronously and independently from the rest of the page 

There's of course many more things about Lift but these are the ones I would highlight after our brief experience.

Some of the Lift features can be tested online here: http://demo.liftweb.net/. The source code for all these demos is available from Lift's github repository here: http://github.com/lift/lift/tree/master/examples.

July 22, 2010
2010-07-22 08:46:11.009202

This is a very simple Safari 5 extension that allows to select some text in a page and via the right-click contextual menu, submit the search terms to any of the pre-confgured search engines:

Screenshot 1

The list of search engines is pre-configured but any of the ones available can be toggled on and off, as required:

Search settings

As of version 1.1, the extension also supports sending the search request to the HTTPS version of the site if available (currently only supported in Google):

SSL support

The extension can be installed from here: RightClickSearch (right click on the link and then select "Save Link As...", as github.com won't serve the file with the right MIME type)

The code is available from my github repository, here.

July 2, 2010
2010-07-02 16:32:07.456129

I just published my first extension for Safari 5.0 to my github.com repository. The extension incorporates two features that I was sorely missing from the Reader Plus for Google Chrome: optimized reading layout and opening articles in background tabs with Shift-V. The extension is heavily based on inspired by two existing Safari extensions: Google Reader Compact and greader-bgtabs.

Screenshot

In order to download, save and then run the ExtendedReader.safariextz extension in the Finder (remember to ensure that extensions are enabled) If interested, the code is in my github repository under SafariExtensions.

The extension includes support for automatic checking for updates, so you will be notified of new releases.

June 8, 2010
2010-06-08 09:30:13.749730

I was using this blog post to configure the natural JSON convention in Jersey 1.2 for some RESTful web services I was using but it wasn't working. It took me a while to figure out what was wrong so I figured someone might have the same problem in the future. Here is the corrected class:

package com.webshop;

import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.JAXBContext;

import com.sun.jersey.api.json.JSONConfiguration;
import com.sun.jersey.api.json.JSONJAXBContext;
import com.webshop.item.ItemBean;
import com.webshop.order.OrderBean;
import com.webshop.order.OrderItemBean;
import com.webshop.order.OrderList;

/**
* Custom JAXB context resolver that enables the "natural" json generator. The
* natural generator has nicer features, such as generating json arrays always
* properly, instead of only when the array has more than one element (makes
* the parsing easier)
*/
@Provider
public class CustomJAXBContextResolver implements ContextResolver {

    private JAXBContext context;
    private Class[] types = {OrderBean.class, OrderItemBean.class, ItemBean.class, OrderList.class};

    public CustomJAXBContextResolver() throws Exception {
        this.context = new JSONJAXBContext(JSONConfiguration.natural().build(), types);
    }

    public JAXBContext getContext(Class objectType) {
        for(Class c : types) {
             if(c.equals(objectType))
             return(context);
        }
        return(null);
    }
}

Please note that your class names may be different than mine

The gist of the issue was to ensure that the getContext() method returns the correct context for the given class. For some reason in the blog post linked above it was always only comparing to the first element in the array.

Jersey will automatically load your custom context resolver, just make sure that it is somewhere in the classpath.

April 11, 2010
2010-04-11 08:15:58.716285

LifeType is a reasonably well-known multi-user and multi-blog platform built on PHP that I led for about 4 years since 2004, probably earlier than that, I can't remember but 2004 was the year of the first public release. I haven't been actively involved with the project for a couple of years by now, due to work and personal reasons but I've been meaning to write about my experiences with it over the years. Today I will start with the things that didn't work so well, or that I would have done differently were I starting LifeType all over again.

Support only one option, and support it well. 

This applies to combinations of modules/platforms/versions/configuration options, as the amount of possible combinations will grow too large to make it possible to support, e.g. PHP4 or PHP5, with/without escape_quotes, with/without a Unicode database, with/without mod_rewrite. Don't be afraid of reducing your target user base by reducing the options; those users who really want to use your software will have no problem setting things up as per your requirements. Those who can't go through the trouble are probably not the kind of user you are looking for anyway.

A couple of examples from LifeType:

  • In LifeType we had support for many different ways of implementing friendly URLs: mod_rewrite, ForceType, etc, and in the end it was very difficult to support them all reliably
  • We also tried to support both PHP4 and PHP5, since in the beginning of LifeType PHP5 was only in its early stages of deployment. Looking back, this was a mistake since PHP5 had some very good features that we had to ignore for some time and the code ended up being a mixture of PHP4 plus features from PHP5 but with workarounds so that they would also work in PHP5.

Additionally, having to support all these combinations will make your development environment too complicated (if even possible at all)

UTF-8 is the only way

Dealing with the myriad of encodings for non-Latin languages out there is not worth the hassle, specially if all the encodings will be mixed in the same database. If you're going to support multiple languages don't even think about it, UTF-8 is the only option. This is obviously very easy to say now in 2010 but in 2004 when LifeType was started things were not so clear and even PHP only supported UTF-8 well via additional modules that were not always installed in hosts.

Don't make it too easy

You don't have to make your software impossible to install but you don't want to make it too easy either, specially if the software itself is somewhat complex as this will attract less knowledgeable users. 

Set up a bug tracking system early enough

If you go for something like code.google.com or github.com, issue management is already in place for you. If you're running your own development infrastructure, consider setting something up so that users can report issues. 

However, based on my personal experience you should ignore forums at all costs. For every useful post in the forums, you'll get 50 questions that have been answered before, that are part of the FAQs or that should be reported as bugs; if your users can't be bothered to use the search functionality or learn how to use a bug tracking system, they don't deserve your time and attention either.

As the project leader, you have to be a dictator

If this some software that you started to scratch your own itch and that you later publicly released, drive it according to your own vision. It is fine to listen to users but most of the times they just ask for features that they personally need. No matter how easy it sounds to implement a feature, more code and more features mean more testing and more potential combinations (see above), which also means more potential problems for you as the developer.

It's not about engineering excellence, but end-users!

Unless you're building a platform, framework, application server or something that people can build other things on, your end users don't care how many development patterns or fancy OOP features you use through your code; 99% of end-users only care about features and ease of use, and the remaining 1% are either hackers or plugin developers who can probably manage with whatever code anyway, regardless of how kludgy or brilliant it is.

Wordpress is in my opinion the best example of this. Last time I looked at the WP code I was horrified, with its lack of object-oriented programming and mixture of SQL code with HTML code and PHP code in several places (disclaimer: that was a while ago, things may have changed since then!) But on the other hand it had plenty of features, it looked good out of the box and it worked relatively well with little effort and at the end of the day, that's what matters to users (for blogging applications anyway)

Tags:
March 28, 2010
2010-03-28 21:03:16.512995

TinyMCE, for some reason, likes to convert to and from newline characters '\n' into <br/>. This has the undesired effect of breaking formatting within <pre> tags, which is very annoying if you use them to wrap around source code.

The solution, with a small cleanup plugin:

fixNewLines = function(type, content) 
{
  switch (type) {
   case "get_from_editor":
     content = content.replace(/<br\s*\/>/gi, "\n");
     break;
   case "insert_to_editor":
     break;
   }

  return content;
}

In order to have the plugin loaded, add the following to the code that creates the TinyMCE editor:

tinyMCE.init({
  ...
  cleanup_callback: fixNewLines,
  ...
}); 

Just make sure that the cleanup plugin is loaded before the TinyMCE object is instantiated.

This idea isn't mine, I only improved the regexp, but I cannot find the link where I saw it...

March 26, 2010
2010-03-26 20:42:20.847962

Not only is it possible in Parklife to import location data from services such as Twitter or YouTube, but now it is also possible to manually set the geolocation data for new entries, or when updating existing entries. The functionality is based on the Google Maps API.

For those browsers and devices that support the W3C Geolocation API, Parklife is able to leverage it to obtain the current location automatically. If the API isn't available, it is still possible to manually set it via a map.

Last but not least, all the geolocation data is seamlessly included into the Atom feeds that Parklife generates via the GeoRSS namespace.

PS: This entry has been randomly geolocated, as an example :-)

March 14, 2010
2010-03-14 22:03:21.620599

I had been running Storytlr for some time now, and even though I liked it, I thought that the code was a bit overdone and that it was too heavy (it had in fact already had some issues with processing quotas with my current hosting)

I had been looking for an excuse to do something with the Google App Engine and Python for some time now, so this was a good chance. I started to work on Parklife, a very simple lifestreaming application inspired by Storytlr but much lighter (fewer features too) and which runs on GAE. Parklife doesn't have all the features I would wish yet but I'm working on it. In the meantime, you can access the Parklife repository at github.com, clone it, and run it in your own GAE account if you wish (it should run just fine, but you may need to make some changes to the template as it currently is very much designed for renalias.net)

« Prev Next »