martes, 27 de marzo de 2007

Generic Validator for Spring MVC & DWR

Last month I blogged about how to leverage Spring Validators to check client information delivered in AJAX calls (you should have read it before proceeding here). I got the original idea after reading a very good article at java.net. The result, in my opinion, was very useful but it presented two problems
  • It forces the developer to create the Validator using a predefined schema
  • The Validator had to implement a new interface (ClassAwareValidator)
As a matter of fact they were more annoyances than real problems. Working lately with Validators I faced something really interesting and that deserved a specific solution, how to manage hundreds of domain objects with just one Validator? Probably the model of a common project is made of lots of entities (in JPA terms) and most of them use the same validation concepts, there is really no point developing a custom form and validator for each of them. Most of the work should be able to be packed in a generic solution.

With that idea in my mind and, by the way, with the intention of also solving the points above I started working a little more with the code already available. The goals were:
  • Define a generic Validator that could check any object
  • But not all objects should be checked by it
  • The Validator could be used to check just a field or the whole object
  • The Validator should be usable in AJAX (with DWR)
  • The Validator should work side by side with other Validators in the system
  • The Validator should support Spring MVC forms
The first thing I realized was that I would need some annotations. A generic Validator cannot work if it can't determine what fields should it test and what checks should it perform. The most elegant solution is to annotate the fields in the target classes, this way all other services behave as expected in its absence. I started defining the following:

@Target(ElementType.FIELD)
public @interface StringConstraint {
   public boolean required() default true;
   public String regexp() default "";
   public int maxLength() default 0;
}

@Target(ElementType.FIELD)
public @interface IntegerConstraint {
   public boolean required() default true;
   public int minValue() default 0;
   public int maxValue() default 0;
}

Those should be enough to start. Later some other ones could be created to test dates or decimals, for example. The code is very clear but to explain it a little more:
  • The string annotation can be applied to any field and it will check that the field is not null, it matches a regular expression and it does not span over a number of characters.
  • The integer annotation defines a minimum and maximum values for the field
With them a Validator can be constructed. The first step is determining what objects it will support:

protected Class getValidationAnnotation(Field field) {
   Class validAnnotation = null;
   if (field != null)
      for (Annotation annotation: field.getAnnotations())
         if (validAnnotation == null)
            if (validAnnotations.contains(annotation.annotationType()))
               validAnnotation = annotation.annotationType();
   return validAnnotation;
}

public boolean supports(Class aClass) {
   boolean supports = false;
   if ((aClass != null) & (validAnnotations != null)) {
      for (Field field : aClass.getDeclaredFields())
         if (!supports) supports |= (getValidationAnnotation(field) != null);
   }
   return supports;
}

The Validator is loaded with the annotations that needs to check (with an init method). To test an object it reads all the fields and checks if at least one of them is annotated with one of the annotations considered valid. If the class is supported it just needs to check each annotated field

public void validate(Object object, Errors errors) {
   if ((object == null) | (errors == null))
      throw new IllegalArgumentException();
   if (!this.supports(object.getClass()))
      throw new IllegalArgumentException();
   for (Field field : object.getClass().getDeclaredFields())
      validateField(field, object, errors);
}

protected void validateFieldAsString(Field field, Object object, Errors errors) {
   StringConstraint req = field.getAnnotation(StringConstraint.class);
   if (req.required() && validateNull(field, object))
      errors.rejectValue(field.getName(), errorCodes[0]);
   field.setAccessible(true);
   stringField = field.get(object).toString();
   if ((stringField != null) & (req.regexp().length() > 0)) {
      Pattern pattern = Pattern.compile(req.regexp());
      Matcher matcher = pattern.matcher(stringField);
      if (!matcher.matches())
         errors.rejectValue(field.getName(), errorCodes[1], req.regexp());
   }
   if ((stringField != null) & (req.maxLength() > 0)) {
      if (stringField.length() > req.maxLength())
         errors.rejectValue(
                  field.getName(),
                  errorCodes[3],
                  Integer.toString(req.maxLength()));
   }
}

