Declarative Programming, emphasizing UI Generation at Runtime


Published on

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.

Published in: Technology
  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Declarative Programming, emphasizing UI Generation at Runtime

  1. 1. Declarative Programming :UI-Generation at Runtime with SwixML Wolf Paulus
  2. 2. 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© 2003-2006 Carlsbad Cubes© 2009
  3. 3. Wikipedia: 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.© 2003-2006 Carlsbad Cubes© 2009
  4. 4. Writing programs in a declarative style in an imperative programming language usually requires lots of runtime information.* *for Java, this means Reflection & Introspection© 2003-2006 Carlsbad Cubes© 2009
  5. 5. Wikipedia: 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.© 2003-2006 Carlsbad Cubes© 2009
  6. 6. Reflection in Java Java 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.© 2003-2006 Carlsbad Cubes© 2009
  7. 7. Reflection 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; } }© 2003-2006 Carlsbad Cubes© 2009
  8. 8. Reflection TestCase 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); } }© 2003-2006 Carlsbad Cubes© 2009
  9. 9. Methods found: javax.swing.JLabel 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)© 2003-2006 Carlsbad Cubes© 2009
  10. 10. javax.swing.JComponent 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)© 2003-2006 Carlsbad Cubes© 2009
  11. 11. java.awt.Container 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.Component 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)© 2003-2006 Carlsbad Cubes© 2009
  12. 12. Introspection package 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; } }© 2003-2006 Carlsbad Cubes© 2009
  13. 13. Introspection package 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; } }© 2003-2006 Carlsbad Cubes© 2009
  14. 14. Introspection TestCase package 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() ); ! } }© 2003-2006 Carlsbad Cubes© 2009
  15. 15. Declarative Programming for GUIs Alternative to code generation Decouple GUI Definition from Code Expressive and Compact Maintainable and Independent© 2003-2006 Carlsbad Cubes© 2009
  16. 16. 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.© 2003-2006 Carlsbad Cubes© 2009
  17. 17. XUL ENGINES Mozilla - Runs on Mac OS, Linux, Solaris, FreeBSD, Irix, BeOS, HPUX, OS/2, BSD, and more Luxor - Xul toolkit includes web server, portal engine, template engine, scripting interpreter etc. SwixML - Tiny (less than 50k) XUL Motor in Java for creating Swing UIs for apps or applets Xoetrope XUI - XUL motor in Java for building AWT UIs running on Java 1.1.8 and up; Thinlets - Tiny XUL Motor in Java (less than 40k); designed for applets or mobile devices; runs even on Java 1.1; no Swing support.© 2003-2006 Carlsbad Cubes© 2009
  18. 18. 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 youre looking for a way to define your Swing UIs 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 Suns Desktop Division: ”When defining Java Swing GUIs declaratively, SwixML is the strongest example.”© 2003-2006 Carlsbad Cubes© 2009
  19. 19.© 2003-2006 Carlsbad Cubes© 2009
  20. 20. • 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.© 2003-2006 Carlsbad Cubes© 2009
  21. 21. Swixml, a different XUL Motor focus 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.© 2003-2006 Carlsbad Cubes© 2009
  22. 22. Inside Swixml 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>© 2003-2006 Carlsbad Cubes© 2009
  23. 23. Inside Swixml Hello 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(); } }© 2003-2006 Carlsbad Cubes© 2009
  24. 24. Inside Swixml Simple 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>© 2003-2006 Carlsbad Cubes© 2009
  25. 25. Inside Swixml Simple 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(); } }© 2003-2006 Carlsbad Cubes© 2009
  26. 26. Inside the Swixml Motor Swixml introspects all the registered classes for their constructors and set-methods. In case a setter methods 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 JLabels 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="" /> instantiates a JComboBox class by using the constructor that takes a ComboBoxModel parameter: JComboBox(ComboBoxModel aModel)© 2003-2006 Carlsbad Cubes© 2009
  27. 27. Mapping private members private 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() ); } }© 2003-2006 Carlsbad Cubes© 2009
  28. 28. Don’t get me wrong ... Ive 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.© 2003-2006 Carlsbad Cubes© 2009
  29. 29. Q&A© 2003-2006 Carlsbad Cubes© 2009
  30. 30. Thanks for coming© 2003-2006 Carlsbad Cubes© 2009