The Source for Java Technology Collaboration
User: Password:



Evan Summers's Blog

December 2006 Archives


Gooey Beans Form

Posted by evanx on December 29, 2006 at 07:03 AM | Permalink | Comments (0)

Gooey Beans Form

We use an MVC architecture, with some simple "beans binding" from our form to our model. Our "model" is a POJO, as in the Presentation Model pattern. We explicitly declare our properties in a model info class as presented earlier in Gooey Beans Info.

In our controller we create "adapters" for the input components in our form, eg. JTextField, JFormattedTextField, JCheckBox and JComboBox. Our form might be created using Matisse, so we bind our adapters to our form's (private) input components using reflection.


Code Snippet

We implemented a model object in Gooey Beans Info, and a form in Group Layout Therapy. We now implement the controller as follows.

public class PersonInfoController implements ActionListener, QGooeyWorksheet {    
    ...
    PersonInfoForm form = new PersonInfoForm();
    PersonInfoModel model = new PersonInfoModel();
    PersonInfoModelInfo modelInfo = new PersonInfoModelInfo();
    
    QGooeyFormHelper<PersonInfoModel> gooey = 
            new QGooeyFormHelper(this, model);
    ...    
    QTextFieldAdapter lastName =
            gooey.createTextFieldAdapter(modelInfo.lastName);    
    QFormattedTextFieldAdapter dependents =
            gooey.createFormattedTextFieldAdapter(modelInfo.dependents);
    QCheckBoxAdapter confirmed =
            gooey.createCheckBoxAdapter(modelInfo.confirmed);
    QComboBoxAdapter title =
            gooey.createComboBoxAdapter(modelInfo.title);
    ...    
    public PersonInfoController() {
        gooey.setForm(form);
    }
    
    public void actionPerformed(ActionEvent event) {
        try {
            gooey.refreshModel();
            ... // process model
            gooey.refreshForm();
            gooey.publishInfo(Level.INFO, null);
        } catch (Exception e) {
            gooey.publishException(e, Level.WARNING, null);
        }
    }
    ...
}

where the component adapters are created with a bean property courtesy of our "model info" class. They enable beans binding to our POJO presentation model object. We provide methods to refresh our model from the form, and visa versa, as seen in the above actionPerformed() method.

Our input component adapters are connected to the components on our form using reflection, when we invoke setForm() in the above constructor. If this form is created using Netbeans, then those components are private. That's fine because we manipulate them in our controller via the adapters.


Demo

We continue with the same demo as in the prequel Gooey Beans Info.

Launch   (PersonInfo, 150k/500k, unsandboxed, Java6)




Hyper Beans 1: Hyper Style

Posted by evanx on December 19, 2006 at 03:21 AM | Permalink | Comments (1)

We wanna style our documents and reports using neutral Java objects, to generate output artifacts eg. HTML with CSS, and/or other formats, eg. PDF and Excel (for reports). We model our style objects after CSS, eg. font-family, font-weight, text-decoration, et al.


Code Snippet

We implement style objects for generating this series of articles, and also Gooey Beans, using quitehyper.

public class GooeyBeansStyleManager extends QStyleManager {
    QStyle javaStyle = createStyle("javaStyle");
    QStyle paragraphStyle = createStyle("paragraphStyle");
    QStyle sectionStyle = createStyle("sectionStyle");
    QStyle subsectionStyle = createStyle("subsectionStyle");
    ...
    List<QFontFamily> courier = Arrays.asList(newCourierFontFamily, 
            courierFontFamily, monospacedFontFamily);

    List<QFontFamily> verdana = Arrays.asList(verdanaFontFamily, 
            helveticaFontFamily, arialFontFamily, sansserifFontFamily);
    
    public GooeyArticleStyleManager() {
        javaStyle.setFontFamily(courier);
        javaStyle.setFontSize(11);
        javaStyle.setBorder(dashedLine, 1);
        javaStyle.setBorderColor(lightgrayColor);
        javaStyle.setPadding(4, leftLocation);
        javaStyle.setWidth(800);
        javaStyle.setBackgroundColor(0xf4f4f4);
        paragraphStyle.setFontFamily(verdana);
        paragraphStyle.setFontSize(10);
        sectionStyle.setFontFamily(verdana);
        sectionStyle.setFontWeight(boldFontWeight);
        sectionStyle.setFontStyle(italicFontStyle);
        ...
    }
    ...
}

where we statically import style enums and constants, eg. lightgrayColor, dashedLine, boldFontWeight, et al.




Gooey Formatter

Posted by evanx on December 14, 2006 at 02:18 AM | Permalink | Comments (4)

We implement a singleton for formatting objects into strings, where custom formatters ie. for specific types, are registered with the singleton.


Code Snippet

Our singleton is implemented as follows.

public class QDefaultFormatter implements QFormatter {
    public Map<Class, QFormatter> formatterMap = new HashMap();
    ...
    public void register(Class type, QFormatter formatter) {
        formatterMap.put(type, formatter);
    }
    
    public void register(QLabelMapFormatter formatter) {
        QResourceMap resourceMap = new QResourceMap(formatter.getType());
        resourceMap.configureEnumLabelMap(formatter.getType(), 
            formatter.getLabelMap());
        formatterMap.put(formatter.getType(), formatter);
    }
    ...
    public String format(Object object) {
        if (object == null) return "";
        ...
        QFormatter formatter = formatterMap.get(object.getClass());
        if (formatter != null) return formatter.format(object);
        return object.toString();
    }
    ...
}

where formatterMap is our registry map eg. for QLabelMapFormatter instances, which map enum values to labels from our resource bundle.




