log4p

Peter Maas’s Weblog

Archive for August, 2006

DWR Call batching

To reduce load on my current project I had a look into reducing the number of requests fired at the application server. Many pages in the application trigger multiple DWR calls resulting in Tomcat generating heavy load on the servers.

One of the sollutions I came up with is batching DWR calls, which reduces the number of calls by combining multiple calls into single requests.

Simply start and end a batch and DWR handles it all! For example:

  1. function batchThreeCalls(){
  2.     DWREngine.beginBatch();
  3.       testbean.getOne(doOne);
  4.       testbean.getTwo(doTwo);
  5.       testbean.getThree(doThree);
  6.     DWREngine.endBatch();
  7.   }

Results in a single call, and a single response which is routed to the correct callbacks by DWR:

request

  1. callCount=3
  2. warningHandler=null
  3. httpSessionId=EA9C0891376DE06E977B26CD729E59C8
  4. scriptSessionId=B206674DE4A43F7E497882E9E3723F3D
  5. page=/JRubyController/dwrtest.html
  6. c0-scriptName=testbean
  7. c0-methodName=getOne
  8. c0-id=158_1156968086615
  9. c1-scriptName=testbean
  10. c1-methodName=getTwo
  11. c1-id=1425_1156968086615
  12. c2-scriptName=testbean
  13. c2-methodName=getThree
  14. c2-id=3057_1156968086615

response

  1. //#DWR-START#
  2. DWREngine._handleResponse('158_1156968086615', "1");
  3. //#DWR-END#
  4. //#DWR-START#
  5. DWREngine._handleResponse('1425_1156968086615', "2");
  6. //#DWR-END#
  7. //#DWR-START#
  8. DWREngine._handleResponse('3057_1156968086615', "3");
  9. //#DWR-END#

More one batching can be found on the DWR site.

5 comments

Javascript compression filter

Yesterday a colleague asked me whether it is possible to automate compression of javascript code in a web application (the current project has a total of about 150kb of javascript for some of the pages). I decided to look into the issue a bit...

There are tons of offline javascript compressors/obfuscators etc. but the ones using Rhino seem to be among the best. This is mostly due to the fact that Rhino can fully interpret the code and decide whether, for instance, variables are local or not. Another good feature of Rhino is the fact that it is java based. The Dojo toolkit offers a patched version of the Rhino library which can be used safely to compres javascript offline.

I couldn't find inline (filter based) compressors... so I decided to wrap the Dojo Rhino version in a filter. Took some work to figure out how Rhino is used, but I managed to get everything to work.

Instead of pasting code here I decided to install a subversion repository, it is browseable through the web from the following URL:

http://svn.maas-frensch.com/pmutils/javascript_compressor_filter/trunk/

The project contains a minimal webapp demonstrating the use of the filter, a simple build file (be sure to configure your tomcat base-dir for compiling) and can be checked out anonymously.

If you just want to use the filter download the following files and put them in your WEB-INF/lib folder (compiled for java5!):

and add the following lines to your web.xml descriptor:

  1. <filter>
  2.   <filter-name>javascript compressor</filter-name>
  3.   <filter-class>com.finalist.web.filters.JavascriptCompressorFilter</filter-class>
  4. </filter>
  5.    
  6. <filter-mapping>
  7.   <filter-name>javascript compressor</filter-name>
  8.   <url-pattern>*.js</url-pattern>
  9. </filter-mapping>

I've tested the filter on my current, Javascript heavy project and it manages to reduce the filesizes by about 50%.. and they still work! Also it's now safe to fully document 'unwanted' but known behaviour of javascripts without the risk of accidenlty exposing it to external users.

The following example illustrates the working of the filter:

input

  1. /**
  2. * called when the window is finished loading
  3. * registers hanlers to each 'anchor' with classname 'button'
  4. */
  5. window.onload = function(){
  6.   var anchor = document.getElementsByTagName('A');
  7.   for(var i in anchor){
  8.     if(anchor[i].className == 'button'){ // if A has class button, register event handlers
  9.       anchor[i].onmouseover = over;
  10.       anchor[i].onmouseout = out;
  11.       preload(anchor[i]); // preload images
  12.       anchor[i].style.backgroundImage = "url('"+anchor[i].getAttribute('out')+"')"; // set default image
  13.     }
  14.   }
  15. }

output:

  1. window.onload=function(){
  2. var _1=document.getElementsByTagName("A");
  3. for(var i in _1){
  4. if(_1[i].className=="button"){
  5. _1[i].onmouseover=over;
  6. _1[i].onmouseout=out;
  7. preload(_1[i]);
  8. _1[i].style.backgroundImage="url('"+_1[i].getAttribute("out")+"')";
  9. }
  10. }
  11. };

After writing the filter I discovered DWR has some java based compression utilities as well; and it is allready on the project classpath. Maybe I'll expand the filter with configuration options for selecting the compressor to use.

2 comments

CX-310-055 (2)

Today the mailman brought me a big brown envelope containing my official, signed certificate... Although Danielle thinks Sun could have done a better job on the quality (it looks like a simple inktjet printout) I'm still proud of it; and since I haven't got other news to post, here it is!

