Following a recent request, the next release of Metawidget will add support for XML Schema (XSD) files. It should be useful for anybody wanting to automatically generate User Interfaces from XSD schemas, Web Services Description Language (WSDL) files, or SOAP.
To use, simply take an existing XML Schema or WSDL file:
<wsdl:definitions ...>
...
<wsdl:types>
<xsd:schema>
<xsd:element name="GetEndorsingBoarder">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="name" type="string" minOccurs="1" />
<xsd:element name="manufacturer" type="string" />
<xsd:element name="model" type="xs:integer" />
<xsd:element name="quantity">
<xsd:simpleType>
<xsd:restriction base="xs:integer">
<xsd:minInclusive value="0" />
<xsd:maxInclusive value="8" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="active" type="xs:boolean" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
...
</wsdl:definitions>
...point Metawidget at it...
public static void main( String[] args ) {
final SwingMetawidget metawidget = new SwingMetawidget();
metawidget.setInspector( new WsdlInspector(
new XmlSchemaInspectorConfig().setInputStream( new SimpleResourceResolver()
.openResource( "endorsementSearch.wsdl" ) ) ) );
metawidget.addInspectionResultProcessor( new XmlSchemaToJavaTypeMappingProcessor
metawidget.setPath( "GetEndorsingBoarder" );
JFrame frame = new JFrame( "Metawidget WSDL" );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.getContentPane().add( metawidget );
frame.setSize( 400, 210 );
metawidget.setBorder( BorderFactory.createEmptyBorder( 5,5,5,5 ) );
frame.setVisible( true );
}
}
...and this will create the screenshot seen below:
Getting data into the UI components and back out again will vary depending on your requirements (choice of UI toolkit, choice of data storage etc). Here's a simple implementation that reads/writes from a DOM document to Swing JComponents:
implements AdvancedWidgetProcessor<JComponent, SwingMetawidget> {
//
// Public methods
//
@Override
public void onStartBuild( SwingMetawidget metawidget ) {
getWrittenComponents( metawidget ).clear();
}
/**
* Retrieve the values from the Document 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...
Document toInspect = metawidget.getToInspect();
Element root = toInspect.getDocumentElement();
Element valueNode = XmlUtils.getChildNamed( root, attributeName );
if ( valueNode == 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, valueNode.getTextContent() );
return component;
}
@Override
public void onEndBuild( SwingMetawidget metawidget ) {
// Do nothing
}
/**
* Store the values from the Components back into the Document.
*/
public void save( SwingMetawidget metawidget ) {
Document toInspect = metawidget.getToInspect();
Element root = toInspect.getDocumentElement();
for ( Map.Entry<String, JComponent> entry : getWrittenComponents( metawidget ).entrySet() ) {
JComponent component = entry.getValue();
String componentProperty = metawidget.getValueProperty( component );
Object value = ClassUtils.getProperty( component, componentProperty );
Element valueNode = XmlUtils.getChildNamed( root, entry.getKey() );
if ( valueNode == null ) {
continue;
}
valueNode.setTextContent( (String) 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( DocumentBindingProcessor.class );
if ( writtenComponents == null ) {
writtenComponents = CollectionUtils.newHashMap();
metawidget.putClientProperty( DocumentBindingProcessor.class, writtenComponents );
}
return writtenComponents;
}
}
To use it, simply add it into your Metawidget's pipeline:
metawidget.addWidgetProcessor( new DocumentBindingProcessor() );
String xml = "<endorsingBoarder><name>Richard</name><manufacturer>Kennard Consulting</manufacturer></endorsingBoarder>";
final Document document = XmlUtils.documentFromString( xml );
metawidget.setToInspect( document );
metawidget.setPath( "GetEndorsingBoarder" );
...
metawidget.add( new JButton( new AbstractAction( "Save" ) {
public void actionPerformed( ActionEvent e ) {
metawidget.getWidgetProcessor( DocumentBindingProcessor.class ).save( metawidget );
System.out.println( XmlUtils.documentToString( document, true ));
}
} ));
And you'll get this:
Feedback welcome!