Chris Oliver's JApplication for F3 Demos

Posted by evanx on December 10, 2006 at 12:53 PM | Permalink | Comments (0)

In Poor man's Multi-VM, Chris Oliver discusses his JApplication class, which he uses for his awesome F3 demos.

f3demo.png

Let's take a walk through his JApplication code to see how he achieves this feat...



Gooey Beans Info

Posted by evanx on December 07, 2006 at 08:37 AM | Permalink | Comments (0)

Let's get us some simplistic "beans binding" to support the Presentation Model pattern. We explicitly declare our properties so as to enjoy IDE auto-completion and refactoring capabilities. "Wa wa wee wa!" Cos string references are fragile with respect to renaming getters and setters, and so we avoid them, like whatsit, the plague ;)


Code Snippet

We implement a POJO Presentation Model object as follows.

public class PersonModel {    
    private String firstNames;
    private String lastName;
    private String phone;
    private String email;
    private Date birthDate;
    private BigInteger idNumber;
    private BigDecimal creditScore;
    private Integer dependents;
    private PersonTitle title;
    private PersonGender gender;
    private PersonMaritalStatus maritalStatus;
    private Boolean confirmed;
    ...    
    @IntegerRangeValidator(minimum = 0, maximum = 9, inclusive = true)
    public void setDependents(Integer dependents) {
        this.dependents = dependents;
    }
    ...
}

where we have illustrated a validation annotation. Alternatively we specify the um, properties' properties, including validators, in an explicit bean info class, as follows. This is sans magic, quite trivial and quite programmable. "It's nice, I like. High five!"

public class PersonModelInfo extends QBeanInfo<PersonModel> {
    final QProperty firstNames = createProperty("firstNames");
    final QProperty lastName = createProperty("lastName");
    final QProperty phone = createProperty("phone");
    final QProperty email = createProperty("email");
    final QProperty birthDate = createProperty("birthDate");
    final QProperty idNumber = createProperty("idNumber");
    final QProperty creditScore = createProperty("creditScore");
    final QProperty dependents = createProperty("dependents");
    final QProperty title = createProperty("title");
    final QProperty gender = createProperty("gender");
    final QProperty maritalStatus = createProperty("maritalStatus");
    final QProperty confirmed = createProperty("confirmed");
    
    public PersonModelInfo() {
        super(PersonModel.class);
        birthDate.setFormatPattern("yyyy-MM-dd");        
        birthDate.setPropertyValueType(dateType);
        birthDate.addValidator(new QFutureDateValidator(false));
        email.setPropertyValueType(emailType);
        dependents.addValidator(new QIntegerRangeValidator(0, 9, false));
        title.setPropertyValueType(enumType);
        gender.setPropertyValueType(enumType);
        maritalStatus.setPropertyValueType(enumType);
        confirmed.setPropertyValueType(booleanType);
    }   
}

We use the above info class to refer to our properties in an explicit, refactorable fashion. When we refactor our bean ie. rename properties (ie. their getter/setter methods) then we need to change the property name here, and we're good to go. Cos they're a pair like Mutt and Jeff.

QProperty stores additional information besides wrapping the underlying PropertyDescriptor, eg. formatPattern and propertyValueType relate to formatting, and also there a list of validators.


Demo

Launch   (PersonInfo, 150k/500k, unsandboxed, Java6)

You can refresh the "BeanInfo" tab (and also the "Console" tab) to see that the values entered into our form are written to our Presentation Model.

where use formatPattern to override the default formatting for that propertyValueType (eg. date, timestamp, currency) and propertyType (eg. Date, Integer et al).




Enhanced DTs with CGLIB

Posted by evanx on December 05, 2006 at 05:03 AM | Permalink | Comments (9)

We try some magic tricks to avoid boilerplate EDT code. First we use dynamic proxies. This makes the code is more difficult to navigate using our IDE. Nevertheless it is potentially useful for general utility classes whose methods should all run in the EDT, eg. to enable EDT-agnostic programming in background threads.

Finally, we investigate using byte code manipulation using CGLib. We intercept invocations, inspect for annotations, and then run the method in the background or in the EDT, according to the annotation. This seems to be a better option than dynamic proxies, since we don't need to introduce an interface, and navigation in our IDE is unaffected.



Code sample

We continue with our fantasy SupportAssistantGui application from the Boiler Room prequel.

public class SupportAssistantGui implements ActionListener {
    ...
    JButton checkForNewMessagesButton = new JButton("Check for new messages");
    ...
    @InBackgroundAnnotation()
    protected void checkForNewMessages() { 
        swingHelper.setEnabled(checkForNewMessagesButton, false);
        try {
            ...
            updateGuiWithNewMessages((CheckForNewMessagesResponse) response);
        } catch (IOException e) {
            swingHelper.showExceptionDialog(e);
        } finally {
            swingHelper.setEnabled(checkForNewMessagesButton, true);
        }
    }
    
    @InEdtAnnotation()
    protected void updateGuiWithNewMessages(CheckForNewMessagesResponse response) {
        ...
    }
    ...
}

where the method annotations determine whether that method is invoked in the EDT using invokeAndWait() or in a background SwingWorker thread, courtesy of CGLIB's interceptor.


Demo

The following screenshot shows the method interceptor invocating methods in succession, switching into a background thread for a long task (so as not to block to the EDT), and then back into the EDT, thanks to the annotations on the methods been invoked, ie. to update the GUI intermittently during the series of long tasks.

Launch (SupportAssistant, 200k/650k, unsandboxed, Java5)

where the first true or false indicates the EDT.






Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds