Thursday, February 24, 2011

User Interface Generation Tools: JAXenter Metawidget interview

I did a short interview with JAXenter about the recent v1.10 release of Metawidget, the user interface generation tool.

Thanks for the shout-out guys!

JAXenter have previously done an in-depth article on Metawidget here.

Thursday, February 10, 2011

User Interface Generation: Metawidget v1.10

Version 1.10 of Metawidget, the user interface generation tool is now available! This release includes the following enhancements:
As always, the best place to start is the Reference Documentation:

http://metawidget.org/doc/reference/en/pdf/metawidget.pdf

Special thanks to Ronald van Kuijk and Leon E for their help with this release!

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

Tuesday, February 8, 2011

Metawidget: PrimeFaces TabView support

In a similar fashion to my previous blog, the next release of Metawidget (v1.10) will add support for the PrimeFaces TabView component.

I have updated the AddressBook Example included in the distribution to demonstrate swapping in PrimeFaces support. So now you can add...

<metawidget>
   ...
   <layout>
      <tabViewLayoutDecorator xmlns="java:org.metawidget.faces.component.html.layout.primefaces"
         config="org.metawidget.layout.decorator.LayoutDecoratorConfig">

         <layout>
            <simpleLayout xmlns="java:org.metawidget.faces.component.layout"/>
         </layout>
      </tabViewLayoutDecorator>
   </layout>
</metawidget>

...and you auto-magically get (note the PrimeFaces TabView and the PrimeFaces Slider)...

Early access code now available in SVN.

Metawidget: ICEfaces PanelTabSet support

The next release (v1.10) of Metawidget improves our ICEfaces support by adding PanelTabSetLayoutDecorator. So now you can do:

<metawidget>
   ...
   <layout>
      <panelTabSetLayoutDecorator xmlns="java:org.metawidget.faces.component.html.layout.icefaces" config="org.metawidget.layout.decorator.LayoutDecoratorConfig">
         <layout>
            <simpleLayout xmlns="java:org.metawidget.faces.component.layout"/>
         </layout>
      </panelTabSetLayoutDecorator>
   </layout>
</metawidget>

I have updated the ICEfaces PenguinColony Example included in the distribution to include tabs inside the dialog:
The full ICEfaces AJAX experience of dynamically creating components still works as normal inside the tabs:



Early access code now available in SVN.

Monday, February 7, 2011

Cluster Ointment: JBoss, JGroups and Shunning

For some months now we've been having intermittent problems with our JBoss cluster. Whenever a cluster node died and restarted, sometimes it would fail to rejoin the cluster. The log would just keep saying:

WARN [org.jgroups.protocols.pbcast.GMS] join(<IP address>) sent to <IP address> timed out (after 3000 ms), retrying
WARN [org.jgroups.protocols.pbcast.GMS] join(<IP address>) sent to <IP address> timed out (after 3000 ms), retrying
WARN [org.jgroups.protocols.pbcast.GMS] join(<IP address>) sent to <IP address> timed out (after 3000 ms), retrying
WARN [org.jgroups.protocols.pbcast.GMS] join(<IP address>) sent to <IP address> timed out (after 3000 ms), retrying

This happened on JBoss 4.0.3, 4.2, 5.0 and 5.1. But today I found some interesting tidbits:
  • When a [JGroups] member [defined by its IP and port number] is expelled from the group, e.g. because it didn't respond to are-you-alive messages, and later comes back, then it is shunned (source)
  • JGroups relies on the fact that the assignment of ports by the OS is always (not necessarily monotonically) increasing across a single machine... [but this may not hold] for TCP ... because we're defining the start_port for a member, and so that member will always reuse the same port when restarted [the term is 'reincarnated'] (source)
  • In [JGroups] 2.8, shunning has been removed, so the sections below only apply to versions up to 2.7 (source)
So any version of JBoss using JGroups 2.7 or earlier (which includes JBoss 5.1) will see this problem if you're explictly defining the start_port for a node. The solution is to edit jgroups-channelfactory-stacks.xml:

<FD_SOCK/>
<FD timeout="6000" max_tries="5" shun="false"/>
<VERIFY_SUSPECT timeout="1500"/>
<pbcast.NAKACK use_mcast_xmit="false" gc_lag="0"
   retransmit_timeout="300,600,1200,2400,4800"
   discard_delivered_msgs="true"/>
<UNICAST timeout="300,600,1200,2400,3600"/>
<pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"
   max_bytes="400000"/>
