7.2 Web WidgetProcessors

Metawidget supports multiple WidgetProcessors for each Web framework, targeting specific features within each environment.

7.2.1 GWT WidgetProcessors

Property Binding

Like most other Metawidgets, GwtMetawidget supports property binding. Property binding generally requires reflection, and GWT recommends using Generators to achieve this. As of the time of writing, however, much of the burden of implementation rests on the developer.

GwtMetawidget automates this burden by supplying a SimpleBindingProcessor implementation. This implementation is pluggable, so may be swapped out as and when later releases of GWT more fully support data binding.

SimpleBindingProcessor expects every domain object to be wrapped with a SimpleBindingProcessorAdapter. The supplied SimpleBindingProcessorAdapterGenerator automates this process. To configure it, add the following to the application-name.gwt.xml file...

<generate-with
	class="org.metawidget.gwt.generator.widgetprocessor.binding.simple.SimpleBindingProcessorAdapterGenerator">
	<when-type-assignable class="org.metawidget.example.shared.addressbook.model.Contact"/>
</generate-with>

...and in the application code...

metawidget.addWidgetProcessor( new SimpleBindingProcessor(
new SimpleBindingProcessorConfig().setAdapter( Contact.class,
	(SimpleBindingProcessorAdapter<Contact>) GWT.create(Contact.class)));
[Important]ClassCastException
If this line throws a ClassCastException casting to SimpleBindingProcessorAdapter, it means GWT is not applying the SimpleBindingProcessorAdapterGenerator. Check you've specified the correct class in your generate-with block.

Updates to the UI can be saved back to the setToInspect by calling save:

myMetawidget.getWidgetProcessor( SimpleBindingProcessor.class ).save( myMetawidget )

After Widgets have been generated for the initial setToInspect, clients can load values for a new Object into the same UI without a full re-inspection by using rebind:

myMetawidget.getWidgetProcessor( SimpleBindingProcessor.class ).rebind( newObject, myMetawidget )

For more details, see Section 9.5.4, “Rebinding”.

Action Binding

GWT supplies com.google.gwt.user.client.ui.ClickListener for binding Buttons to backing objects. It is futher possible to combine this with a generator to support runtime binding. This is exactly what the default action binding, SimpleBindingProcessor, does.

However, Metawidget makes action bindings pluggable to support other use cases. In particular, use cases where there is no backing object, and instead the Button should invoke, say, an RPC call (for an example, see Section 1.4.9, “GWT Client Side Example”). Implement your own pluggable binding by implementing WidgetProcessor and use it by calling...

myMetawidget.addWidgetProcessor( new MyWidgetProcessor() );

StyleNameProcessor

StyleNameProcessor sets styleName on all generated widgets, based on the styleName of the parent Metawidget. It does not 'drill into' Stubs.

7.2.2 JavaScript WidgetProcessors

AngularWidgetProcessor

WidgetProcessor to add Angular JS bindings and validation, and compile the widget.

BootstrapWidgetProcessor

WidgetProcessor to add CSS styles for Bootstrap. For example, adds:

HTML Tag Name CSS
BUTTON btn
TABLE table table-striped table-bordered table-hover
INPUT SPAN class="add-on" if inputPrepend attribute is set

DisabledAttributeProcessor

WidgetProcessor that sets the 'disabled' attribute.

IdProcessor

WidgetProcessor that sets the 'id' attribute.

RequiredAttributeProcessor

WidgetProcessor that sets the 'required' attribute.

SimpleBindingProcessor

Simple data/action binding implementation. Frameworks that supply their own data-binding mechanisms should override this with their own WidgetProcessor.

SimpleBindingProcessor binds properties using widget.value. To save values back into the domain object, clients must call save:

mw.getWidgetProcessor( function( widgetProcessor ) {
	return widgetProcessor instanceof metawidget.widgetprocessor.SimpleBindingProcessor;
} ).save( mw );

SimpleBindingProcessor can also reload the values in the widgets. This is independent of toInspect, and it doesn't save any values back from the widgets. But it can be useful in Node.js environments for re-populating the widgets based on an HTTP request POST-back:

mw.getWidgetProcessor( function( widgetProcessor ) {
	return widgetProcessor instanceof metawidget.widgetprocessor.SimpleBindingProcessor;
} ).reload( requestData, mw );

7.2.3 JSF WidgetProcessors

AjaxProcessor

AjaxProcessor adds a JSF 2.0 AjaxBehavior to any widgets with a faces-ajax-action attribute.

CssStyleProcessor

CssStyleProcessor sets style and styleClass properties on all generated widgets, based on the style and styleClass of the parent Metawidget. It does not 'drill into' UIStubs.

HiddenFieldProcessor

Many Web applications store their data at the HttpServletRequest level, not at the HttpSession level. Using session-level state (or, ideally, a UI framework that supports some kind of 'conversation'-level state) is safer than passing variables to and from the client in hidden HTML fields. However, for those that need this approach HiddenFieldProcessor wraps a Stub containing an HtmlInputHidden around read-only values, so that they POST back.

ImmediateAttributeProcessor

ImmediateAttributeProcessor sets UIInput.setImmediate for any widgets with a faces-immediate attribute.

LabelProcessor

LabelProcessor sets JSF 1.2's setLabel for those UIComponents that support it. This label is used during validation errors and conversion errors (even if the UIComponent does not explicitly have a converter).

ReadableIdProcessor

ReadableIdProcessor sets 'human readable' ids for each widget. Unlike UIViewRoot.createUniqueId, it tries to make the id readable both for debugging purposes and for when running unit tests (using, say, WebTest). Because the ids are based off the value binding (or method binding) of the UIComponent, this WidgetProcessor must come after StandardBindingProcessor (or equivalent).

Clients can plug in a different WidgetProcessor to use UIViewRoot.createUniqueId if preferred. They can even plug in assigning a changing, random id to a component each time it is generated. This is a great way to fox hackers who are trying to POST back pre-generated payloads of HTTP fields (i.e. CSRF attacks).

RequiredAttributeProcessor

RequiredAttributeProcessor sets UIInput.setRequired for any widgets with a required attribute.

RichFacesProcessor

RichFacesProcessor adds a RichFaces AJAX Support widget to any widgets with a faces-ajax-action attribute (for JSF 2.0, see also AjaxProcessor).

StandardBindingProcessor

StandardBindingProcessor attaches standard JSF value and action bindings to each widget.

StandardConverterProcessor

StandardConverterProcessor attaches standard JSF converters to each widget as needed. This includes DateTimeConverter and NumberConverter, and support for the faces-converter attribute.

StandardValidatorProcessor

StandardValidatorProcessor attaches standard JSF validators to each widget as needed. This includes DoubleRangeValidator, LongRangeValidator and LengthValidator.

7.2.4 JSP WidgetProcessors

HiddenFieldProcessor

Many Web applications store their data at the HttpServletRequest level, not at the HttpSession level. Using session-level state (or, ideally, a UI framework that supports some kind of 'conversation'-level state) is safer than passing variables to and from the client in hidden HTML fields. However, for those that need this approach HiddenFieldProcessor adds HTML hidden fields to read-only values, so that they POST back.

There are subclasses of HiddenFieldProcessor for JSP, Spring and Struts.

7.2.5 Vaadin WidgetProcessors

CaptionProcessor

CaptionProcessor calls setCaption on a Component, based on an uncamel-cased version of the business property name. This can then be used by Layouts such as org.metawidget.vaadin.ui.layout.FormLayout.

MinimumMaximumValidatorProcessor

MinimumMaximumValidatorProcessor adds a com.vaadin.data.Validator to a Component, based on either (or both) the Metawidget attributes minimum-value or maximum-value being set. These attributes can be set by, for example, using Hibernate Validator's @Range annotation.

RequiredProcessor

RequiredProcessor calls setRequired and setRequiredError on a Component, based on the Metawidget required attribute being set. This attribute can be set by, for example, using a @UiRequired annotation or Bean Validation's @NotNull annotation.

SimpleBindingProcessor

Like most other Metawidgets, VaadinMetawidget supports property binding. As of the time of writing, however, Vaadin leaves much of the implementation of property binding to the developer. VaadinMetawidget automates this by supplying a SimpleBindingProcessor. This implementation is pluggable, so may be swapped out as and when later releases of Vaadin more fully support data binding.

SimpleBindingProcessor binds properties using setValue. To save values back into the domain object, clients must call save:

myMetawidget.getWidgetProcessor( SimpleBindingProcessor.class ).save( myMetawidget )

If the type of the business property does not match the type expected by the Component, clients can register a Converter. First implement the org.metawidget.vaadin.ui.widgetprocessor.binding.simple.Converter interface...

public class ColorToStringConverter
	implements Converter<Color, String> {

	public String convert( Color value, Class<? extends String> expectedType ) {

		// return Color as a String (e.g. ff0000)
	}
}

...then register it either programmatically or in metawidget.xml:

<widgetProcessors>
	<array>
		<simpleBindingProcessor xmlns="java:org.metawidget.vaadin.ui.widgetprocessor.binding.simple"
				config="SimpleBindingProcessorConfig">
			<converter>
				<class>java.lang.Color</class>
				<class>java.lang.String</class>
				<colorToStringConverter xmlns="java:com.myapp"/>
			</converter>					
			<converter>
				...another converter...
			</converter>					
		</simpleBindingProcessor>
		...