Friday, October 30, 2009

XSL-FO number-columns-spanned="remainder"

Every so often when developing some XSL-FO I get the dreaded...

column-number or number of cells in the row overflows the number of fo:table-column specified for the table

...these tend to be a nightmare to track down, and very fiddly to fix, because often you need to add a number-columns-spanned attribute to one of the fo:table-cell elements, and in a dynamic world you have to figure out exactly how many cells to span. Agh!

It'd be much easier if XSL-FO let you just say number-columns-spanned="remainder". So today I wrote a little XSLT that you can put after your XSL-FO and before you try to serialize it (with something like Apache FOP).

<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
            xmlns:fo="http://www.w3.org/1999/XSL/Format">

   <!-- number-columns-spanned: remainder -->
   
   <xsl:template match="fo:table-cell[@number-columns-spanned = 'remainder']" mode="#all">
   
      <xsl:copy>
         <xsl:attribute name="number-columns-spanned">
            <xsl:variable name="number-columns-in-table" as="xs:integer">
               <xsl:value-of select="count(ancestor::fo:table[1]/fo:table-column)"/>
            </xsl:variable>
            <xsl:variable name="number-columns-in-row" as="xs:integer">
               <xsl:value-of select="count(preceding-sibling::fo:table-cell[not(@number-columns-spanned)]) + count(following-sibling::fo:table-cell[not(@number-columns-spanned)])"/>
            </xsl:variable>
            <xsl:variable name="number-spanned-columns-in-row" as="xs:integer">
               <xsl:value-of select="sum(preceding-sibling::fo:table-cell[@number-columns-spanned ne 'remainder']/@number-columns-spanned) + sum(following-sibling::fo:table-cell[@number-columns-spanned ne 'remainder']/@number-columns-spanned)"/>
            </xsl:variable>
            <xsl:value-of select="$number-columns-in-table - $number-columns-in-row - $number-spanned-columns-in-row"/>
         </xsl:attribute>
         <xsl:apply-templates select="@*[not(local-name() = 'number-columns-spanned')]|node()"/>
      </xsl:copy>
      
   </xsl:template>


   <!-- identity transform -->
   
   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>

</xsl:stylesheet>

I should've done it years ago. Note unfortunately it won't work if you've got other rows that are using number-rows-spanned. Improvements welcome!

Thursday, October 15, 2009

User Interface Generator: Metawidget v0.85

Version 0.85 of Metawidget, the user interface generator, is now available! This release has something for everyone:

For first time users, we have updated and improved the User Guide. For intermediate users, we have greatly expanded the architecture documentation, with lots more diagrams and detailed explanations. And for advanced users, we have substantially refactored the internals, including introducing new pluggable WidgetProcessors to handle more demanding requirements. Please note there are unfortunately some breaking changes, as covered in the Migration Guide.

In addition we have improved our support for RichFaces (now includes SuggestionBox, TabPanel and RichPanel), ExtGWT (now includes Slider), Swing (now includes configurable labels), and have added XML schemas for every component and lots more unit tests.

Special thanks to Girolamo Violante and Illya Yalovyy for their help with this release!

As always, the best place to start is the Reference Documentation:

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

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

Friday, October 2, 2009

Metawidget 0.8 to 0.85 Migration Guide

The next release of Metawidget (v0.85, due in late October) will represent a significant refactoring of the Metawidget internals, aimed at increasing API clarity and consistency, code reuse, type safety and extensibility - all in preparation for our 1.0 release. As such, there will be a number of breaking changes.

We apologise for this disruption and provide this Migration Guide to help in moving from v0.8 to v0.85. All of the existing documentation and examples have already been migrated, as a reference point.

WidgetProcessors

The big new change is the concept of a 'widget processor'. These are lightweight, pluggable classes who can 'process' a widget just after its building (by the WidgetBuilder) and before it is laid out (by the Layout).


The interface is simply:

W processWidget( W widget, String elementName, Map<String, String> attributes, M metawidget )