<pbcast.GMS print_local_addr="true" join_timeout="3000"
   shun="false"
   reject_join_from_existing_member="false"

   view_bundling="true"
   view_ack_collection_timeout="5000"/>

This has shown an immediate improvement in our cluster. Hope it works for you too!

Wednesday, February 2, 2011

Metawidget: Defining Business Objects Using Maps (JSF Version)

I thought I'd do a JSF 2 version of my previous blog entry. Doing it in JSF is a litte more difficult to grok, because the all important methods...

metawidget.setToInspect( values );
metawidget.setPath( "person" );

...are obscured behind JSF's standard syntax:

<m:metawidget value="#{...}"/>

There are a number of ways you could unobscure them, but so as not to be confusing I'll just talk about one here. Basically I will wrap the 'toInspect' values and the 'path' type in MyManagedBean so that I can pass them both in a single ValueExpression:

<m:metawidget value="#{myManagedBean}"/>

Regardless, the crucial point - as with the Swing version - is that there's a MapInspector and a MapWidgetProcessor and they operate on different Maps.

You can download the complete project here.

Metawidget: Defining Business Objects Using Maps

I was recently asked whether Metawidget could inspect, load and save business objects based not on a JavaBean (or GroovyBean, ScalaBean etc) but on a Map of names and attributes. The answer is yes!

I've sort of covered this before but last time I only blogged about inspecting the Map, not loading and saving the values.We already have a GWT version of this in the Metawidget distribution (see the GWT Client Side example) but now I've put together a Swing project you can download too. It's very similar to the previous blog but adds a MapWidgetProcessor that loads and saves values back into a Map.

An important point to grok is that the 'Map of properties' (used by MapInspector) is different to the 'Map of values' (used by MapWidgetProcessor). This is in the same way that a 'Class' is different to an 'Object': one defines the type, one defines the instance values. So in the code you will see:

metawidget.setToInspect( values );
metawidget.setPath( "person" );

We call both setToInspect (to tell Metawidget where the values are coming from) and setPath (to tell Metawidget what the type is). Normally when using a JavaBean (or GroovyBean, ScalaBean etc) you don't need to do this, because Metawidget will internally call...

metawidget.setPath( metawidget.getToInspect().getClass() )

...on your behalf. But if you want to start using Maps, these two concepts need to be explictly separate.

Take a look for yourself here. Or, for the impatient, here's the most important piece of code:

/**
* MapWidgetProcessor uses the Metawidget's <code>toInspect</code> to retrieve/store values.
*/

public class MapWidgetProcessor
   implements AdvancedWidgetProcessor<JComponent, SwingMetawidget> {

   //
   // Public methods
   //

   @Override
   public void onStartBuild( SwingMetawidget metawidget ) {

      getWrittenComponents( metawidget ).clear();
   }

   /**
    * Retrieve the values from the Map and put them in the Components.
    */


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

      String attributeName = attributes.get( NAME );
      getWrittenComponents( metawidget ).put( attributeName, component );

      // Fetch the value...

      Map<String, Object> toInspect = metawidget.getToInspect();
      Object value = toInspect.get( attributeName );

      if ( value == null ) {
         return component;
      }

      // ...and apply it to the component. For simplicity, we won't worry about converters

      String componentProperty = metawidget.getValueProperty( component );
      ClassUtils.setProperty( component, componentProperty, value );

      return component;
   }

   @Override
   public void onEndBuild( SwingMetawidget metawidget ) {

      // Do nothing
   }

   /**
    * Store the values from the Components back into the Map.
    */


   public void save( SwingMetawidget metawidget ) {

      Map<String, Object> toInspect = metawidget.getToInspect();

      for ( Map.Entry<String,JComponent> entry : getWrittenComponents( metawidget ).entrySet() ) {

         JComponent component = entry.getValue();
         String componentProperty = metawidget.getValueProperty( component );
         Object value = ClassUtils.getProperty( component, componentProperty );

         toInspect.put( entry.getKey(), value );
      }
   }

   //
   // Private methods
   //

   /**
    * During load-time we keep track of all the components. At save-time we write them all back
    * again.
    */


   private Map<String,JComponent> getWrittenComponents( SwingMetawidget metawidget ) {

      @SuppressWarnings( "unchecked" )
      Map<String,JComponent> writtenComponents = (Map<String,JComponent>) metawidget.getClientProperty( MapWidgetProcessor.class );

      if ( writtenComponents == null ) {
         writtenComponents = CollectionUtils.newHashMap();
         metawidget.putClientProperty( MapWidgetProcessor.class, writtenComponents );
      }

      return writtenComponents;
   }
}