Of course, a validateFieldXXX is needed for each type of annotation. I've just posted the String one as an example. There's one point left and it is modifying the validation service so it can use this new Validator (and by the way fix the little annoyances described above)

protected Validator getValidator(Class clazz) {
   Validator validValidator = null;
   if (clazz != null) {
      for (Validator validator : this.validators)
         if ((validValidator == null) && (validator.supports(clazz)))
            validValidator = validator;
   }
   return validValidator;
}

public String validateField(String fieldName, String fieldValue) throws Exception {
   String message = null;
   if ((fieldName == null) || (fieldName.indexOf(".") < 0))
      throw new DWRBindException(fieldName);
   String className = fieldName.substring(0, fieldName.lastIndexOf("."));
   Class clazz = this.getClassFromName(className);
   Validator validator = this.getValidator(clazz);
   if (validator != null) {
      String field = fieldName.substring(fieldName.lastIndexOf(".") + 1);
      String capitalizedField = StringUtils.capitalize(field);
      Object formBackingObject = clazz.newInstance();
      Field f = clazz.getDeclaredField(field);
      Object value = this.getValueObject(f.getType(), fieldValue);
      f.setAccessible(true);
      f.set(formBackingObject, value);
      Errors errors = validateObject(formBackingObject);
      FieldError error = errors.getFieldError(field);
      if (error != null) message = error.getCode();
   }
   return message;
}

public Errors validateObject(Object object) throws Exception {
   Errors errors = null;
   if (object != null) {
      Validator validator = this.getValidator(object.getClass());
      if (validator != null) {
         errors = new DirectFieldBindingResult(object, "command");
         Class[] validationArgs = new Class[] { Object.class, Errors.class };
         String methodName = "validate";
         Method method = validator.getClass().getMethod(methodName, validationArgs);
         if (method != null)
            method.invoke(validator, new Object[] { object, errors });
      }
   }
   return errors;
}

The full source code has been submitted to the Spring Annotations project and should be available there (with time). Until then I've compiled a test WAR available here. The implementation sources are available here (the testing classes source code is shown here if you want to peek).

domingo, 25 de marzo de 2007

Deploying dojo the intelligent way

After reading the topic of this post one or two questions should arise quickly, the first one being why is it important to study how to deploy dojo and the second should be what different possibilities do we have. To answer them we firstly need to understand how dojo is structured.

The dojo package is (primary) composed of a main javascript file called dojo.js and a a src directory that contains several hundred of files. The dojo.js is in fact compiled from some of the files in the src directory and is available in different flavours (AJAX being the most common). It requires around 150K. Unfortunately that's not (nearly) enough and the src directory needs to be added as well. Then, during runtime all the necessary files will be downloaded along the main js.

Of course, this doesn't seem optimal as it forces to deploy hundreds of files that may or may not be used later. dojo offers a good alternative by allowing a compilation of a custom build. A custom build constructs a personal dojo.js with the needed dependencies and I think it's the way to go if the dependencies are a little subset of the available widgets. This approach has two main problems, the first being to identify all the dependencies (the number of relations can be huge) and the second being the size of the final dojo.js file. There's no point in including everything and force every page to download a several megabytes large file. A mixed approach could be achieved, compile the most common functionality (it would be donwloaded anyways) and leave the rest as a separate download. Of course, the discovery of dependencies is still needed but this, although cumbersome, is actually recommended.

In the Java world the most common practice is to deploy to an application server (or maybe a servlet container) all the files packaged as a WAR (web application archive). Chances are that a project includes a handful web applications and that many (or may be all) of them leverage AJAX calls. Even tough the dojo size have been trimmed it probably still weights considerably. Deploying it once per application does not seem optimal again. There are several possibilities now. I will offer a couple but some others may be applied in addition.

