30
Wolf Paulus Declarative Programming : UI - Generation at Runtime with Swix ML wolfpaulus.com

Declarative Programming, emphasizing UI Generation at Runtime

Embed Size (px)

DESCRIPTION

Graphical User Interfaces are described in XML documents that are parsed at runtime and rendered into UI-Widgets. While open-source projects like Thinlet and Swixml focus mainly on the GUI, they are also good examples for how declarative programming can be done in Java.

Citation preview

Page 1: Declarative Programming, emphasizing UI Generation at Runtime

Wolf Paulus

Declarative Programming :UI-Generation at Runtime with SwixML

wolfpaulus.com

Page 2: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

1. Declarative Programming

2. Reflection and Introspection in JAVA

3. Thinlets, Declarative GUI Toolkit for Java

4. Theodore, a Thinlet XUL Editor

1.Demo and Code

5. Swixml, GUI Generation Engine

6. Custom Tags and Bindings

7. Mapping of private members

1. Code, Demo and more Code

Page 3: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Declarative programming concentrates on expressing a set of conditions, describing a solution space, but leaves finding a solution to an engine, dedicated to a certain class of problems.

Wikipedia:

Page 4: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Writing programs in a declarative style in an imperative programming

language usually requires lots of runtime information.*

*for Java, this means Reflection & Introspection

Page 5: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Computational reflection is the ability of a program to observe and possibly modify its high level structure.

It is most common in high-level virtual machine programming languages like Smalltalk, and less common in lower-level programming languages like C.

Wikipedia:

Page 6: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Reflection in JavaJava allows a program to discover information about the fields, methods, and constructors of loaded classes. Also, a Java program can instantiate a class and operate on the underlying objects, (within security restrictions.)

Reflection is the process of looking at an object during run time in order to understand its features or properties.

Where the reflection process analyzes the object itself to discover the object’s properties, Introspection relies on the class to provide information on its behalf.

Page 7: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

package com.carlsbadcubes.codecamp;

import java.lang.reflect.Method;import java.util.Vector;

public class Reflector { /** * Find all methods that can be called on the given object that * <li> start with the prefix <i>set</i> </li> * <li> take only a single parameter </li> * <li> and have the return type <i>void</i></li> * @param client <code>Object</code> * @return <code>Vector</code> containing possibly setters methods */ public static Vector<Method> getSetters(final Object client) { Vector<Method> setters = new Vector<Method>(); Method[] methods = client.getClass().getMethods(); for (Method method : methods) { if (method.getName().startsWith("set") && method.getParameterTypes().length == 1 && method.getReturnType() == void.class) { setters.add(method); } } return setters; }}

Reflection

Page 8: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

package com.carlsbadcubes.codecamp;

import junit.framework.TestCase;import javax.swing.*;import java.lang.reflect.Method;import java.util.Vector;

public class ReflectorTest extends TestCase {

public void testFindSetters() { Object obj = new JLabel("hello"); Vector<Method> setters = Reflector.getSetters(obj);

TestCase.assertTrue(setters != null); TestCase.assertTrue(0 < setters.size());

for (Method setter : setters) System.out.println( setter.getDeclaringClass().getName() +":"+ setter); }}

Reflection TestC

ase

Page 9: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Methods found:

public void javax.swing.JLabel.setUI(javax.swing.plaf.LabelUI)public void javax.swing.JLabel.setText(java.lang.String)public void javax.swing.JLabel.setIcon(javax.swing.Icon)public void javax.swing.JLabel.setDisabledIcon(javax.swing.Icon)public void javax.swing.JLabel.setVerticalAlignment(int)public void javax.swing.JLabel.setHorizontalAlignment(int)public void javax.swing.JLabel.setVerticalTextPosition(int)public void javax.swing.JLabel.setHorizontalTextPosition(int)public void javax.swing.JLabel.setIconTextGap(int)public void javax.swing.JLabel.setDisplayedMnemonicIndex(int)public void javax.swing.JLabel.setDisplayedMnemonic(int)public void javax.swing.JLabel.setDisplayedMnemonic(char)public void javax.swing.JLabel.setLabelFor(java.awt.Component)

javax.swing.JLabel

Page 10: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

public void javax.swing.JComponent.setEnabled(boolean)public void javax.swing.JComponent.setVisible(boolean)public void javax.swing.JComponent.setForeground(java.awt.Color)public void javax.swing.JComponent.setBackground(java.awt.Color)public void javax.swing.JComponent.setFont(java.awt.Font)public void javax.swing.JComponent.setNextFocusableComponent(java.awt.Component)public void javax.swing.JComponent.setRequestFocusEnabled(boolean)public void javax.swing.JComponent.setVerifyInputWhenFocusTarget(boolean)public void javax.swing.JComponent.setPreferredSize(java.awt.Dimension)public void javax.swing.JComponent.setMaximumSize(java.awt.Dimension)public void javax.swing.JComponent.setMinimumSize(java.awt.Dimension)public void javax.swing.JComponent.setBorder(javax.swing.border.Border)public void javax.swing.JComponent.setAlignmentY(float)public void javax.swing.JComponent.setAlignmentX(float)public void javax.swing.JComponent.setInputVerifier(javax.swing.InputVerifier)public void javax.swing.JComponent.setDebugGraphicsOptions(int)public final void javax.swing.JComponent.setActionMap(javax.swing.ActionMap)public static void javax.swing.JComponent.setDefaultLocale(java.util.Locale)public void javax.swing.JComponent.setToolTipText(java.lang.String)public void javax.swing.JComponent.setAutoscrolls(boolean)public void javax.swing.JComponent.setTransferHandler(javax.swing.TransferHandler)public void javax.swing.JComponent.setOpaque(boolean)public void javax.swing.JComponent.setDoubleBuffered(boolean)