SCJP for Java 5

2 comments

Rails update…

The small Rails app which I wrote for my wife broke down completely just after the installation of the new version of Rails (the 'mandatory' 1.1.5 and 1.1.6) by Dreamhost.

Couldn't get it to work at all, and no sensible logging info was produced...

At the end (took me about four hours) it started to work again, and I actually don't know which of the following actions actually helped:

  • create a new Rails app using the rails version of the server, copy application files into the project
  • setup FastCGI again
  • start webbrick to see stuff working without fcgi (it actually worked)
  • write a message to the helpdesk
  • remove all temp files (like sessions, damn a LOT of sessions...)
  • execute the dispatcher script using a CLI again, no errors...
  • changed the she-bang line to reflect the first line of the script for starting webbrick (which worked), executed the script again... still no errors
  • re-configure fcgi

Somehow this, or one of those, solved my problem...!? Being a java programmer I'm not really used to this sort of voodoo... (well o.k. I have used WebLogic as wel) ... Is there something I should read which could enlighten me in understanding what happened?

No comments

Major security flaw in Rails?

Just after writing my previous post I noticed the following post on one of my incoming RSS feeds:

Rails 1.1.5: Mandatory security patch (and more)

From the article:

This is a MANDATORY upgrade for anyone not running on a very recent edge (which isn’t affected by this). If you have a public Rails site, you MUST upgrade to Rails 1.1.5. The security issue is severe and you do not want to be caught unpatched.

Wow... doesn't sound nice at all... lets hope dreamhost.com updates my rails version ASAP!

No comments

Spring MVC and JRuby controllers

While going through some Spring 2.0 documentation on using dynamic languages in combination with Spring I noticed an example of a Spring MVC controller written in Groovy. I fiddled arround with it a bit, the refreshable bean feature makes it really cool... now I can edit my controllers in a running application server!

Since I like Ruby I decided to combine to documentation on using JRuby and the Groovy controller example.

First, I created this ultra simple controller:

  1. require 'java'
  2.  
  3. include_class 'org.springframework.web.servlet.ModelAndView'
  4. include_class 'org.springframework.web.servlet.mvc.Controller'
  5.  
  6. class MyController <Controller
  7.   def handleRequest(request, response)
  8.     puts "I'm in Ruby"
  9.     mav = ModelAndView.new @@resultView
  10.     mav.addObject("key","value")
  11.    
  12.     return mav
  13.   end
  14.  
  15.   def setResultView(resultView)
  16.     @@resultView = resultView
  17.   end 
  18.  
  19.   def toString
  20.     return "MyController in Ruby"
  21.   end
  22. end
  23.  
  24. # needed by spring
  25. MyController.new

The setResultView method (l. 15) will be called from Spring (IOC) to configure to resulting view for this controller. As you can see the controller class inherits Spring MVC's Controller interface (yes, I know inheriting an interface might sound a bit strange... but Ruby doesn't actually use the interface concept). I had to implement the toString method to get rid of some nasty error messages complaining about it.
For people less familiar with Spring MVC, the ModelAndView object contains the name of the target view AND the model to be rendered in this view. The objects added by the addObject call will be exposed to the view renderer (i.e. jsp, xslt, velocity, freemarker).

The controller can be configured in the Spring MVC dispatcher xml like this:

  1. <lang:jruby id="myController" refresh-check-delay="3000"
  2.         script-source="/WEB-INF/Ruby/MyController.rb"
  3.         script-interfaces="org.springframework.web.servlet.mvc.Controller">
  4.         <lang:property name="resultView" value="view" />
  5.     </lang:jruby>

Notice the Spring 2 use of namespaces, and the refresh-check-delay attribute which defines the interval in which the script file is checked for modifications. Also, as you can see we use Spring to set the 'resultView' property.

Throw in some url handler mappings and a JSP and there we go! Sweet!

At the moment I don't have a specific case for using Ruby to write spring controllers, but I really like the fact that it is actually possible!

If you want to experiment:

4 comments

Insects

I managed to get some insects to smile at my camera just long enough to get their portrets taken:

BeeFly

No comments

Sun Certified Programmer for Java 5

Today I passed the CX310-055 exam, which means as much as:

I am a 'Sun Certified Programmer for the Java 2 SE Platform, Standard Edition 5.0'

Scores

I scored a wopping 90% (59% required)! yeah!

5 comments

Drip

While trying to relax for the upcomming exam today I took the camera out in the morning sun to take some close-ups. I think this one worked out particularly well:

Olive leaf with drip

No comments

EOS350D – New header

Today the Canon EOS350D we ordered arrived. During the day Danielle mailed me some nice shots she made while experimenting... soon Sjoerd's weblog will be packed with hi-res 8 megapixel SLR pictures ;-)

But after dinner I had a go, and took a couple of shots of my espresso machine. I think some of them worked out pretty well:

espresso machine different angle

The new header is cropped from the first image!

BTW, I upgraded my lightbox install (the fancy image overlay) to v2. Now you can hoover over the image to get a 'next' and 'previous' button

No comments