If you can afford another server a very common solution is to proxy the application server with a dedicated web server (ie Apache) that will be in charge of processing static material (and so is dojo). The other option is to create a separate web application and deploy it alone in the AS, this web application should be publicly accessible and just contain js and css files.

What both solutions do, in practice, is keep apart Java code (which is specific to each request) from other kinds of code common to every applicative. The advantages obtained following all the steps are:
  • Trimmed size
  • Optimized download times
  • Optimized resource consumption (memory, disk and CPU time)
  • Faster development (no need to package dojo time and again)
  • Faster deployment (dojo is deployed once and the applications are smaller)
  • Easier upgrade (modify and deploy just one application)
  • Better maintenance
  • And a better architecture overall

I hope I did answer the questions brought and make clear that dojo is a complex enough library to deserve a specific deployment study.

martes, 20 de marzo de 2007

AOP Enabled Form Controllers in Spring MVC

In the first part of this article (read it here) I tried to explain how to write simple Spring MVC controllers that could be intercepted (AOP) or used by DWR (AJAX calls) without adding any complexity. Some people asked about adding form controllers to the mix. In fact, the first article didn't cover them at all as Form controllers perform a very specific task (submit data) and, generally speaking, won't be the core of the MVC. But, without doubt, they will show sooner or later during development, and it can be useful to intercept calls.

The problems to handle form controllers (SimpleFormController for example) and AOP are more or less the same, just only aggravated by the fact that Spring deals with lots of work (binding, validation, views) internally. As nobody probably wants to loose this functionality (leaving implementing Controller out of question) some new approach has to be devised.

As always we are constraint by the final method declarations up in the hierarchy so extending the classes is not an option. The next idea would be the Decorator patter (see it described here), trying to add behaviour at runtime. Unfortunately, it won't be of help here as this pattern forces the code to implement the same public interface (not the Java interfaces) of the object and that poses the same problem as subclassing.

The idea of wrapping the object is good though. We just need to be able to intercept the handleRequest and the doSubmitAction methods and be able to forward the rest of the calls to the proxied object. An abstract class will take this task:

public class AbstractAdvisableFormController extends AbstractRequestHandler {

   private SimpleFormController formController = new SimpleFormController();

   public ModelAndView handleRequest(
                  HttpServletRequest request, HttpServletResponse response) {
      ModelAndView mv = formController.handleRequest(request, response);
      if (mv.getViewName().equals(getSuccessView()))
         doSubmitAction(mv.getModel().get(getCommandName()));
      return mv;
   }

   public void doSubmitAction(Object command) {
      return;
   }

   ...

}

The complete code is available here but the bread and butter is that. The handleRequest function will forward the call to the form controller and then process the result in case the original call returned a success. The doSubmitAction should be overridden by the concrete class later. An AOP form can be later defined as

@UrlMapping("form.action")
@AutowireToController(controllerBean="actionController")
public class FormAction extends AbstractAdvisableFormController {

   @LogDebug(loggerClass=FormAction.class)
   public ModelAndView handleRequest(
               HttpServletRequest request, HttpServletResponse response) {
      log.info("Do stuff");
      return super.handleRequest(request, response);
   }

   @Override
   public void doSubmitAction(Object command) {
      log.info("Do more stuff");
   }
}

And there it is, a full SimpleFormController auto-mapped (wired to a MultiActionController!), that can be intercepted and supports all the configuration options as can be seen in the following code snippet:

<bean id="aForm" class="test.web.FormAction">
   <property name="sessionForm" value="false" />
   <property name="commandName" value="trivialObjectBean" />
   <property name="commandClass" value="test.dwr.TrivialObject" />
   <property name="validator" ref="trivialValidator" />
   <property name="formView" value="trivialForm" />
   <property name="successView" value="trivialSuccess" />
</bean>

As always you can download the full source code and examples at the repository

domingo, 18 de marzo de 2007

An Image converter for DWR