This is great because:

  • It allows you to plug-in arbitrary processing of a widget without touching the Metawidget class itself. For example you could write a widget processor to add a tooltip to every component:

    JComponent processWidget( JComponent widget, String elementName, Map attributes, SwingMetawidget metawidget ) {
       widget.setToolTipText( attributes.get( NAME ));
       return widget;
    }

  • It provides more ways to identify and process a widget than getComponent( String... names ), for situations where you don't know the component's name in advance

  • It allows you to attach Event Handlers as inner classes that have connections to their parent class:

    final Object someObject = ...;

    metawidget.addWidgetProcessor( new BaseWidgetProcessor() {
    JComponent processWidget( JComponent widget, String elementName, Map<String, String> attributes, SwingMetawidget metawidget ) {
       ...decide whether to attach event handler...

       widget.add( new AbstractAction() {
          public void actionPerformed( ActionEvent event ) {
             someObject.doSomething();
          }
       }
    }
    }

  • Standardizing this concept allows us to refactor a lot of previously ad-hoc functionality. For example all binding and validation functionality are now implemented as widget processors:


    They can be chained together either programmatically or in metawidget.xml:

    <widgetProcessors>
       <list>
          <processor:requiredAttributeProcessor />
          <processor:immediateAttributeProcessor />
          <processor:standardBindingProcessor />
          <processor:readableIdProcessor />
          <processor:labelProcessor />
          <processor:standardValidatorProcessor />
          <processor:standardConverterProcessor />
       </list>
    </widgetProcessors>

Refactored save(), rebind(), validate()

As mentioned, binding and validation have now been refactored into WidgetProcessors. This has the advantage of moving methods such as save() and validate() out of the Metawidget (where they weren't always applicable) and into the responsible WidgetProcessor (where they will always be applicable, by definition).

This unfortunately means a slightly more cumbersome API. Instead of...

metawidget.save()

...you now have to do...

metawidget.getWidgetProcessor( BeansBindingProcessor.class ).save( metawidget )
...however we think the tradeoff is worth it.

metawidget.xml now supports (and mostly uses) <array>

ConfigReader now natively supports an <array> element. This allows it to natively call vararg methods, removing the need for some of the overloaded methods in the xxxConfig classes.

Most current usages of <list> should be replaced with <array>. Lists (and Sets) are still supported for your custom use-cases.

Refactored setCreateHiddenFields

JSF hidden field creation has also been refactored into a WidgetProcessor. For example:

<widgetProcessors>
   <list>
      <hiddenFieldProcessor />
   </list>
</widgetProcessors>

Layouts must now be immutable

Layouts are now a standardized part of the Metawidget pipeline. They must implement the new org.metawidget.layout.iface.Layout interface, and must be threadsafe and immutable just like Inspectors, WidgetBuilders and WidgetProcessors. Custom Layouts that are currently thread-unsafe or mutable need to be refactored in a couple of ways:

  • Configuration settings, that do not change over the lifetime of the Layout and would previously have been retrieved via metawidget.getParameter (and possibly saved into member variables), should now be configured by an external xxxConfig class. For example:

    public GridBagLayout() {
       this( new GridBagLayoutConfig() );
    }

    public GridBagLayout( GridBagLayoutConfig config ) {
       mNumberOfColumns = config.getNumberOfColumns();
       mLabelAlignment = config.getLabelAlignment();
       mSectionStyle = config.getSectionStyle();
       mLabelSuffix = config.getLabelSuffix();
       mRequiredAlignment = config.getRequiredAlignment();
       mRequiredText = config.getRequiredText();
    }

    ...and configured either programmatically or in metawidget.xml:

    <layout>
       <htmlTableLayout xmlns="java:org.metawidget.jsp.tagext.html.layout" config="HtmlTableLayoutConfig">
          <tableStyle>
             <string>aTableStyle</string>
          </tableStyle>
       </htmlTableLayout>
    </layout>

  • Internal state that changes during layout and was stored in member variables should now be stored in the parent Metawidget. For example:

    State state = (State) metawidget.getClientProperty( GridBagLayout.class );
    state.currentRow++;

No more metawidget.setParameter or m:param

The previously (type unsafe) metawidget.setParameter methods and m:param tags have now been removed, in favour of typesafe configuration objects on the WidgetProcessors and Layouts. So instead of...

metawidget.setPropertyBindingClass( BeansBinding.class )
metawidget.setParameter( "updateStrategy", UpdateStrategy.READ )

...you now do...

metawidget.addWidgetProcessor( new BeansBindingProcessor(
   new BeansBindingProcessorConfig()
      .setUpdateStrategy( UpdateStrategy.READ )));

...or equivalent in metawidget.xml.

ConfigReader Moved

ConfigReader has now been moved out of org.metawidget.inspector and into the new org.metawidget.config. This reflects it outgrowing its roots as a purely Inspector-focussed mechanism, into a general purpose way to configure Metawidgets.

XSDs

Existing XSDs have now been moved under http://metawidget.org/xsd. In addition, all the XSDs for the Inspectors, WidgetBuilders etc have been generated.

PropertyStyles and ActionStyles are now objects

ConfigReader is now smart enough to reuse PropertyStyle and ActionStyles instances between Inspectors. This means they are now specified on the Inspector as an object, not their class. This opens the door to people writing their own, configrable property styles if they need to.

Ant Build

The formerly monolithic build.xml has been split into several smaller ones. The original (/build.xml) now only builds Metawidget itself. There is a separate /examples/build.xml (builds examples), /test/build.xml (runs unit tests), /src/doc/build.xml (builds documentation) and /src/web/build.xml (builds Web site).

Similarly, the lib folder has now been split into /lib, /examples/lib and /test/lib.

Java Puzzler: enforcing whether a class overrides equals/hashCode


The Problem

Let's say I'm writing a Java class that requires users of my class override equals and hashCode on their objects. I'd be in good company: lots of classes do this, not least the java.util.Collection classes like List and Set.

This important requirement is generally only recorded in the JavaDoc, with a stern warning that Bad Things Will Happen if you forget. But the requirement is not enforced at runtime, much less compile time.

The Question

What if I wanted to enforce it? What if I wanted to write a class like HashMap that made sure anything you put in it overrode equals and hashCode? What if I'm prepared to sacrifice a little performance and/or code complexity to do this? What are my choices? Can I do it at runtime? Better yet, can I do it at compile-time?

The Answer?

I don't know a great answer. I don't know of any libraries that do. I'd love some feedback on helping eliminate this important category of subtle bugs.

To get the ball rolling, this is what I'm thinking of doing in Metawidget:

Class classToTest = objectToCache.getClass();
Object dummy1 = classToTest.newInstance();
Object dummy2 = classToTest.newInstance();

if ( !dummy1.equals( dummy2 ))
throw new Exception( classToTest + " does not override .equals(), so cannot be reliably cached" );

if ( dummy1.hashCode() != dummy2.hashCode() )
throw new Exception( classToTest + " does not override .hashCode(), so cannot be reliably cached" );

This approach takes advantage of the fact that, given your class has internal state, two brand new instances should always have equivalent state, but the default Object.equals (which uses ==) will return false. It's not perfect. It'll work if you write a POJO and forget to override equals. But it won't work if your superclass overrides equals but your subclass, which adds some more internal state, forgets to. But it's a start.

Note that, annoyingly, this doesn't seem to work:

class.getDeclaredMethod( "hashCode" )

Public methods like hashCode and equals are always considered 'declared methods', even if the class doesn't actually declare them. Similarly:

class.getDeclaredMethod( "hashCode" ).getDeclaringClass()

Always returns the subclass name, even if the subclass doesn't override hashCode.

Suggestions welcome!

Update

Thanks to everyone for the really helpful comments. The first thing to note is that...

class.getDeclaredMethod( "hashCode" ).getDeclaringClass()

...does actually work. I don't know why it didn't seem to when I tried it originally. Evidentally I am an idiot!

Anyway, here's what's currently going into Metawidget, based on everyone's feedback:

Class<?> configClass = configToStoreUnder.getClass();

// Hard error

// equals

Class<?> equalsDeclaringClass = configClass.getMethod( "equals", Object.class ).getDeclaringClass();

if ( Object.class.equals( equalsDeclaringClass ) )
throw new Exception( configClass + " does not override .equals(), so cannot cache reliably" );

// hashCode

Class<?> hashCodeDeclaringClass = configClass.getMethod( "hashCode" ).getDeclaringClass();

if ( Object.class.equals( hashCodeDeclaringClass ) )
throw new Exception( configClass + " does not override .hashCode(), so cannot cache reliably" );

if ( !equalsDeclaringClass.equals( hashCodeDeclaringClass ) )
throw new Exception( equalsDeclaringClass + " implements .equals(), but .hashCode() is implemented by " + hashCodeDeclaringClass + ", so cannot cache reliably" );

if ( !configClass.equals( equalsDeclaringClass ) )
{
// Soft warning
//
// Note: only show this if the configClass appears to have its own 'state'.
// Base this assumption on whether it declares any methods. We don't want to
// use .getDeclaredFields because that requires a security manager
// check of checkMemberAccess(Member.DECLARED), whereas we may only have
// checkMemberAccess(Member.PUBLIC) permission

for ( Method declaredMethod : configClass.getMethods() )
{
if ( configClass.equals( declaredMethod.getDeclaringClass() ) )
{
LOG.warn( configClass + " does not override .equals() (only its super" + equalsDeclaringClass + " does), so may not be cached reliably" );
break;
}
}

// Note: not necessary to do !configClass.equals( hashCodeDeclaringClass ),
// as will already have thrown an Exception from
// !equalsDeclaringClass.equals( hashCodeDeclaringClass ) if that's the case
}

Improvements welcome!