Apr 3, 2012

plupload file browse dialog only open on firefox

I've just experienced an issue with plupload. Say that the file browse dialog open only on Firefox, other browsers doesn't work including IE 9, Chrome, Opera, I didn't test Safari though. Fortunately this thread told me where the issue comes from. You must put the browse_button inside the container:
        var uploader = new plupload.Uploader({
            runtimes : 'html5, flash, browserplus',
            browse_button : 'theUploadBtn', 
            container: 'divPlUploadContainer', // << 'theUploadBtn' must be inside this element!
            max_file_size : '2mb',
            url : 'file/upload/handler',
            multipart: true,
            flash_swf_url : '/lib/plupload/js/plupload.flash.swf',
            filters : [
                {title : "Image files", extensions : "jpg,gif,png"},
            ]
        });
However plupload still not work on Opera with this change

Mar 7, 2012

Rythm - an easy to use high performance Java template engine

I've kept looking for a template engine that has the rich features of Play!framework's groovy template engine, the speed of Japid and the clean, elegant syntax of Razor for years. Without any findings, finally I decide to create one by myself. And it comes Rythm.

I've used it for 2 months in real projects and can't feel any better than that. I'd like to share this work to public and start to promote it. This blog is to give a very brief introduce to Rythm by example. I found Mr. Philipp Schneider's blog on Velocity is easy to go and decide to rewrite it using Rythm. So let's have a look on how I use the template in Java:

Map<string, object> context = new HashMap<string, object>();
context.put("title", "template");
Person p1 = new Person("Mueller");
Person p2 = new Person("Schneider");
List<person> list = new ArrayList<person>();
list.add(p1);
list.add(p2);
context.put("personList", list);

String readyToUseTemplateOutput = Rythm.render("/folderinResource/MyTemplate.anyending", context);

You can also choose to pass template arguments by location:

Person p1 = new Person("Mueller");
Person p2 = new Person("Schneider");
List<person> list = new ArrayList<person>();
list.add(p1);
list.add(p2);

String readyToUseTemplateOutput = Rythm.render("/folderinResource/MyTemplate.anyending", "template", list);

And now the template file:

@args String title, List<person> personList;
Hello world!
This is my first @title
@for (Person person: personList) {
@if (person_index == 1) {Here is a list of persons:}
- @person.getName()
}

The result will look like this:

Hello world!
This is my first template
Here is a list of persons:
- Mueller
- Schneider

So this was really easy to use. And you can also create complex templates, that extends a layout template, invoke customized tags etc. You can do nearly all things that you can in velocity. Maybe even more.

In addition, Rythm is very fast, about 2 to 3 times faster than velocity. Some other features about Rythm:

  • Strong typed. Meaning your template get compiled and less runtime error
  • In-memory compilation. No need to call your javac to process generated java source files. Just call the API to process your template and get your result
  • Cached. Your template compilation get cached so next time no parsing/generating/compilation and it means super fast
  • Hot reload on dev mode. So if you are working on a server program you don't need to restart the server, just hit F5 to refresh your browser.
  • General purpose. Rythm can be used to generate any type of text file. It's not limited to HTML/XML
  • Easy to define tag/macro because every template is a tag and can be invoked from within any other templates
  • Support template inheritance. Reusing your layout page is piece of cake.

Check more on http://www.rythmengine.com!

Updates: I have just release an new template engine plugin built on top of Rythm for Play!Framework

Oct 8, 2011

Play!Framework: Use RenderArgs and Excel module effectively

Mr. Basav Nagur has posted a blog demonstrates how easy it is to create Excel reports in Play!Framework. Being the author of Excel module, I really appreciate that. In additional I would like to help make the controller more concise in the sample code. Here is the original code of Application controller:
package controllers;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang.RandomStringUtils;
import models.Customer;
import play.Logger;
import play.modules.excel.RenderExcel;
import play.mvc.Controller;
import play.mvc.With;

@With(ExcelControllerHelper.class)
public class Application extends Controller {
    public static void index() {
        render();
    }
    public static void customerphonelist(){
        Logger.info("Generating Customer Phone List Excel report ");
        request.format = "xlsx";
        Date date = new Date();
        String user = "Bob";
        List customers = new ArrayList();
        for (int i = 0 ;i < 10; i++){
         customers.add(new Customer("Mr", RandomStringUtils.randomAlphabetic(15), RandomStringUtils.randomNumeric(10)));
        } 
        renderArgs.put("date", date);
        renderArgs.put("user", user);
        renderArgs.put("customers", customers);
        renderArgs.put(RenderExcel.RA_ASYNC, true);
        renderArgs.put(RenderExcel.RA_FILENAME, "customer_list_report.xlsx");
        render();
        Logger.info("Completed Customer Phone List Excel report ");
    }
} 