If you know DWR, you should be confortable with the concept of converters. They, more or less, are classes used by the framework to parse Java objects and transform them into valid Javascript objects & JSON. The framework provides out-of-the-box the most usual ones, like bean, array or list. Unfortunately it lacks the power to convert binary objects like images or PDFs.

Time and again during project development I've found that a lot of work is done or is based on documents. There's always the option to revert to traditional web requests and withdraw AJAX but it seems you can do better. One of the powerful extensions offered by DWR are custom converters where a developer may implement a converter for a specific task and add it to the flow.

But there was a reason why images were not supported in DWR and it was cross-platform Javascript. Let's review what methods can be used to define an image in a page
  • Using the image (<img>) tag and setting an URL as the source
    <img src="http://..." alt="" />
  • Using the <object> tag. Very similar to the image tag but IE adds vertical and horizontal scroll bars what makes it unacceptable
  • Using the image tag and the data URL schema. This would be the most preferable method but IE does not yet support (and probably never will) this type of URL (even though they are actually a stardard).
    <img src="data:image/png;base64,..." alt="..."/>
  • Using the Javascript Image object. It has the same properties and functionality of the corresponding tag.
From the list above it's easy to come to a conclusion, IE will be problematic. It does not support inline images and gives problems with several other approaches. After some research I could only find a solution that may work in IE. It was developed by Benn Herrera a couple of years ago and barring MHT it's the only working code for IE. It relies on RLE compression and HTML tables to create a markup that should work in any browser. The method is costly though so we will only use it for Explorer.

With the method defined creating a converter is easy. Images can be mapped from multiple sources (byte[], URL, ...) but I will parse java.awt.image.BufferedImage for two reasons. The first one is that it allows to retrieve external images (one thing I need for a project as AJAX will serve as a Proxy there) and the other is that the code Benn wrote needs one.

