Fabric 2.0.1
Design
Fabric is based on JavaBeans XML aka “Long-Term Persistence for JavaBeans”. The serialization format created by Sun to store Java Bean data in XML. Instead of using a custom parser and reading the elements into a data structure, I decided to use XSLT transformation and XMLDecoder to create a runtime object. Some may say this is insane and I sort of agree. It is nuts and I know of no other implementation like it. I did it because I wanted to learn XSLT and because I believe automated derivative data is the future, rather than huge parsers with plenty of vendor lock in. Just look at web browsers and the eternal bitch fest that is CSS layout. Internet Explorer still lags behind everyone else and because of this no one bothers to create standard compliant code. Validate Google's HTML if you do not believe me.
Ironically some people probably ignore Fabric because they are worried about being locked into a technology created by a tiny company that might be gone tomorrow. Fabric has in fact been designed from the ground up to overcome this. This is how it works.
This is the default view – home.jfc:
<jfc>
<component class="com.teppefall.park.runtime.ParkDesktop"/>
</jfc>
This is transformed into this:
<?xml version="1.0" encoding="utf-8"?>
<java version="1.4.2" class="java.beans.XMLDecoder">
<!--
This file was automatically generated by Teppefall Fabric.
http://www.teppefall.com
-->
<object id="self" class="com.teppefall.park.runtime.jfc.JFCPanel">
<object idref="self">
<void property="title">
<string/>
</void>
</object>
<void method="add">
<object class="com.teppefall.park.runtime.ParkDesktop"/>
</void>
</object>
</java>
JFCPanel extends AssemblyAdapter which implements Assembly. All these classes are available in the source folder.
You can access this view either by using the entire Fabric SDK (now you are dependent on me):
add(new Park(“home.jfc”));
Or just the runtime part (now you have access to all the source code):
Assembly assembly = Importer.decode(getClass(), “home.xml”); // this is the transformed data
Jpanel root = assembly.getPanel();
JmenuBar menu = assembly.getMenuBar();
JpopupMenu popup = assembly.getPopupMenu();
If you follow a simple pattern – MyPanel.java + MyPanel.xml – you can also do this.
Assembly assembly = Importer.decode(getClass());
There is nothing magical about the importer.
public static Assembly decode(Class owner) {
return decode(owner, Console.self(owner) + ".xml");
}
public static Assembly decode(Class owner, String resource) {
InputStream xml = owner.getResourceAsStream(resource);
if(xml == null) {
Console.warn(Importer.class, "Resource not found \"" + resource + "\"");
}
XMLDecoder decoder = new XMLDecoder(xml);
Assembly assembly = (Assembly)decoder.readObject();
return assembly;
}
Fabric is a prototype tool
But it can be used directly in an application. Since there is no standardized data and event binding available today this technology should only be used in small web applications. Fabric JFC (the format, not the application) is designed as a lightweight alternative to Adobe Apollo, Microsoft XAML and Mozilla XUL. Some seriously suggest to people that they should use the Eclipse or NetBeans application framework to create Java web applications. This is the equivalent of buying an 18 wheeler for a one mile paper route.
Yeah, but this is a toy right ?
Fabric has been really brutal to developers up to now. Doing recursive programming in XSLT is hard and very few people have probably even attempted to create their own transformers. Because of this I have spent a lot of time creating a powerful syntax that I have simply named JFC after Java Foundation Classes. It is simple to understand and very powerful.
<jfc title="Java Hut">
<popupmenu>
<menuitem text="PAL"/>
<menuitem text="NTSC"/>
<menuitem text="320x240"/>
<menuitem text="640x480"/>
<menuitem text="800x600"/>
<menuitem text="Custom"/>
<separator/>
<menuitem text="Frames per second"/>
</popupmenu>
<layout class="java.awt.BorderLayout">
<layout class="java.awt.BorderLayout" constraint="Center">
<component class="com.teppefall.ds.render2d.Darkstar" name="renderer" constraint="Center"/>
<gridlayout columns="3" rows="1" constraint="South">
<component class="javax.swing.JPanel">
</component>
<layout class="java.awt.FlowLayout">
<component class="javax.swing.JButton" name="capture">
<property name="text" value="Capture"/>
</component>
</layout>
<layout class="java.awt.FlowLayout">
<property name="alignment" value="2" type="int"/>
<component class="javax.swing.JLabel" name="effects">
<property name="text" value="Effects"/>
</component>
<component class="javax.swing.JToggleButton" name="one">
<property name="text" value="1"/>
</component>
<component class="javax.swing.JToggleButton" name="two">
<property name="text" value="2"/>
</component>
</layout>
</gridlayout>
</layout>
<component class="javax.swing.JScrollPane" constraint="South">
<property name="verticalScrollBarPolicy" value="21" type="int"/>
<property name="horizontalScrollBarPolicy" value="31" type="int"/>
<property name="viewportView" type="Component">
<component class="javax.swing.JList" name="images">
<property name="cellRenderer" type="Object" value="com.teppefall.park.runtime.MyImageItemRenderer"/>
<property name="selectionMode" value="1" type="int"/>
<property name="layoutOrientation" value="2" type="int"/>
<property name="visibleRowCount" value="1" type="int"/>
<property name="fixedCellWidth" value="80" type="int"/>
<property name="fixedCellHeight" value="80" type="int"/>
<property name="selectionMode" value="2" type="int"/>
<property name="listData" type="Vector">
<vector>
<item>Hello World !</item><item>Hello World !</item>
</vector>
</property>
</component>
</property>
</component>
</layout>
</jfc>
Fabric JFC
Copyright 2007 Teppefall
<jfc
title=””
height=””
width=””
>
<component, layout, gridlayout
name=””
class=””
action=””
constraint=””
text=””
enabled=””
mnemonic=””
icon=””
focus=””
>
<gridlayout
rows=””
columns=””
>
<property
name=””
value=””
type=”boolean|byte|char|short|double|float|int|long|Hashtable|Vector|Component|Object|Color|Dimension|Rectangle|Point|Icon|Tree”
>
<action,
name=””
class=””
>
<menubar, popupmmenu>
<menu, menuitem
name=””
action=””
text=””
enabled=””
mnemonic=””
icon=””
>
<menuitem
type=”radiobutton|checkbox”
>
<separator>
<vector>
<hashtable>
<item
name=””
value=””
>
package com.teppefall.park.runtime;
/**
* (c) Teppefall
* http://teppefall.com
*
* Assembly.java
* Mar 3, 2004
*/
import java.io.Serializable;
import java.util.Hashtable;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.JMenuBar;
import javax.swing.JPopupMenu;
import javax.swing.JPanel;
public interface Assembly extends Serializable {
void parkInitialize();
void parkShutdown();
void parkInstruction(String instruction);
void parkBinder(String listener);
void parkParameter(String data);
void add(JComponent component);
JPanel getPanel();
JMenuBar getMenuBar();
JPopupMenu getPopupMenu();
ActionListener getActionListener();
String getIcon();
String getTitle();
String getStatus();
Dimension getSize();
void setIcon(String icon);
void setTitle(String title);
void setUsingStatus(boolean usingStatus);
boolean isUsingStatus();
void setAttributes(Hashtable attributes);
void setAttribute(String name, Object value);
Object getAttribute(String name);
Hashtable getAttributes();
}
Further reading
http://java.sun.com/products/jfc/tsc/articles/persistence/
http://java.sun.com/products/jfc/tsc/articles/persistence2/
http://java.sun.com/products/jfc/tsc/articles/persistence3/
http://java.sun.com/products/jfc/tsc/articles/persistence3/javabeans.dtd
Fabric 2.01
Check out Jan Erik Paulsen on Twitter.