Thursday, September 30, 2010

Runtime Generation of User Interface: Metwidget v1.0

Metawidget v1.0 is now available! Representing the culmination of two and a half years of careful incremental releases, we're proud to announce this final 1.0 release of the industry's most practical User Interface generator.

The past 30 months have been an exciting ride. We've paid close attention to your feedback, conducted detailed interviews and case studies, and assisted over a dozen production deployments. We've seen Metawidget deployed at energy companies, by governments, in pharmaceutical labs, for ERP, for light and sound engineering, for telecommunications, and more.

We've worked closely with key industry players and developed strong ties with the academic community - publishing conference papers and journal articles, and fostering relationships with other research teams.

We'd like to thank everyone for their support in getting us this far. And now that we're 1.0, there's never been a better time to dive in and see what Metawidget can do for you! It's mature, it's Open Source, and it's ready to save you from all that error-prone, laborious, boilerplate UI code!

This release was focused on:
Special thanks to Gérard Collin and Ian Darwin for their help with this release!

Your continued feedback is invaluable to us. Please download it and let us know what you think.

Thursday, September 23, 2010

Domain Driven Design versus Anemic Domain Model: FIGHT!

I've been reading a bit lately about Domain Driven Design (DDD) versus the Anemic Domain Model (ADM).

On the one hand you've got folks who argue DDD is closer to 'true' Object Oriented Programming because you keep the business logic and the data together in the same class. On the other hand most of the popular Java EE frameworks 'encourage' ADM: your POJOs are just a bunch of getters and setters, then you wrap technologies like JPA, Bean Validation, Session Beans, Drools etc around them to provide business logic.

So who's right? Hmmmm? Well, I'm certainly not going to go there!

All I wanted to blog was that Metawidget doesn't mind, and works great with both approaches. This is because Metawidgets are lightweight: there's no problem combining several of them in the one screen, each pointing to a different part of your domain model.

Here are two examples you can paste into the Metawidget Live Demo editor (so you can try it right now). The first is for DDD:

import javax.swing.*; import org.metawidget.inspector.annotation.*;
import org.metawidget.inspector.composite.*; import org.metawidget.inspector.iface.*;
import org.metawidget.inspector.impl.*;
import org.metawidget.inspector.impl.propertystyle.*; import org.metawidget.inspector.impl.propertystyle.groovy.*;
import org.metawidget.inspector.java5.*; import org.metawidget.inspector.propertytype.*;
import org.metawidget.swing.*;

enum Title { Mr, Mrs, Miss }

class Person {
   Title title;

   @UiComesAfter("title")
   String firstname;

   @UiComesAfter("firstname")
   String surname;

   @UiAction
   @UiComesAfter("surname")
   void save() {
      JOptionPane.showMessageDialog(SwingUtilities.getSharedOwnerFrame(),"Save button clicked!","Save",JOptionPane.INFORMATION_MESSAGE);
   }
}

class PersonDialog extends JDialog {

   PersonDialog() {
      super(SwingUtilities.getSharedOwnerFrame(),"Domain Driven Design",true);

      PropertyStyle propertyStyle = new GroovyPropertyStyle();
      BaseObjectInspectorConfig groovyConfig = new BaseObjectInspectorConfig().setPropertyStyle(propertyStyle);
      Inspector inspector = new CompositeInspector( new CompositeInspectorConfig().setInspectors(
         new PropertyTypeInspector(groovyConfig),
         new MetawidgetAnnotationInspector(groovyConfig),
         new Java5Inspector(groovyConfig)));

      SwingMetawidget metawidget = new SwingMetawidget();
      metawidget.setInspector(inspector);
      metawidget.setToInspect(new Person());
      metawidget.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
      add(metawidget,java.awt.BorderLayout.CENTER);
      
      setSize( 400, 150 );
   }   
}

new PersonDialog().show();


And the second is for ADM:

import javax.swing.*; import org.metawidget.inspector.annotation.*;
import org.metawidget.inspector.composite.*; import org.metawidget.inspector.iface.*;
import org.metawidget.inspector.impl.*;
import org.metawidget.inspector.impl.propertystyle.*; import org.metawidget.inspector.impl.propertystyle.groovy.*;
import org.metawidget.inspector.java5.*; import org.metawidget.inspector.propertytype.*;
import org.metawidget.swing.*; import org.metawidget.swing.layout.*;

enum Title { Mr, Mrs, Miss }

class Person {
   Title title;

   @UiComesAfter("title")
   String firstname;

   @UiComesAfter("firstname")
   String surname;
}

class PersonDialog extends JDialog {