The code is very simple (it's just an skeleton that anyone can use to fit his needs):

ByteArrayOutputStream stream = new ByteArrayOutputStream();
String result;
if ("IE".equals(img.getBrowser())) {
   JSImage jsImage = new JSImage(image);
   jsImage.setCreateColorPalette(true);
   jsImage.serialize(stream, true);
} else {
   ImageIO.write(image, defaultFormat, stream);
}
byte[] unencoded = stream.toByteArray();
String unenc = new String(unencoded, "iso-8859-1");
result = new String(Base64.encodeBase64(unencoded));

Of course, it uses Benn's code (JSImage) to create the RLE image (and jsImage.js to parse it in the client).

function call() {
   ImageConverter.getImage(browserType, "[URL]", callback);
}

function callback(data) {
   if (browserType == "FF") document.getElementById("imgcontainer").innerHTML =
            "<img src='data:image/png;base64," + data + "'>";
   if (browserType == "IE") {
      var decoded = decode64(data);
      var jsarr = decoded.split(",");
      jsarr[1] = eval(jsarr[1]);
      jsarr[2] = eval(jsarr[2]);
      jsarr[3] = eval(jsarr[3]);
      jsarr[4] = eval(jsarr[4]);
      jsarr[5] = eval(jsarr[5]);
      jsarr[6] = eval(jsarr[6]);
      var jsim = new JSImage(jsarr[0],jsarr[1],jsarr[2],jsarr[3],jsarr[4],jsarr[5],
                                 jsarr[6],jsarr[7],jsarr[8]);
      imgContainer = document.getElementById( "imgcontainer" );
      jsim.display( imgContainer );
   }
}

The code has been posted to the DWR mailing list and I hope it may be added to DWR sometime after v2.0 is finally released.

martes, 13 de marzo de 2007

Integrating BIRT with Spring in a Web application

Right now, Spring (MVC) out-of-the-box supports both Excel/PDF and JasperReports views. The PDF/excel ones are useful but as the complexity increases building documents with iText becomes harder and harder. JasperReports offers a powerful alternative based on XML reports that can be designed with a GUI. There's still another tool in the Open Source Java field to create custom reports, Birt. I'm not going to compare it with Jasper as that has been made several times before and it's way beyond the scope of this entry.

But if someone finally decides to stick with Birt and is using Spring then he has to know that specific support in the framework won't be available until version 2.2 (see Jira) which could take sometime yet. Fortunately, a good solution can be implemented without much effort right now.

The first thing to do is understanding the Birt runtime engine. Birt is composed of several modules and the runtime environment is one of them. It can be downloaded separately and installed on its own. Once downloaded, there are some steps to follow to deploy it in a web application. The final structure should be like this:



Once deployed it can be integrated with Spring. The first consideration to make is deciding what modules of the runtime engine are going to be initialized. There are two possibilities (we'll leave the Chart Engine for later): the report engine and the design engine. They can be started independently or both in common. The report engine is in charge of processing predefined reports and documents. The design engine will allow a developer to create a report from scratch (programmatically) or modify a previous report. Reports created and modified by the design engine can be transformed later with the report engine.

To start the report engine you need to declare a simple bean with start and shutdown methods. Even though the Birt engine is hefty it will take very little time to load.

public void startReportEngine(ServletContext servletContext) throws Exception {
   EngineConfig config = new EngineConfig();
   config.setEngineHome("");
   config.setLogConfig(null, Level.ALL);
   IPlatformContext context = new PlatformServletContext(servletContext);
   config.setPlatformContext(context);
   Platform.startup(config);
   IReportEngineFactory factory = (IReportEngineFactory)
      Platform.createFactoryObject(
            IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY);
   reportEngine = factory.createReportEngine(config);
}

public void shutdown() {
   if (reportEngine != null) reportEngine.shutdown();
   Platform.shutdown();
}

The code above is entirely taken from the Birt documentation. Remember that those methods will be called when Spring is building the context so they will be executed just once. To process a report (deployed in the Reports directory) just need to add:

public byte[] createPDF(IReportRunnable design) throws Exception {
   PDFRenderContext renderContext = new PDFRenderContext();
   HashMap contextMap = new HashMap();
   contextMap.put(EngineConstants.APPCONTEXT_PDF_RENDER_CONTEXT, renderContext);
   HTMLRenderOption options = new HTMLRenderOption();
   ByteArrayOutputStream out = new ByteArrayOutputStream();
   options.setOutputStream(out);
   options.setOutputFormat("pdf");
   IRunAndRenderTask task = reportEngine.createRunAndRenderTask(design);
   task.setAppContext(contextMap);
   task.setRenderOption(options);
   task.run();
   task.close();
   return out.toByteArray();
}

That method returns a PDF as a byte[]. If you need another format just modify it (very easy to do). It takes a IReportRunnable design as a parameter. This is very useful as it allows it to be called from a newly created design or a report file

public byte[] createPDF(String reportName) throws Exception {
   return createPDF(
      reportEngine.openReportDesign(sc.getRealPath("/Reports/" + reportName)));
}

public byte[] createPDF(ReportDesignHandle reportDesign) throws Exception {
   return createPDF(reportEngine.openReportDesign(reportDesign));
}

And that's all really. Don't forget to pass the ServletContext on initialization of course! I do it by making the bean ApplicationContextAware.

It's possible that some parameters are also required. Here's a little modification that allows them:

public byte[] createPDF(IReportRunnable design, Properties parameters)
               throws Exception {
   IRunAndRenderTask runAndRenderTask =
               reportEngine.createRunAndRenderTask(design);
   for (Object param : parameters.keySet())
      runAndRenderTask.setParameterValue((String) param,
               parameters.getProperty((String) param));
   ...
}

If you are using Spring MVC to return the PDF to the client just subclass AbstractView and use a ResourceBundleViewResolver

public class BIRTPDF extends AbstractView {

   public BIRTPDF() {
      setContentType("application/pdf");
   }

   protected void buildPdfDocument(
            Map model,
            Document document,
            PdfWriter pdfWriter,
            HttpServletRequest httpServletRequest,
            HttpServletResponse httpServletResponse) throws Exception {
      byte[] bytes = (byte[]) model.get("pdf");
      httpServletResponse.getOutputStream().write(bytes);
      httpServletResponse.getOutputStream().close();
      httpServletResponse.getOutputStream().flush();
   }

   protected void renderMergedOutputModel(
            Map map, HttpServletRequest httpServletRequest,
            HttpServletResponse httpServletResponse) throws Exception {
      buildPdfDocument(map, null, null, httpServletRequest, httpServletResponse);
   }
}

The design engine is even easier to integrate. Just add a new bean with the following code:

private IDesignEngine designEngine = null;

public void startDesignEngine() throws Exception {
   DesignConfig config = new DesignConfig();
   config.setBIRTHome("");
   Platform.startup(config);
   IDesignEngineFactory factory = (IDesignEngineFactory)
      Platform.createFactoryObject(
         IDesignEngineFactory.EXTENSION_DESIGN_ENGINE_FACTORY);
   designEngine = factory.createDesignEngine(config);
}

And use the following code to create a new report programmatically

public ReportDesignHandle createReport() throws Exception {
   SessionHandle session = designEngine.newSessionHandle(ULocale.ENGLISH);
   ReportDesignHandle reportDesignHandle = session.createDesign();
   return reportDesignHandle;
}

Finally, I must add that there is another approach here that you may prefer (though it's a bit more complicated IMHO).

domingo, 11 de marzo de 2007

AJAX: How complicated can it get?

I'm not a web developer. At least, I shouldn't be one. But my role as Technical Architect includes tasks as evaluating different technologies and propose them to be used in projects. AJAX is one of such technologies so I've been playing a little with it lately (you may read other posts here and here).

To evaluate a technology is a broad concept but, in my opinion, no self-respecting software architect can pass without actually coding something (even if it is a little) before making any assessment. Our current AJAX needs were more or less known so the easiest way to go was to select a requirement and code it so I could grasp the complexity. The selected widget was a table (easy, isn't it?)

These were the features I was looking for:

  • Generic enough

  • Sorting

  • Paging

  • Filtering

  • Export to PDF and /or Excel

  • Saving to disk

After some research dojo offers a nice table widget that supports sorting and filtering. It can be created programatically and loads JSON data. A nice solid base to begin with. Of course, I've noticed that a developer should know this two technologies to start. This table will need to parse hundreds of thousands of records so I'm quite sure by now that the a lot of the paging work should be made server side. In addition dojo's FilteringTable has memory/performance troubles when the number of rows go beyond several hundreds.

Even though dojo is quite capable of handling the communications DWR just offers a better integration with a Spring/Java backend. Fortunately, DWR uses JSON to transfer data so that's one problem less. I take notes, this is the third technology/tool for a developer to learn. Once here I considered using jMaki to wrap everything but I'm not sure yet if it will be worth it so I left it pending a future revision.

Design is not my best (this is obvious) so here's what I got (at least is based on CSS so easily changeable):

So I started coding quickly and this is what I learned:

  • Even with dojo and JSON expect to code a lot of Javascript

  • dojo documentation is a nightmare (being kind)

  • On the other hand, dojo's mailing list is incredible

  • dojo works but...don't try too many things...really

  • I wasn't brave enough to try to extend the FilteringTable widget

  • DWR keeps it simple but it works like a charm

  • XHTML / CSS / dojo / JSON / DWR / Java / JSP / jMaki...isn't it too much?

  • And even with all those the final code is everything but elegant

  • AJAX is not about lightspeed...in any possible way

  • I don't have a clue on how am I going to explain all this to a developer

  • Firebug is the tool of the year for AJAX developers

I cannot show all the code here as it is quite complex but, as always, if you need a Paging Table you can download the source code from our repository. To use it just declare the following variables:

<link rel="stylesheet" href="css/PagingTable.css" media="screen"/>
<script language="JavaScript">
   var tableQuery = "TrivialObject.class";
   var showRows = 10;
   var numberOfPages = 5;
   var headers = ["Trivial Field", "Trivial Date", "Trivial Long"];
   var fields = ["trivialField", "trivialDate", "trivialLong"];
   var types = ["String", "Date", "Number"];
</script>
<script type='text/javascript' src='dojo/dojo.js'></script>
<script type='text/javascript' src='js/PagingTable.js'></script>

And include the mark up code anywhere in the body tag:

<jsp:include page="PagingTable.jsp"></jsp:include>

The code available is the preliminary version (only paging, sorting and filtering is available), exporting will be available next (I hope during the week). Once that is also done I may add the option of working in the client (with the current dataset) or the server (with the complete recordset). If you are interested in something more please let me know.

miércoles, 7 de marzo de 2007

AJAX Frameworks: Mixing Dojo & DWR

Right now is complex to determine which AJAX (Asynchronous JavaScript And XML) framework is the right choice for a project. This is it because AJAX is a complex mix of different scenarios and technologies. So when looking to the various options available it's important to understand where do they can be best applied. Currently there's a course over Java Passion that has a lesson dedicated to this. In summary these are the things to understand:

  • AJAX is composed of client side technologies (Javascript), server side technologies and XML requests

  • On the client side, one should ask for a library that facilitates the work with Javascript (provides an abstraction layer), has a rich widget set, manages the communications and, really important, is browser independent

  • On the server side the choices are limited by other constraints. At least, the selected option should offer a good integration with your web framework and handle the low level incoming requests

  • Both sides of the equation should be in equilibrium, that is, you have to bridge the gap between client and server
The available interesting (a personal point of view, there are more) frameworks, usable with Java, are:

  • dojo: It can handle everything on the client side and offers a good selection of widgets. It can work with any server side technology. It's the most used Javascript framework probably.

  • scriptaculous: The most appealing AJAX widgets I've seen. They are few though.

  • Honorable mentions go for DHTML Goodies (nice!) and Rico aswell

  • As appointed Yahoo! UI Library is a very well documented and supported client side library. I would endorse it specially for people that find dojo's documentation a little nightmare!

  • Looking into the future there's the Sun backed jMaki, a framework to wrap JS widgets in JSP tags (or JSF components). It's still under heavy development but I expect very interesting things to show up this year.

  • DWR: It offers a different approach. It's neither client nor server technology but the glue between them. It shows its power managing communications and exposing server code in the browser.

  • GWT: want to create your own gmail?
Once known the alternatives an informed decision can be made. I'm gonna stand and recommend something, keep your Java server code untouched (and I would recommend using Spring), select the widget library (dojo this time but you can even mix and match) and glue everything with DWR. The advantages are obvious, the code will work with or without AJAX calls, no extra work is needed to expose the beans and the look&feel is highly improved.

I'm quite sure a lot of people are successfully using this scheme lately but I haven't really found a simple tutorial to help beginners. Here's a little example to start. Fortunately, there's not much you need to do. DWR has put a lot of effort to handle the communications and move the logic to the server side. Just rely on it.

If you have already defined a widget in your screen:

<script type='text/javascript' src='/TestBeanAnnotation/dojo/dojo.js'></script>
<script language="javascript">
   dojo.require("dojo.event.*");
   dojo.require("dojo.widget.Button");
   dojo.require("dojo.widget.DatePicker");
</script>
<div dojoType="datepicker" id="datepickerbox"></div>
<button dojoType="Button" widgetId="dwrCaller" id="dwrCaller">
      Invoke DWR
</button>

The DWR code can be added independently:

<script type='text/javascript' src='[APP]/interface/DayFromDate.js'></script>
<script type='text/javascript' src='[APP]/engine.js'></script>
<script type='text/javascript' src='[APP]/util.js'></script>
<script language="javascript">
   function dwrDoCall(evt) {
      DayFromDate.getDay(dojo.widget.byId("datepickerbox").getValue(),
                        dwrResult);
   }

   function dwrResult(data) {
      var day = ["", "Sunday", "Monday",
                     "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
      for (var prop in data) {
         alert(prop + " is a " + day[data[prop]]);
      }
   }
</script>

And now everything can be wired together. To do it we take advantage of the dojo event model.

function init() {
   var caller = dojo.widget.byId('dwrCaller');
   dojo.event.connect(caller, 'onClick', dwrDoCall);
}

dojo.addOnLoad(init);

The code above is very simple. It adds a hook on the load of the page. Whenever the button is pressed the event will invoke the JS function which happens to be a DWR call. Everything is tied together. Remember you can download the full source code and an example application at our repository

domingo, 4 de marzo de 2007

Building a web site over Alfresco CMS

Since a couple of weeks ago I've been thinking about revamping Internna's web site making it a little bit more dynamic. I decided to use Alfresco as the content repository mainly to learn a little bit more about its Web Content Management (WCM) capabilites.

The WCM is an add-on package (Alfresco can be installed without it) that adds better handling of different content types (no just document and files). It does so, via XForms and Chiba. Basically, a developer uploads a XSD template that can be later filled by different collaborators of a web site. The form is transformed with XSLT or FreeMarker templates to render a view. Beyond this new type of content, WCM provides SCM capabilities in the form of sandboxes where developers and content managers work with a personal and an independent snapshot of the site.

There's a big but though. Both packages (CMS & WCM) are not that tightly integrated in this version. For example, as of now XForms cannot be used to upload content to a workspace (only to web projects) and WCM cannot provide all the functionality of the document repository (it works separately). This forces the developer to take sides, either you go with the WCM plugin getting a fine grained control over different types of contents or you stick to the CMS repository getting advanced services out of the box (SOAP, Spring integration, security, versatile uploading). It's a tough decision to make and the result may vary depending on the type of web, expertise of the developers and taste for other tools (ie, Subversion). I'm quite sure this will be solved soon (see Jira issue).

I chosed the CMS repository for the following reasons:
  • The document repository features
  • The ability to mimic WCM features (ie, extending the metadata model)
  • Being a simple site (just one developer and three or four content collaborators)
Setting the architecture is a big step but another one, as big, needs to be addressed, the documentation is (really) scarce at this point. The wiki is your main friend here and is not much. To simplify it a little, here's the list of steps to take:
  • Use the client to create a user
  • Use the client to create a workspace
  • Give the user permissions over the workspace
  • Create subspaces and a Draft/Approval workflow (if desired)
  • Give Everyone and Guest permission to read documents
  • Modify the model adding new metadata (if needed)
  • Create and deploy a JSP
  • Create and deploy a FreeMarker template
The first steps are covered in depth in the Alfresco tutorial. Nothing to add here.

Explaining how to modify the model is beyond this guide but basically you have to create the new content (an XML and a properties to add i18n), register the model in the repository (a Spring bean), deploy and restart. Everything is detailed here. Remember that modifying the Alfresco content model directly is possible (and easier probably) but you are advised not to do it. Just create new models better.

Finally, create a JSP page. The following code is needed:

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %><%@ taglib uri="/WEB-INF/repo.tld" prefix="r" %>

<f:view>
   <h:form>
      <r:template template="alfresco/templates/internna/blog.ftl" />
   </h:form>
</f:view>

Deploy it to the exploded Alfresco web application JSP dir (in my installation D:/Alfresco/tomcat/webapps/alfresco/jsp). It will call a FreeMarker template like this (deploy in ${install_dir}/WEB-INF/classes/alfresco/templates):

<#list companyhome.childByNamePath["[WORKSPACE]"].children as child>
   <#if child.isDocument>
      Title: ${child.name}<br/>
      Desc:${child.properties.description}
   </#if>
</#list>

I have added a more complex JSP/Template to our repository. It includes an Ant script to deploy to the correct directories. Bare with the fact that it is a yet in design sample page (only 1024x768 and IE/Firefox). With time our whole web will be there.