javax.swing.JComponent

Page 11: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

public void java.awt.Container.setLayout(java.awt.LayoutManager)public void java.awt.Container.setFocusTraversalPolicy(java.awt.FocusTraversalPolicy)public void java.awt.Container.setFocusCycleRoot(boolean)

java.awt.Container

public void java.awt.Component.setName(java.lang.String)public void java.awt.Component.setSize(java.awt.Dimension)public synchronized void java.awt.Component.setDropTarget(java.awt.dnd.DropTarget)public void java.awt.Component.setLocale(java.util.Locale)public void java.awt.Component.setLocation(java.awt.Point)public void java.awt.Component.setBounds(java.awt.Rectangle)public void java.awt.Component.setCursor(java.awt.Cursor)public void java.awt.Component.setIgnoreRepaint(boolean)public void java.awt.Component.setFocusable(boolean)public void java.awt.Component.setFocusTraversalKeysEnabled(boolean)public void java.awt.Component.setComponentOrientation(java.awt.ComponentOrientation)

java.awt.Component

Page 12: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Introspectionpackage com.carlsbadcubes.codecamp;import java.lang.reflect.*;

public class Introspector { /** * Trys to instantiate a given class using its default constructor * then its sets its name using a setName(String name) method. * @param classname <code>String</code> - name of the class to be loaded and instantiated * @param name <code>String</code> - parameter to be used in a setName method * @return <code>Object</code> of the given class or null. */ public static Object createNamedInstance(String classname, String name) { Object obj = null; try { Class cls = Class.forName(classname); // shortcut would be to just call cls.newInstance(); Constructor ctor = cls.getConstructor(); // gets the default ctor if available. obj = ctor.newInstance(); // call with empty parameter array Method method = cls.getMethod("setName", String.class); method.invoke(obj, name ); } catch (ClassNotFoundException e) { // intent. empty } catch (NoSuchMethodException e) { // intent. empty } catch (InstantiationException e) { // intent. empty } catch (IllegalAccessException e) { // intent. empty } catch (InvocationTargetException e) { // intent. empty } return obj; }}

Page 13: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Introspectionpackage com.carlsbadcubes.codecamp;import java.lang.reflect.*;

public class Introspector {

public static Object createNamedInstance( String classname, String name ) { !Object obj = null; !try {

! ! ! Class cls = Class.forName( classname ); // shortcut would be to just call cls.newInstance();

Constructor ctor = cls.getConstructor(); // gets the default ctor obj = ctor.newInstance(); // call with empty parameter array

Method method = cls.getMethod( "setName", String.class ); method.invoke( obj, name ); ! ! ! } catch (Exception e) { // intent. empty !} !return obj; }}

Page 14: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Introspection TestCasepackage com.carlsbadcubes.codecamp;

import junit.framework.TestCase;import javax.swing.*;

public class IntrospectorTest extends TestCase {

public void testInstatiate() { ! ! Object obj = ! ! Introspector.createNamedInstance("javax.swing.JLabel", "myLabel"); ! ! TestCase.assertTrue( obj != null ); !TestCase.assertTrue( JLabel.class.equals(obj.getClass()) ); !TestCase.assertEquals( "myLabel", ((JLabel) obj).getName() );! }}

Page 15: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Alternative to code generation

Decouple GUI Definition from Code

Expressive and Compact

Maintainable and Independent

Declarative Programming for GUIs

Page 16: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

XUL - XAML - MXML

• Separating the GUI layout from the GUI logic (event-handlers) is not new - describing the UI in XML is methodology de jour.

• Xml User Interface Language is a markup language for describing user interfaces.

• XUL Engine (a.k.a XUL Motor) converts XML descriptors into a User Interface at Runtime.

• XUL dialects exist for almost any platform and for many programming languages.

Page 17: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Mozilla - http://www.mozilla.org Runs on Mac OS, Linux, Solaris, FreeBSD, Irix, BeOS, HPUX, OS/2, BSD, and more

Luxor - http://luxor-xul.sourceforge.net Xul toolkit includes web server, portal engine, template engine, scripting interpreter etc.

SwixML - http://www.swixml.org Tiny (less than 50k) XUL Motor in Java for creating Swing UIs for apps or applets

Xoetrope XUI -http://www.xoetrope.com/xuiXUL motor in Java for building AWT UIs running on Java 1.1.8 and up;

Thinlets - http://www.thinlet.com Tiny XUL Motor in Java (less than 40k); designed for applets or mobile devices; runs even on Java 1.1; no Swing support.

XU

L ENG

INES

Page 18: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Joshua Marinacci, Member of Sun’s Swing Team: “The net result of working with SwixML is delivering better-looking applications in less time, and that is always a good thing.”

Ben Galbraith, author of Professional JSP 2.0 and Professional Apache Tomcat: “SwixML is the most mature XUL/Swing offering.If you're looking for a way to define your Swing UI's in XML, SwixML is one of the best choices around.”

Rick Jelliffe, CTO of Topologi: “By moving to SwixML, we reduced source code size by 500k and improved maintainability and startup time.”

Kate Rhodes: “I think that SwixML is the easiest way to define a Swing layout, period.”

Hans Mueller, CTO for Sun's Desktop Division: ”When defining Java Swing GUIs declaratively, SwixML is the strongest example.”

Page 19: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

http://www.swixml.org/TS-7122.pdf

Page 20: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

• SwiXml, is a small GUI generating engine for Java applications and applets. Graphical User Interfaces are described in XML documents that are parsed at runtime and rendered into javax.swing objects.

Page 21: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Swixml, a different XUL Motorfocus is completely on javax.swing.

Programmers knowing Swing can immediately start writing descriptors. No additional XML dialect has to be learned: Class names translate into tags and method names into attributes.

fast - since no additional layers had to be added on top of the Swing objects.

small - despite the fact that the swixml.jar file is only about 50 Kbyte in size, almost all Swing objects and widgets are supported.

Page 22: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Hello World - XUL Descriptor

<?xml version="1.0" encoding="UTF-8"?><frame size="440,380" title="Hello SWIXML World">

<panel constraints="BorderLayout.NORTH"> <label font="ARIAL-BOLD-16" foreground="blue" text="Hello World!"/> </panel>

<panel constraints="BorderLayout.SOUTH"> <button text="Click Here" /> </panel>

</frame>

Inside Swixml

Page 23: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Inside SwixmlHello World - Java Code

public class Foo {

public Foo() throws Exception { new SwingEngine().render( "xul/gui.xml").setVisible( true ); }

public static void main( String[] args ) throws Exception { new Foo(); }}

Page 24: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Inside SwixmlSimple Editor - XUL Descriptor

<?xml version="1.0" encoding="UTF-8"?><frame size="440,380" title="Hello SWIXML World">

<panel constraints="BorderLayout.NORTH"> <label font="ARIAL-BOLD-16" foreground="green" text="Swixml Editor"/> </panel>

<scrollpane><editorpane id=”ep”/></scrollpane>

<panel constraints="BorderLayout.SOUTH"> <button text="Click Here" action=”show”/> </panel>

</frame>

Page 25: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Inside SwixmlSimple Editor - Java Code

public class Foo { private JEditorPane ep; public Action show = new AbstractAction() { public void actionPerformed( ActionEvent event ) { new SwingEngine().render( new StringReader( ep.getText() ) ).setVisible( true ); } }; public Foo() throws Exception { new SwingEngine( this ).render( "xul/gui.xml").setVisible( true ); } public static void main( String[] args ) throws Exception { new Foo(); }}

Page 26: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Inside the Swixml MotorSwixml introspects all the registered classes for their constructors and set-methods.In case a setter method's parameters can be constructed by converting a String, the setter gets registered and can be called through an xml attribute.

<label text="My blue label" color="blue"/>

works, because a JLabel's setText(String s) methods takes a String typed parameter and Swixml provides a ColorConverter, capable of converting a String into a java.awt.Color typed object.

There is also the initclass attribute, which is useful when the class that is represented by the tag name, needs to be instantiated by something other than the default-contructor.

<combobox initclass="com.xyz.ComboModel" />

instantiates a JComboBox class by using the constructor that takes a ComboBoxModel parameter: JComboBox(ComboBoxModel aModel)

Page 27: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Mapping private membersprivate void mapMembers( Object obj, Class cls ) { if (obj != null && cls != null && !Object.class.equals( cls )) { Field[] flds = cls.getDeclaredFields();

for (int i = 0; i < flds.length; i++) { Object widget = idmap.get( flds[i].getName() ); if ( widget != null && flds[i].getType().isAssignableFrom ( widget.getClass() ) && !Modifier.isTransient( flds[i].getModifiers() )) { try { boolean accessible = flds[i].isAccessible(); flds[i].setAccessible(true); flds[i].set(obj, widget); flds[i].setAccessible( accessible ); } catch ( .. ) { } } } mapMembers( obj, cls.getSuperclass() ); }}

Page 28: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

I've talked a lot about how declarative programming and especially UI definition takes up less lines of code. But there are hundreds of lines of parser code supporting the declarative UI definition, remember he two phases: Declaration and Interpretation?  I would rather see you think about where you can take advantage of declarative programming, like in areas where you want to abstract functionality to gain flexibility in maintenance or extensibility.

Don’t get me wrong ...

Page 29: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Q & A

Page 30: Declarative Programming, emphasizing UI Generation at Runtime

© 2003-2006 Carlsbad Cubes© 2009 wolfpaulus.com

Thanks for coming