GwtMetawidget is a client-side, JavaScript widget for GWT. Despite the limitations of the
JavaScript environment, GwtMetawidget supports reflection, annotations, pluggable layouts and data binding. For an introduction
to GwtMetawidget, see Section 1.2.2, “Web Address Book” and
Section 1.3.9, “GWT Hosted Mode Examples”.
There are five steps to installing Metawidget within a GWT application:
Update the application's .gwt.xml module to include Metawidet:
<module> <inherits name="org.metawidget.GwtMetawidget" /> ... </module>
Include both metawidget.jar and examples\gwt\metawidget-gwt-client.jar
in the CLASSPATH during the GWTCompiler phase. This provides the GwtMetawidget component.
Add metawidget.jar into WEB-INF/lib. This provides the GwtRemoteInspectorImpl servlet.
Update the application's web.xml to include GwtRemoteInspectorImpl:
<web-app> ... <servlet> <servlet-name>metawidget-inspector</servlet-name> <servlet-class>org.metawidget.inspector.gwt.remote.server.GwtRemoteInspectorImpl</servlet-class> </servlet> <servlet-mapping> <servlet-name>metawidget-inspector</servlet-name> <url-pattern>/metawidget-inspector</url-pattern> </servlet-mapping> </web-app>
You can (optionally) configure the default Inspector. To do this, add a
metawidget.xml file into WEB-INF, and an
init-param to your web.xml:
<init-param> <param-name>config</param-name> <param-value>metawidget.xml</param-value> </init-param>
A working example of all five steps can be found in addressbook-gwt.war included in the binary
distribution. You may also find the example-gwt-addressbook Ant task in the source
distribution's build.xml useful.
GwtMetawidget leverages Metawidget's separate Inspector/renderer
architecture and AJAX to perform server-side inspection as in Figure 3.1. This
allows GwtMetawidget to reflect properties and inspect annotations of business
objects, even though JavaScript supports neither.
The process is:
instantiate the business object on the client-side as normal (ie. as JavaScript)
give the business object to GwtMetawidget (a client-side, JavaScript GWT Widget)
GwtMetawidget uses AJAX to pass the business object to the server
the server, using Java, runs all the Inspectors (including reflection and annotations)
the server returns the inspection results as an XML document
GwtMetawidget uses JavaScript to render the HTML widgets
Note that steps 3 and 5 (the AJAX call to and from the server) are the most costly in terms of performance. Techniques to improve GWT performance are discussed in Section 9.3, “Rebinding”.
Like other Metawidgets, GwtMetawidget supports pluggable inspectors, layout managers and binding
implementations. However, the other Metawidgets do this using Class.newInstance, which
JavaScript does not support.
Instead, GwtMetawidget supplies GWT Generators in the form of
org.metawidget.gwt.generator.FactoryGenerator. At compile-time, each generator scans all the classes included in the
application and statically generates code to instantiate them. This is transparent to the application code,
which can simply do:
metawidget.setLayout( new FlexTableLayout() )
As noted in Section 3.2.1.2, “Reflection and Annotations” by default GwtMetawidget uses
server-side inspectors. This allows the full power of Java-based reflection but carries the performance cost of an AJAX call.
This cost can be mitigated by using rebinding (see Section 9.3, “Rebinding”), but there is
another way: inspection can be performed client-side, with no AJAX calls.
Setting up a client-side Inspector is very easy. The default GwtMetawidget
Inspector is GwtRemoteInspectorProxy, which is itself a client-side
Inspector (one that makes a remote call to GwtRemoteInspectorImpl). To
replace this default, simply implement your own Inspector:
public class MyClientSideInspector implements Inspector { public String inspect( Object toInspect, String type, String... names ) { return ...some XML string... } }
Make sure this Inspector is located under the client folder of your GWT application
so that it is compiled by the GWTCompiler into JavaScript. Use this Inspector by doing...
myGWTMetawidget.setInspectorClass( MyClientSideInspector.class )
...which overrides the default GwtRemoteInspectorProxy. Behind the scenes, GwtMetawidget
has a FactoryGenerator which takes care of generating JavaScript code to
instantiate your inspector.
For an example of this technique see Section 1.3.8, “GWT Client Side Example”.
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, Web
Metawidgets support that approach for those that need it through setCreateHiddenFields( true ).
UIMetawidget is a Java Server Faces component. For an introduction
to UIMetawidget, see Section 1.2.2, “Web Address Book”
and Section 1.3.2, “Seam Example”.
There are three steps to installing UIMetawidget within a JSF application:
Add metawidget.jar into WEB-INF/lib.
Add a tag library descriptor to the top of your JSP page...
<%@ taglib uri="http://metawidget.org/faces" prefix="m" %> ... <m:metawidget value="#{foo}"/> ...
...or Facelets page...
<ui:composition xmlns="http://www.w3.org/1999/xhtml" ... xmlns:m="http://metawidget.org/faces"> ... <m:metawidget value="#{foo}"/> ...
You can (optionally) configure the Metawidget by adding a metawidget.xml file into WEB-INF.
One of JSF's most important Look and Feel technologies is CSS. Metawidget supports several approaches to suit different needs.
By convention, JSF's HTML widgets (HtmlInputText, HtmlSelectBooleanCheckbox, etc) define
style and styleClass attributes for applying CSS styles and classes to their output.
HtmlMetawidget follows this convention. When expanding to a single widget (such as an
HtmlInputText) the CSS styles are applied to it. When expanding to multiple widgets,
all widgets have the same CSS styles applied to them.
Another important JSF Look and Feel technology is Renderers. Whilst often Renderers are discussed in the context of rendering the same widget to different platforms (eg. HTML or WML), they can equally be used to render the same widget to the same platform but in different layouts.
HtmlTableLayoutRenderer is the default LayoutRenderer. It further
defines parameters such as tableStyle,
labelStyle and columnStyleClasses parameters (see the
JavaDoc for a complete list). The latter is a comma separated list of CSS style classes to be applied to table columns. The first style
class is the label column, the second the widget column, and the third the 'required' column.
Further style classes may be used for multi-column layouts. You can get quite far using, for example:
.table-component-column input { width: 100%; }..this approach has the advantage of automatically applying to every widget, so overridden widgets do not have to explicitly set styleClass information. However, not all Web browsers support fine-grained CSS selectors such as...
.table-component-column input[type="button"] { width: auto; }
...in which case it may be better to switch to using styleClass on HtmlMetawidget itself.
Other supplied LayoutRenderers include div and simple (see
the JavaDoc, and the META-INF/faces-config.xml in metawidget.jar for a
complete list).
SpringMetawidget is a Spring taglib. For an introduction
to SpringMetawidget, see Section 1.2.2, “Web Address Book”.
There are three steps to installing SpringMetawidget within a Spring application:
Add metawidget.jar into WEB-INF/lib.
Add a tag library descriptor to the top of your JSP page:
<%@ taglib uri="http://metawidget.org/spring" prefix="m" %> ... <m:metawidget value="#{foo}"/> ...
You can (optionally) configure the Metawidget by adding a metawidget.xml file into WEB-INF.
JSP-based technologies do not distinguish between what a widget is versus how it is rendered.
Instead, SpringMetawidget mimics this by providing loosely coupled Layout classes.
Each layout can further be configured by using specific param tags.
With regard to overriding widget creation, JSP-based technologies such as Spring lack some component-based features.
Specifically, whilst it is possible for JSP tags to reference their parent (using TagSupport.findAncestorWithClass),
they have no way to enumerate their children. Therefore, it is not possible to
directly support arbitrary child tags within SpringMetawidgetTag. As a next best thing, Metawidget includes
StubTag for wrapping arbitrary tags. It also supports wrapping arbitrary HTML.
StrutsMetawidget is a Struts taglib. For an introduction
to StrutsMetawidget, see Section 1.2.2, “Web Address Book”.
There are three steps to installing StrutsMetawidget within a Struts application:
Add metawidget.jar into WEB-INF/lib.
Add a tag library descriptor to the top of your JSP page:
<%@ taglib uri="http://metawidget.org/struts" prefix="m" %> ... <m:metawidget value="#{foo}"/> ...
You can (optionally) configure the Metawidget by adding a metawidget.xml file into WEB-INF.
JSP-based technologies do not distinguish between what a widget is versus how it is rendered.
Instead, StrutsMetawidget mimics this by providing loosely coupled Layout classes.
Each layout can further be configured by using specific param tags.
With regard to overriding widget creation, JSP-based technologies such as Struts lack some component-based features.
Specifically, whilst it is possible for JSP tags to reference their parent (using TagSupport.findAncestorWithClass),
they have no way to enumerate their children. Therefore, it is not possible to
directly support arbitrary child tags within SpringMetawidgetTag. As a next best thing, Metawidget includes
StubTag for wrapping arbitrary tags. It also supports wrapping arbitrary HTML.
StrutsMetawidget creates native Struts widgets, such as <html:text>, but does
not create the surrounding Struts form. Make sure your Metawidget tag is enclosed in
a <html:form> tag and the Struts HTML taglib is included at the top of the page.