The code is correct, however we could make even better in several places:
  1. "@With(ExcelControllerHelper.class)" could be removed. The dependency on that @With has been dropped since Excel v1.2.2
  2. All renderArgs.put(...) for app variables could be removed. You simply pass the variable in the render() directly, and they will get put into renderArgs automatically. 
  3. "renderArgs.put(RenderExcel.RA_ASYNC, true);" could be eliminated if you have "excel.async=true" in your conf/application.conf file.
  4. "renderArgs.put(RenderExcel.RA_FILENAME, "customer_list_report.xlsx");" could be eliminated if your template file name is "customerphonelist.xlsx" which matches the controller name, or if the action method name renamed to "customer_list_report".
All these tiny little things tries to show the beauty of this great framework: being nice to programmer and making programming on the framework a really enjoyable experience. Now the new version of the Application.java:
package controllers;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang.RandomStringUtils;
import models.Customer;
import play.Logger;
import play.modules.excel.RenderExcel;
import play.mvc.Controller;
public class Application extends Controller {
    public static void index() {
        render();
    }
    public static void customer_list_report(){
        Logger.info("Generating Customer Phone List Excel report ");
        request.format = "xlsx";
        Date date = new Date();
        String user = "Bob";
        List customers = new ArrayList();
        for (int i = 0 ;i < 10; i++){
         customers.add(new Customer("Mr", RandomStringUtils.randomAlphabetic(15), RandomStringUtils.randomNumeric(10)));
        } 
        render(date, user, customers)
        Logger.info("Completed Customer Phone List Excel report ");
    }
} 

Isn't it more concise and easier for both programming and reading? What do you think?

One additional note about xlsx format of excel template, in order to use that, you will need Excel v1.2.3x version instead of v1.2.3 version mentioned in original post.

BTW, I would be really glad if someone tell me how to format code in the way Mr. Basav did in his post :)

Sep 17, 2011

The Trouble with LESSCSS

GreenScript v1.2.6 start to support LESS. I am pretty excited with this feature and decide to move on to LESS. However very soon I found I am faced with an annoying issue with LESS.

So the story starts with twitter bootstrap, a CSS framework built with LESS which is pretty hyped up by web developers recently. I decide to use it in my view. I've included 'less/bootstrap.less' in my default template. It's all good, unless I want to reference a variable defined in bootstrap library in my own foo.css:
.hero-unit .h2 {
  margin-bottom: .5em;
  font-size: 40px;
  color: @grayLight; // grayLight is defined in less/preboot.less file
  padding: 0 10em;
}


The problem with the above code is when GreenScript tries to compile it, the less compiler complains that the variable @grayLight is not defined. Well, it's a surprise but it's correct. The fix is to add the following line to the beginning of the css file:
@import "bootstrap/preboot.less";

However, the issue with this approach is it duplicates all compiled css code from "bootstrap/preboot.less" in the final css output. And if every css file tries to include this or that less libraries, the css will get bloated very quickly.

Another approach is to remove all @import clause from LESS file and let GreenScript's dependent management mechanism to manage the import relationships. E.g. in the view file (or in greenscript.conf file), declare the dependency between foo.css and bootstrap/preboot.less:
#{css 'foo < bootstrap/preboot'/}


GreenScript will make sure the content of preboot.less be put in front of foo.css when doing merge of the 2 files. And then call less compiler to compile the merged content. That could solve the result css bloat out problem, but another issue comes up. Because GreenScript run LESS compilation on merged file only, if there is an error in the compilation, it's not possible to give out information that which file caused the trouble, and make it very hard to debug the LESS errors.

The final solution might need a pure Java Less compile engine supporting the session concept, where all the LESS variables, mixins etc be cached through out the session and could used in future compilation process in the same session. So far I don't know there is any implementation for this stuff. I would like to put it in my TO-DO list. But please let me know if you already have that tool.

Aug 5, 2011

Remove the scrollbars from your facebook canvas application

One of my facebook canvas applications always display the vertical and horizontal scrollbars with it, which is very annoying. By looking into the html source code with firebug, I found the app is hosted inside the <ifram> element with "smart_sizing_iframe" class. While another app without the scrollbars is hosted inside the <ifram> element with "canvas_iframe_util" class. I am pretty sure that my app code is the same in terms of canvas size setting.

After visiting my app settings from https://developers.facebook.com I got the tricky: go to the "canvas setting" under "On Facebook", you have two option for IFrame size: "Show Scrollbars" and "Auto-resize". By selecting "Auto-resize" and save, then refresh your application page, then you got it! Yes, the scrollbar get removed.