   PersonDialog() {
      super(SwingUtilities.getSharedOwnerFrame(),"Anemic Domain Model",true);

      PropertyStyle propertyStyle = new GroovyPropertyStyle();
      BaseObjectInspectorConfig groovyConfig = new BaseObjectInspectorConfig().setPropertyStyle(propertyStyle);
      Inspector inspector = new CompositeInspector( new CompositeInspectorConfig().setInspectors(
         new PropertyTypeInspector(groovyConfig),
         new MetawidgetAnnotationInspector(groovyConfig),
         new Java5Inspector(groovyConfig)));

      SwingMetawidget metawidget1 = new SwingMetawidget();
      metawidget1.setInspector(inspector);
      metawidget1.setToInspect(new Person());
      metawidget1.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
      add(metawidget1,java.awt.BorderLayout.CENTER);

      SwingMetawidget metawidget2 = new SwingMetawidget();
      metawidget2.setInspector(inspector);
      metawidget2.setToInspect(this);
      metawidget2.setMetawidgetLayout(new FlowLayout());
      add(metawidget2,java.awt.BorderLayout.SOUTH);

      setSize( 400, 150 );
   }
   
   @UiAction
   void save() {
      JOptionPane.showMessageDialog(this,"Save button clicked!",getTitle(),JOptionPane.INFORMATION_MESSAGE);
   }   
}

new PersonDialog().show();

Metawidget: it's like the Switzerland of the DDD vs ADM wars :)

Wednesday, September 22, 2010

Metawidget Neat Trick: Concurrent Inspectors

Here's another neat trick I've discovered while using Metawidget in my own work.

Metawidget comes with multiple Inspectors to inspect different aspects of your back-end architecture. It then merges the result. This merging is done by CompositeInspector which is itself just another Inspector and therefore pluggable. This means you can plug in different ways of running and merging multiple Inspectors.

What sorts of different ways? Well, since each Inspector is immutable, it's easy to isolate each one in its own Thread. And if you have some fancy processor with a bunch of cores (12, anyone?) you may as well put them to use!

Here's the code:
package com.myapp;

import java.util.concurrent.CyclicBarrier;

import org.metawidget.inspector.composite.*;
import org.metawidget.inspector.iface.*;
import org.w3c.dom.Document;

public class ConcurrentCompositeInspector
   extends CompositeInspector {

   private final Inspector[]   mConcurrentInspectors;

   public ConcurrentCompositeInspector( ConcurrentCompositeInspectorConfig config ) {

      super( config );

      Inspector[] concurrentInspectors = config.getConcurrentInspectors();

      // Must have at least one concurrentInspector (else we may as well use CompositeInspector)

      if ( concurrentInspectors == null || concurrentInspectors.length == 0 ) {
         throw InspectorException.newException( "ConcurrentCompositeInspector needs at least one concurrentInspector" );
      }

      // Defensive copy

      mConcurrentInspectors = new Inspector[concurrentInspectors.length];

      for ( int loop = 0, length = concurrentInspectors.length; loop < length; loop++ ) {
         Inspector inspector = concurrentInspectors[loop];

         for ( int checkDuplicates = 0; checkDuplicates < loop; checkDuplicates++ ) {
            if ( mConcurrentInspectors[checkDuplicates].equals( inspector ) ) {
               throw InspectorException.newException( "ConcurrentCompositeInspector's list of Concurrent Inspectors contains two of the same " + inspector.getClass().getName() );
            }
         }

         mConcurrentInspectors[loop] = inspector;
      }
   }

   /**
    * Overriden to use a CyclicBarrier to run inspectors concurrently.
    */

   @Override
   protected Document runInspectors( Document masterDocument, final Object toInspect, final String type, final String... names )
      throws Exception {

      // Run concurrent Inspectors...

      int length = mConcurrentInspectors.length;
      final Document[] concurrentDocuments = new Document[length];

      // Prepare a CyclicBarrier of 'n concurrent inspectors + 1 primary thread'

      final CyclicBarrier barrier = new CyclicBarrier( length + 1 );

      for ( int loop = 0; loop < length; loop++ ) {
         final int concurrentInspectorIndex = loop;

         new Thread( "ConcurrentCompositeInspector Thread" ) {

            @Override
            public void run() {

               try {
                  concurrentDocuments[concurrentInspectorIndex] = ConcurrentCompositeInspector.this.runInspector( mConcurrentInspectors[concurrentInspectorIndex], toInspect, type, names );
               } catch ( Exception e ) {
                  throw InspectorException.newException( e );
               } finally {
                  try {
                     barrier.await();
                  } catch ( Exception e ) {
                     throw InspectorException.newException( e );
                  }
               }
            }
         }.start();
      }

      // ...run regular Inspectors at the same time (if any)...

      Document masterDocumentToUse;

      try {
         masterDocumentToUse = super.runInspectors( masterDocument, toInspect, type, names );
      } finally {
         barrier.await();
      }

      // ...merge the result...

      for ( Document concurrentDocument : concurrentDocuments ) {
         masterDocumentToUse = combineInspectionResult( masterDocumentToUse, concurrentDocument );
      }

      // ...and return

      return masterDocumentToUse;
   }
}

You'll also need a Config class:
package com.myapp;

import org.metawidget.inspector.composite.CompositeInspectorConfig;
import org.metawidget.inspector.iface.Inspector;
import org.metawidget.util.simple.ObjectUtils;