Jul 28, 2011

Use GreenScript correctly

I've just encountered an mail about greenscript in the playframework google group. Here is the code:

-- main.html --


<html>
<head>
#{get 'title' /}
#{get 'moreStyles' /}

#{script 'jquery-1.6.2.min.js' /}
#{script 'jquery.validate.min.js' /}
#{script 'jquery.form.js' /}
#{get 'moreScripts' /}
</head>
<body>
#{doLayout /}
</body>
</html>

-- index.html --

#{extends 'main.html' /}
#{set title:'title' /}
#{set 'moreStyles'}
#{greenscript.css "main005", output:'all'/}
#{/set}
#{set 'moreScripts'}
#{greenscript.js output:true}
#{/set}
...


So what's wrong in the above code:
1. JavaScripts did not get processed (minimize and compress) at all. The above code is still using #{script} tag to output JavaScripts, which will NOT gain the benefit of greenscript at all
2. Using #{set 'moreScripts'} and #{get 'moreScripts'} is neither needed nor encouraged when you have the power of greenscript.

This code gives me a feeling that you have an electric motor saw but you are using it like a plain saw by not powering it on. The correct way could be much more simpler:

-- main.html --
<html>
<head>
#{get 'title' /}


#{greenscript.js 'jquery.form < jquery.validate.min < jquery-1.6.2', output:'all'/}
#{greenscript.css output:'all'/}
</head>
<body>
#{doLayout /}
</body>
</html>

-- index.html --

#{extends 'main.html' /}
#{set title:'title' /}
#{greenscript.css 'main005' /}

Tips:
  • you can declare multiple resource files in one greenscript tag. E.g. #{greenscript.js 'a b c'/} declares /public/javascripts/a.js, /public/javascripts/b.js and /public/javascripts/c.js using one call to greenscript js tag
  • you can declare dependencies inside greenscript tag, e.g. #{greenscript.js 'jquery.validate.min < jquery-1.6.2' /} will guarantee jquery-1.6.2.js be rendered before jquery.validate.min.js/
  • use [output: 'all'] to render all declared and not rendered resources. E.g. #{greenscript.css output: 'all' /} will output all declared css resource in place. Usually you should use [output: 'all' ] inside <head> block
  • By typing "play greenscript:cp -a ." in your project folder, you copied the needed tags to your project and you can simply the invoking of greenscript tag as: #{js .../}, #{css ... /}

Jun 18, 2011

Play-Excel v1.2.1 released with support to asynchronous Excel rendering

I am very glad to release play-excel-1.2.1 which support asynchronous report rendering. Here are changes compare to v1.1:


Render method call
v1.1: play.modules.excel.Excel.renderExcel(...)
v1.2: play.mvc.Controller.render(...), play.mvc.Controller.renderTemplate(...)


in other words, now you don't even aware that you are rendering a Excel report or normal HTML report. Everything is determined by request.format. Once your request.format set to 'xls' or 'xlsx', Excel module will take over the rendering process automatically. There are 2 ways to set request.format:
1. explicitly set request.format in controller methods
a. Set request.format in Action methods
b. Set request format in @Before methods based on http params for example
2. set request.format in route config file. Refer to http://www.playframework.org/documentation/1.2.1/routes#content-types for detail


Template location
v1.1 Excel template can not be put inside views folder, instead you will need to put the templates outside of views folder and set the template root in application.conf file, e.g. excel.template.root=app/excel_tmpl
v1.2 Just put Excel template in views folder along with your normal groovy template files. And of course "excel.template.root" shall not be used anymore


File name
v1.1 set download file name by set "fileName" in renderArgs
v1.2 use play.modules.excel.RenderExcel.RA_FILENAME instead of "fileName".


Async rendering (v1.2.1 only)
v1.1 does not support asynchronous rendering
v1.2.1 support transparent asynchronous rendering. You don't have to deal with Future, Promise, await, request.new etc and you get the power for nearly free (Yes, this is really cool! and thanks to the excellent play framework again!). The only place you need to touch is
1. add "excel.async=true" in application.conf, which enable async rendering globally
2. do renderArgs.set(play.modules.excel.RenderExcel.RA_ASYNC, true) in your action controller to enable async rendering for this controller action only


For those who don't yet see the power of async rendering, please refer to http://www.playframework.org/documentation/1.2.1/asynchronous, or think about the fact that a large Excel table rendering might take as long as 500ms and blocking request handling thread for half second is NOT acceptable in a high performance web server like play which use only limited thread (N+1) to handle web requests.



- Green