public class ConcurrentCompositeInspectorConfig
   extends CompositeInspectorConfig {

   private Inspector[]   mConcurrentInspectors;

   public Inspector[] getConcurrentInspectors() {

      return mConcurrentInspectors;
   }

   public ConcurrentCompositeInspectorConfig setConcurrentInspectors( Inspector... concurrentInspectors ) {

      mConcurrentInspectors = concurrentInspectors;

      return this;
   }

   @Override
   public boolean equals( Object that ) {

      if ( this == that ) {
         return true;
      }

      if ( that == null ) {
         return false;
      }

      if ( getClass() != that.getClass() ) {
         return false;
      }

      if ( !ObjectUtils.nullSafeEquals( mConcurrentInspectors, ( (ConcurrentCompositeInspectorConfig) that ).mConcurrentInspectors ) ) {
         return false;
      }

      return super.equals( that );
   }

   @Override
   public int hashCode() {

      int hashCode = super.hashCode();
      hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode( mConcurrentInspectors );

      return hashCode;
   }
}

And then you can deploy it like this:
<inspector>
   <concurrentCompositeInspector xmlns="java:com.myapp"
      config="ConcurrentCompositeInspectorConfig">
      <inspectors>
         <array>
            ...
         </array>
      </inspectors>
      <concurrentInspectors>
         <array>
            ...
         </array>
      </concurrentInspectors>
   </concurrentCompositeInspector>
</inspector>

This should spread the load across your cores. It's not a no-brainer: some Inspectors may rely on ThreadLocal variables (like FacesContext) and so will need to be kept on the primary Thread. But where it can be used, it works well.

Hope that helps!

Tuesday, September 21, 2010

Metawidget Neat Trick: Enhancing the RichFaces Color Picker

I thought I'd post a few blog entries about 'neat tricks' I've discovered while using Metawidget for my own clients (eating my own dog food, as it were).

The first one concerns a bugbear I've had with the RichFaces color picker widget. The widget looks like this:
It's a cool component, but for me it lacks an important feature: once you've chosen a color there's no way to unchoose it - to clear the box. This is annoying because typically getColor is a nullable field, so we need a way to null it. One approach would be to extend HtmlColorPicker (or its Renderer) and try to add the extra functionality - but that can be a bit scary.

Metawidget affords us a different approach. We can write a small WidgetProcessor and it will process every ColorPicker (across our entire application) and add the extra button. Here's the code:

package com.myapp;

import java.util.Map;

import javax.faces.application.Application;
import javax.faces.component.UIComponent;
import javax.faces.component.html.HtmlGraphicImage;
import javax.faces.context.FacesContext;

import org.metawidget.faces.component.UIMetawidget;
import org.metawidget.widgetprocessor.iface.WidgetProcessor;
import org.richfaces.component.html.HtmlColorPicker;

public class ColorPickerWidgetProcessor
   implements WidgetProcessor<UIComponent, UIMetawidget> {

   @Override
   public UIComponent processWidget( UIComponent component, String elementName, Map<String, String> attributes,
                     UIMetawidget metawidget ) {

      if ( !( component instanceof HtmlColorPicker ) ) {
         return component;
      }

      FacesContext context = FacesContext.getCurrentInstance();
      Application application = context.getApplication();

      UIComponent stubComponent = application.createComponent( "org.metawidget.Stub" );
      stubComponent.getChildren().add( component );

      HtmlGraphicImage graphicImage = (HtmlGraphicImage) application.createComponent( "javax.faces.HtmlGraphicImage" );
      graphicImage.setStyle( "vertical-align: middle; margin-left: 2px; cursor: pointer" );
      graphicImage.setValue( "/media/core.delete.gif" );
      graphicImage.setTitle( "Remove colour" );
      graphicImage.setOnclick( "if ( confirm( 'Okay to remove this colour?' )) { var picker = document.getElementById( '" + component.getClientId( context ) + "' ); picker.childNodes[0].value = ''; picker.childNodes[1].style.backgroundColor = '#ffffff'; }" );
      stubComponent.getChildren().add( graphicImage );

      return stubComponent;
   }
}


And here's what it produces:
Now you can click the red 'X' next to each ColorPicker, and it will use JavaScript to clear the box ready for POST back.

Feedback welcome!

Monday, September 20, 2010

UML Wallchart

Check out this awesome Metawidget wallchart created by Steffen Luypaert.

It's a large UML class diagram showing which technologies Metawidget can mix and match, and what configuration options are available. The wallchart includes all supported back-end technologies (shown in red), desktop frameworks (shown in green), web frameworks (shown in blue) and mobile frameworks (shown in yellow).

It's a great tool for both familiarising yourself with the overall architecture of Metawidget, and for exploring what plugins are available. It's downloadable as a PNG image designed to be printed across two pieces of landscape A3 or A4 paper. Click here to download it.

Thanks Steffen!

Click here to download the UML wallchart