You are on page 1of 267

Building Software Applications

with

JMATTER

Building Software Applications


with

JMATTER

Eitan Suez

March 2009

2009 JMatterSoft LLC. All rights reserved.

On the Cover
The sport of windsurng conveys qualities of speed and agility, qualities that I believe are also born by the software framework JMatter in the eld of software development. A sincere thanks goes to the StarBoard company, to the rider, and to the photographer, for the permission to use the photograph on the cover of this book. Photo Details:

Board: 2008 StarBoard Evo XTV Rider: Kevin Pritchard Photographer: Tiesda You

This book was typeset and produced using Open Source software. LYX was used for typesetting and layout.

Suez, Eitan Building Software Applications with JMatter Bibliography. ISBN: This publication is not yet registered with an ISBN Agency

Contents
I
1

Introduction
Overview 1.1 1.2 1.3 How? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Seeing is believing . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1
3 4 6 7 9 9 10 11 11 12

Software Installation 2.1 2.2 Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

A Short Tour 3.1 3.2 Launching ContactMgr . . . . . . . . . . . . . . . . . . . . . . . . . . The Tour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

II
4

Tutorial Applications
A Zero-Code Contact Manager 4.1 4.2 4.3 4.4 4.5 4.6 4.7 Creating a New Project . . . . . . . . . . . . . . . . . . . . . . . . . . The Schema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The Class Bar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Running Your Contact Manager . . . . . . . . . . . . . . . . . . . . . Custom Views Revisited . . . . . . . . . . . . . . . . . . . . . . . . . Project Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

29
31 31 32 33 34 35 36 38

MyTunes in under 200 Lines 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 Creating the Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . Setup your Project in an IDE . . . . . . . . . . . . . . . . . . . . . . . Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The Album Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The Genre Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The Song Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Running our Application . . . . . . . . . . . . . . . . . . . . . . . . . Back To the Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

39 39 39 40 42 43 44 46 49 51 53 55 57 59 61 63 63 64 65 72 74 80 82 86 89 89 90 93 97

5.10 Behaviour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.11 Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.12 Importing Songs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.13 Not Completely Finished . . . . . . . . . . . . . . . . . . . . . . . . . 5.14 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 A Conference Manager 6.1 6.2 6.3 6.4 6.5 6.6 6.7 6.8 7 Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Setting up the Project . . . . . . . . . . . . . . . . . . . . . . . . . . . The Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Enhancements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Calendaring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Inheritance-Based Polymorphism . . . . . . . . . . . . . . . . . . . . Interface-Based Polymorphism . . . . . . . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Issue Manager 7.1 7.2 7.3 7.4 Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Modeling Issues Lifecycle . . . . . . . . . . . . . . . . . . . . . . . . Per-State Icons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

vi

7.5 7.6 7.7 7.8 7.9

Additional Metadata . . . . . . . . . . . . . . . . . . . . . . . . . . . A Few Loose Ends . . . . . . . . . . . . . . . . . . . . . . . . . . . .

98 99

Issue Categories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 The Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104

III
8

Framework Reference
Dichotomy of a Model Object 8.1 8.2 8.3 8.4 8.5 8.6 8.7

105
107

Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 Fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 Metadata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 Per-Field Metadata . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 Per-Command Metadata . . . . . . . . . . . . . . . . . . . . . . . . . 127 Persistence Lifecycle and AppEvents . . . . . . . . . . . . . . . . . . 129 131 137

Validation

10 Authentication & Authorization

10.1 Autologin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 10.2 Authorization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 10.3 List Filtering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 11 Search 143

11.1 Filtering Listings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143 11.2 The Find Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 11.3 Smart Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 11.4 Search in Associations . . . . . . . . . . . . . . . . . . . . . . . . . . 144 11.5 Polymorphic queries . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 11.6 Code Hints for Search . . . . . . . . . . . . . . . . . . . . . . . . . . 145

vii

12 Wizards, CSV Export, and PDFs

147

12.1 Subclassing Person . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 12.2 Writing the Wizard . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 12.3 Running the Application . . . . . . . . . . . . . . . . . . . . . . . . . 151 12.4 CSV Export . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 12.5 PDFs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155 12.6 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 13 Calendars and Maps 163

13.1 Calendars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 13.2 Maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 14 Customized Views and Editors 171

14.1 Complex, or Composite Views . . . . . . . . . . . . . . . . . . . . . 171 14.2 A Custom View for Sympster Sessions . . . . . . . . . . . . . . . . . 176 14.3 The Self demo application . . . . . . . . . . . . . . . . . . . . . . . . 177 14.4 Customizing Layout . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 14.5 Atomic Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 15 Localization and Internationalization 183

15.1 States . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 15.2 Generic UI Localization . . . . . . . . . . . . . . . . . . . . . . . . . 187 15.3 Right-To-Left . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 15.4 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 16 Child Projects 191

16.1 Creating Child Projects . . . . . . . . . . . . . . . . . . . . . . . . . . 191 16.2 Directory Structure and Files . . . . . . . . . . . . . . . . . . . . . . 192 16.3 Build File Targets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 17 Styling the UI with CSS 197

17.1 JMatters CSS Engine . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 17.2 The JMatter Stylesheet . . . . . . . . . . . . . . . . . . . . . . . . . . 201 17.3 Using CSS4Swing in Standalone Swing Applications . . . . . . . . 205 17.4 Future Plans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207

viii

18 Deploying your Application

209

18.1 JMatter Applications Architecture . . . . . . . . . . . . . . . . . . . 209 18.2 Java Web Start . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 18.3 Deploying ContactMgr . . . . . . . . . . . . . . . . . . . . . . . . . . 210 18.4 Caveats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212 18.5 Security Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212 18.6 More About JWS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 18.7 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 19 Deployment, Take II: The Application Browser 215

19.1 How it works, by example . . . . . . . . . . . . . . . . . . . . . . . . 216 19.2 Dealing with dependencies . . . . . . . . . . . . . . . . . . . . . . . 218 19.3 Looking Ahead . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 20 Tooling 219

20.1 Reverse Engineering an Existing Schema . . . . . . . . . . . . . . . 219 20.2 IDEA Productivity Templates . . . . . . . . . . . . . . . . . . . . . . 220 20.3 Ultraviolet and UMLC . . . . . . . . . . . . . . . . . . . . . . . . . . 221 21 The Power User 223

21.1 Visual Command Interface . . . . . . . . . . . . . . . . . . . . . . . . 223 21.2 Associations Made Easy . . . . . . . . . . . . . . . . . . . . . . . . . 226 21.3 Paging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 21.4 Expos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229 21.5 Navigation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230 21.6 Copy and Paste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 21.7 The Restore Desktop Feature . . . . . . . . . . . . . . . . . . . . . . . 236 22 Summary 237

22.1 Looking Forward . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 A Keyboard Shortcuts 241

ix

B Database Setup

243

B.1 Conguring your own database . . . . . . . . . . . . . . . . . . . . . 243 C Working from the Subversion Repository 247

C.1 Checking out the code . . . . . . . . . . . . . . . . . . . . . . . . . . 247 C.2 Directory Structure, Compiling, Running demo applications . . . . 248 D Online Articles on JMatter E FAQ F Contributing to this project G A Desktop within a Desktop? 249 251 253 255

G.1 Dreaming of a Better Virtual World . . . . . . . . . . . . . . . . . . . 255 G.2 Collapsing the desktops . . . . . . . . . . . . . . . . . . . . . . . . . 256

Part I

Introduction

Chapter 1

Overview
Welcome! JMatter is a software application framework. It is designed specically for building business software applications for work groups. Examples might include accounting software, software for legal rms, medical software for small practices, software for auto mechanic shops, software for small software development shops, and more1 . The principal advantage of developing a business software application with JMatter is a dramatic reduction in development time. It is not an exaggeration to say that the difference in development time compared to traditional methods is roughly a factor of 10! That is, one order of magnitude. Take for example, the Issue Manager demo application described in chapter 7 on page 89. Surprisingly, even though this application is presented as a demo, it nevertheless is a complete and working Issue Management software application that can be used for day-to-day tracking and management of software issues. The authors of the JMatter framework used this application for some time for tracking bugs and enhancements to JMatter. This Issue Manager software application was implemented by a single developer in roughly four hours. Contrast this to comparable systems such as Bugzilla http://www.bugzilla.org/, JIRA http://jira.atlassian.com/, and trac http://www. edgewall.com/trac which, albeit may have a few more features, have taken somewhere in the neighborhood of one or more man-years to develop. Equally important is the number of lines of code necessary to implement such a software application. Using JMatter, the entire Issue Manager application consists of 300 lines of code at the moment, including white-space (blank lines), strewn across three Java classes. Compare that to approximately 13,000 lines of python code2 in trac spread among roughly 170 les (I dont mean to pick on trac, which
1 By 2 Measured

small we mean organizations with up to 100 users. using wc -l on python-2.4/site-packages/trac

CHAPTER 1. OVERVIEW

is a very nice issue management application; I just happen to have a copy installed on my computer). This brings up another point: the JMatter framework is written in the Java programming language. This means that your software applications can run in a heterogeneous IT environment, on a variety of operation systems including the plethora of GNU/Linux OSs, Solaris, MacOSX, and the various avors of Windows3 . Software development professionals or teams that use the JMatter framework therefore enjoy a signicant competitive advantage over other software development rms that employ more traditional methods of developing software. At this point you should be asking yourself some very important questions: Can this really be? How? Is it really possible to shave 90% or more of an applications code? To deliver software in so much less time?

1.1

How?

Lets take a moment to reect on how software applications are constructed. The reason for developers high productivity with JMatter is simple, but needs some elaboration. All applications have a great deal in common. Examples include, a login dialog, the need for authentication (controlling who can and cannot access the system), etc. . . Believe it or not though, most developers build these same features over and over again each time they work on a new application. With JMatter, things are different. JMatter provides those common things so that developers dont have to start from scratch each time. You wont nd a single line of authentication code in a software application constructed using JMatter; thats all tucked away in the framework. If it were all about login dialogs, JMatter wouldnt buy you very much. What sets JMatter apart is the fact that there are plenty more things that developers write from scratch for each new application; things that are common to them all. Here are some of them: A User Interface A window, the ability to create new users, change their passwords, the ability to create a new contact, edit the address for an existing contact, delete an old contact. The basic need to Create, view (Read), Update, and Delete information is termed CRUD. Its true that for each type of thing youre creating (a User, a Business, a Person, etc..), the forms will vary because each
3 This

includes both the client and server portions of the solution.

1.1. HOW?

thing contains a different set of elds. However, the mechanism is the same. Developing a user interface from scratch is a very tedious job. Estimates state that approximately 60% of the time spent developing an application is spent constructing its user interface; Query Services The basic need to lter information. For example, the ability to ask the question: Display all Persons who live in a certain city; Validation The ability to specify which elds are required, which are optional, what constitutes a valid phone number, date, etc.. when performing form entry tasks; Persistence The ability to save information, associations between objects, and more; Calendaring Many varying applications have the basic need to deal with time: scheduling activities, looking up and manipulating events on a calendar, etc..; Basic knowledge of simple types of information So many business applications need to process dates, phone numbers, social security numbers, images, passwords, percentages, currencies, names, addresses, notes, and more. Yet here again, you will discover software developers spending time [re-]writing code to parse, validate, and format such basic information as a phone number; Logging Tracking activity in the system, the fact that someone logged in at a specic time, that they deleted an entry, etc..; Authorization Specifying who is allowed to perform what actions in a system; Reporting The ability to produce printable (PDF) reports from the information that an application manages; Wizards A component of user interface construction, often used to break down complex tasks into a series of steps.

CHAPTER 1. OVERVIEW

Most of this work has nothing to do with the specic problem domain: theyre generic services that all applications should have, but that [unfortunately] are constructed from scratch each time4 . I like to say that these services are orthogonal to the problem domain. We can see now why software projects are often delivered late and over budget: developers have a great deal of work to perform when building even the most basic of business applications. Before they have a chance to begin working on the problem domain, theyre faced with building an entire software infrastructure. The end-result is often a combination of: a poorly-constructed general foundation for an application that is tightly and needlessly coupled to the problem domain a solution that compromises the end-users feature requirements to stay within time and cost constraints JMatter promises to empower developers to work on the task at hand without having to build a foundation. At the time of this writing, JMatter provides most of the listed orthogonal services. The implementation of a built-in, generic Authorization system has recently been completed. The predominant architecture for software applications today is known as ModelView-Controller. You can think of JMatter as providing a complete and generic View-Controller implementation, leaving developers to work on the Model. So to sum things up for now, the JMatter frameworks goal is to provide all of these orthogonal services, out of the box, so to speak without requiring any extra effort on the part of the application developer.

1.2

Architecture

Before diving into JMatter, lets briey discuss what types of applications JMatter produces. What is their architecture? What language are these applications written in? What operating systems can they be deployed onto, etc.. The JMatter framework and JMatter-based applications are written in the Java programming language. The implication is primarily that these applications can run on a number of target operating systems, from windows computers, to macs, to the variety of GNU/Linux operating systems out there, as well as other avors of Unix such as Solaris and BSD. JMatter applications by design produce software applications where all data is persisted to a back-end relational database. Databases provide powerful query
4 or

not! Its rare to nd a complete application that provides all of these services.

1.3. SEEING IS BELIEVING

capabilities that are the foundation for many business needs. The JMatter framework uses the Hibernate 5 framework to communicate to back-end databases. This affords the framework database independence. JMatter applications are compatible with a number of back-end database systems. It has been tested with PostgresQL, MySQL, and Oracle databases, as well as newer and more lightweight database systems such as H2 and hsqldb. These back-end databases are available for a large number of operating systems. On the client side, JMatter leverages the Java Swing Toolkit to produce rich client applications. These user interfaces are platform-independent. The overall architecture has two tiers: the client application communicates over the network to the back-end database. Multiple clients are installed on multiple workstations, and multiple users can access the system concurrently. This type of architecture is suitable for local area network deployment, or the wide area network, over a VPN 6 connection. A number of database systems today can be congured for communications over SSL, making it possible to deploy such solutions over a wide area network without requiring a VPN solution. To automate the task of installing clients on multiple workstations, and of keeping these installations up to date, JMatter leverages Java WebStart. Chapter 18 is devoted to the specics of deploying JMatter applications using this technology. At the time of writing, JMatter already has early (alpha quality) implementations of the infrastructure necessary to deploy the very same applications over the world wide web, using a three-tier architecture. This will give users the ability to deploy their applications either to the web or using Swing, or both (a mixed population of users).

1.3

Seeing is believing

Heres what lays ahead in the upcoming chapters: well walk through installing JMatter on your system. Then well begin by studying one of the JMatter demo applications: the Contact Manager (Chapter 3). By the end of that chapter, youll have a good feel for JMatter applications, what they look like, how to interact with them. Part 2 of this manual focuses on teaching you how to write JMatter applications by example. Well start by building our own contact management software. In each succeeding chapter well build a new application, each one building upon the notions learned in the preceding chapters. All of the tutorial applications documented here are included in the JMatter framework distribution.
5 see http://hibernate.org/ 6 Virtual Private Network

CHAPTER 1. OVERVIEW

The third part of this manual aims to provide a complete reference of the JMatter framework. Thats where youll nd detailed information on the various features of the framework, options, and conventions to adhere to. Bold claims have been made in this introduction. Coming from the authors of the JMatter framework, these should be regarded with a healthy dose of skepticism. It is for you, the reader, to judge the cost-benet proposition of the JMatter framework for delivering software applications. This document arms you with the information necessary to make that judgment.

Chapter 2

Software Installation
In this chapter well focus on the steps to install JMatter on your system. Lets begin with the prerequisites.

2.1
2.1.1

Prerequisites
Java Standard Edition, version 5 (JSE 5) or later

JMatter is a Java-based framework and thus requires Java Standard Edition from Sun Microsystems. Download a copy from http://java.sun.com.

2.1.2

Ant

Ant is a Java build tool which JMatter heavily relies upon. You can obtain ant from http://ant.apache.org/. After installing ant, verify that it is properly installed by typing:
ant -version

at the command prompt. Here is what the output of the above command looks like on my screen:
Apache Ant version 1.6.5 compiled on July 5 2006

10

CHAPTER 2. SOFTWARE INSTALLATION

2.2

Installation

Visit the JMatter web site at http://jmatter.org/ and click on the Download link in the sidebar. You have the option of downloading the software either as a zip le or as a tgz archive (a compressed tar le). Both les are otherwise identical. Go ahead and download the version you prefer and unpack it.
unzip jmatter-<date>.zip

You should now have a folder named jmatter-<date>, containing these folders: Folder Name demo-apps jmatter modules AppBrowser Description Where JMatter tutorial applications reside The core of the JMatter framework Various modules which the framework relies upon The JMatter Application Browser 1

If applicable, place a copy of the JDBC driver .jar le for your database in JMatters lib/runtime/jdbc subdirectory (see Appendix B). Thats it.

Chapter 3

A Short Tour
Lets take a rst look at a software application developed using JMatter. Were going to setup and launch, and then study the Contact Manager demo application that is bundled with JMatter. You will nd it in demo-apps/ContactMgr.

3.1

Launching ContactMgr

Follow these steps1 :


$ cd demo-apps/ContactMgr $ ant schema-export

From the tutorial applications base directory, issuing the schema-export command (an ant target) for the rst time will: 1. compile the framework, 2. compile the tutorial applications code, 3. create an H2 database (in subdirectory db/ ), 4. generate the necessary o/r mapping les for the application, and 5. subsequently generates the actual database schema. Next, lets launch our application:
1 The $ symbol prexing each command serves to indicate the command line and is not part of the command

11

12

CHAPTER 3. A SHORT TOUR

$ ant run

This command is simply a convenient way of launching the application during development. JMatter applications are designed to be multi-user applications, running in clientserver mode. The framework supports the task of deploying applications using Suns Java WebStart technology. Please refer to chapter 18 for complete documentation pertaining to deploying applications. If you prefer to congure your own MySQL or PostgresQL database, please refer to appendix B.

3.2

The Tour

OK, weve just launched our rst JMatter application. We should be greeted with the login screen shown in gure 3.1.

Figure 3.1: Contact Manager Login Screen

3.2. THE TOUR

13

When an application is rst created, a single user will exist in the system. The user name and password values are admin. Later on, well show you how to change the admin password. Go ahead and login. You are now presented to your applications desktop (see gure 3.2).

Figure 3.2: Contact Manager Application Desktop

3.2.1

A Quick Orientation to the User Interface

On the left hand side you see a toolbar. This toolbar is a little different from most application toolbars. Instead of containing various actions (such as copy, paste, and others typically found in a word processing application, for example), this toolbar contains types of things: Persons, Businesses, Users, Folders, etc.. Im going to call this toolbar the Class Bar from here on. Furthermore, I will often reference the term as a single, lower-cased word: classbar. The JMatter user interface was designed to be simple and easy to understand. The mechanism for communicating various activities to the application mirrors the way we naturally tend to think about how to perform actions. We rst identify the object in question, and then specify the action to perform.

14

CHAPTER 3. A SHORT TOUR

In JMatter applications, when an object is displayed in a minimized form (which is the case with the various objects we see in the classbar), the various actions to invoke are accessible via a context menu, summoned by right-clicking on the object in question. This gesture should be a familiar one. For example, on the windows desktop, right-clicking on a le or folder will bring up its context menu. On the MacOS with a two-button mouse, its the same gesture (simulated as a ctrl-click on a 1-button mouse). GNU/Linux-based desktops have the same metaphor. The mechanism of rst selecting an object, and then selecting an action is known as a noun-verb user interface metaphor2 . So for example, to browse the list of users dened in the system, you can move your mouse to the Users icon, right-click on it and a menu of actions will appear. One of these actions is the Browse action. Go ahead and browse Users. You should see something similar to gure 3.3.
2 Its worthwhile noting that many applications user interfaces today dont abide by this metaphor. Typical applications toolbars contain actions and its not entirely clear what objects they relate to. When working with menus, youll pick an action rst and an object second (think about how we usually open les in software applications: we pick the open action rst and select the le second).

3.2. THE TOUR

15

Figure 3.3: Users I promised Id show you how to change the admin users password. Lets do this now: 1. Right-click on the admin user in the list 2. Select the action Change Password 3. You will be presented with a dialog and prompted to enter the new password (twice, to guard against typos) The next time you log in to the application, youll have to enter the new password. JMatter stores an md5 hash of the password in the database and so passwords are not vulnerable to prying eyes. Close the window containing the listing of users for now. Lets go ahead and add a person to our contact manager. Youve probably already guessed how to do it: right-click on the Persons icon in the Class Bar. Sure enough theres an action on its context menu called New. Thats the one.

16

CHAPTER 3. A SHORT TOUR

Your screen should now look like gure 3.4.

Figure 3.4: Creating a new Person Go ahead and complete the form. Note that there are two tabs worth of information to enter: the persons name and their contact information. Furthermore, the second tab contains a collapsible element: the address portion of the contact information can be expanded to reveal the address elds (street, city, state, zip, etc..). After youve nished entering the information, go ahead and click the Save button. Your view of the information you just entered will change to a read-only mode. To edit the information further, click the Edit button. Dont worry if you closed the window. Your information has been saved and you can retrieve this new persons information at any time. Note that other users logged in to the system can also view the contact information for this new person. Right-click Browse on Persons to view a listing of all the persons in your system. If you have a system with 300 persons in them, JMatter will make sure to page the listing 15 entries at a time3 . Also, notice that if you modify the Preferred Contact Method for a person from, say, Home Phone to Email, then when youre viewing that person in a minimized context (say browsing through a list of persons), the
3 The

page size can be customized.

3.2. THE TOUR

17

title for that person will automatically change. In the former case, it might say Joe Burns, (512) 333-444 and in the latter case it will change to Joe Burns, jb@yahoo.com. You can also create objects of type Business, for example, if you need to keep track of contact information for various businesses that you interact with. The mechanism for performing CRUD4 operations on any type (Person, Business, User, etc..) is the same. Lastly, notice that you can delete persons, though we want to prevent the possibility of accidental deletion of important information. JMatter does this by protecting the Delete action with a lock. Just click on the lock rst to unlock the action and then click on the button to perform the deletion. Its important to note that JMatter applications user interfaces are very simple: they boil down to the implementation of a single concept: the noun-verb user interface metaphor. That is, were in a world of objects and we manipulate them through actions5 .

3.2.2

Folders

Notice the Folders icon in the classbar. Right-click the New with name action, and specify a name for the new folder youre creating. Lets say that you want to keep track of important contacts, in which case you might want to name the folder Important Contacts. After entering the folder name, click OK. The folder is created and displayed on the screen. From a listing of Persons, you can simply drag and drop an entry onto the folder to add that person. You can put pretty much anything you want in a folder. The concept is completely analogous to the notion of folders on Operating System desktops. The difference of course is that you are not putting folders and les into a folder, but any type of object that is dened by the application, including Folders, Persons, Businesses, Queries, and more. Drag and Drop is only one mechanism to add items to a folder. Ill be showing you other ways of doing the same thing later on.

3.2.3

Queries

Assume you have plenty of contacts in your contact management system. This is not a problem of course since the application is backed by a database management
Create, Read, Update, Delete Not only do I contend that such user interfaces are simple and natural, but a beautiful thing happens in addition: these concepts map naturally onto an object-oriented implementation. To build your own such applications, very little else is needed other than dening an object model (classes and methods).
5 Aside: 4 CRUD:

18

CHAPTER 3. A SHORT TOUR

system, designed to hold thousands of records, gigabytes of information. The primary advantage of a database of course is its ability to mine information. Id like to look up all members of the Suez family in my contact manager. Heres one way to do this using JMatter: right-click on Persons in the Class Bar and pick the corresponding action, which this time will be Find. When invoking Find on Persons, a window will appear containing a way for us to specify a query. This one will be fairly easy: 1. From the pull-down menu on the left, select Person Names Last; 2. From the second pull-down menu, select the appropriate comparison operation; in this case it does not really matter, lets pick contains 3. In the text eld on the right hand side, enter Suez (or whatever last name youre searching for); 4. Finally go ahead and click on the Find button to perform the query. The search results will appear in the listing below the query you just performed. Lets take this example one step further: click on Save Query. At this point your screen should look something similar to gure 3.5.

3.2. THE TOUR

19

Figure 3.5: Performing and Saving a Query Give your query a name (I called it The Suezs) and click Save. Weve just dened and executed a query, then named it and nally saved it. It turns out that in JMatter, a query is nothing more than yet another type of thing, like a Person or a Business. Thats why there exists an entry in the Class Bar called queries. Go ahead and browse queries (right-click Browse on Queries in the Class Bar) and youll see your new query show up in the list (see gure 3.6).

20

CHAPTER 3. A SHORT TOUR

Figure 3.6: Browsing Queries If you like, you can even query queries. This may sound far-fetched but after a while, after youve dened lots of queries, the ability to search for a query (by name) might come in handy. Now that your query is dened and saved, you can execute it at any time. You guessed it, just right-click the Execute action on any query listed and youll get the search results. If another matching entry is entered into the system after a query is created, the search results will include the new entry as well, of course. JMatter calls this feature a Smart List. Finally, since the query we just saved was a query on Persons, JMatter went ahead and established an association between the Persons type and this new query. It took the liberty to add a new action to the Persons context menu. That is, you can now right-click The Suezs on Persons. 3.2.3.1 Quick Recap

I know we havent yet reached the chapter about actually writing applications in JMatter. Still, its important to note even at this early stage that the query facilities

3.2. THE TOUR

21

baked into this application are provided by the framework. You will not nd a single line of code in the Contact Manager application to support these capabilities. Something should be clicking at this point. Attempt to quantify how many lines of code exist in a traditional software application to support searches; especially for a category of application such as an issue manager. Issue managers are all about entering and updating and searching issues. Since entering and updating and searching things is built-in in JMatter, then very little work actually remains: the need to dene that there exists such as thing as an issue. Thats about it. Also, notice how both developers and end users are empowered by this model of building applications: 1. end users do not have to go to a developer in order to dene a new query in the system, they can do it themselves 2. developers time is freed to work on higher business-value tasks

3.2.4

Logs

To really drive the notion that all kinds of objects can play in the JMatter sandbox, so to speak, have a look at the type called Log in the Class Bar. Browse the list of log entries and youll see a screen that looks like gure 3.7.

22

CHAPTER 3. A SHORT TOUR

Figure 3.7: Log Listing What we discover is that the framework keeps track of specic events such as when a user logs in or out of the system or when a specic piece of information is created or updated6 . The system creates a log entry: a message, possibly a longer description of the event that took place, who performed the specic action, and what object this action was performed on. Since log objects are proper JMatter objects (like Person and Business) they inherit the same benets: the ability to search through logs, to view and even edit logs (though technically that last bit should be forbidden, and can be made so7 ). You can also see in gure 3.7 that the listing is currently showing you the rst of two pages of logs, with a page navigation arrow at the bottom.
6 Tapping 7 See

into this log system to log additional activities is trivial section 10.2 on authorization

3.2. THE TOUR

23

3.2.5

Multiple Views

Before we end our tour, theres one last major aspect of the user interface that we need to discuss: the notion of multiple views. You might have noticed four little icons on the top right-hand-side of listings windows. Bring up a listing of persons (right-click Browse on Persons) and click on the icon with the yellow star in it. You should see something similar to gure 3.8.

Figure 3.8: Icon Alternate List View The user interface for the Contact Manager application basically provides multiple alternative ways of viewing information. You can view a listing of Persons (or Queries or Logs) as a simple listing or as a list of Icons, or as a table, with the Persons elds (name, contact information) laid out in separate columns, or as a composite view: a listing on the left-hand-side combined with a form view of the currently selected item on the right hand side. This notion of multiple views should feel familiar, as its akin to the way le managers on our desktops behave: we can view a listing of les and directories in detail view or iconized view and so

24

CHAPTER 3. A SHORT TOUR

on. For single objects, say a single contact, you will likewise nd alternate views. You can use a tree view for a contact where the tree is arranged in such a way that associations between objects can be traversed. So for example, we can lookup a log entry about someone logging in to the system and view that entry in a composite tree view, as shown in gure 3.9. By expanding the tree nodes we can discover some of the associations between log objects and other objects. In this case, the person who logged in was the administrator. We also discover that users can be assigned to roles. The admin user belongs to the Administrators role, which in turn also keeps a list of all the users in the system that have the same role. Finally we see that roles maintain lists of eld and command restriction objects. It is by adding such restrictions to roles that we can begin to specify an authorization policy for our system: who is allowed to view what elds, who is allowed to invoke what actions, etc..

Figure 3.9: Composite Tree View for a Log Object So this composite tree view is actually a wonderful way to explore and quickly

3.2. THE TOUR

25

learn the way information is modeled in a system, the various associations between types of objects, and how to traverse them. In chapters 5 and 6 well have a chance to explore such relationships. 3.2.5.1 Custom Views

Going back to the notion that we can have multiple different and complementary views for objects or lists of objects: certain types of objects have additional custom views, specic to that type. For example the Class Bar is nothing but a custom view of a folder of folders. Although I wont show you how to do this until section 4.5, you can look for a special folder named Class List whose contents are reected in the Class Bar. Figure 3.10 shows a composite tree view of the class bar. You can right-click Browse or New on any of the three views of the Persons type, for example. Furthermore, it is possible to customize the class bar by placing other types into that folder (for example the Role type, which would be useful for system administrators who sometimes need to dene a new role, or add new users to an existing role).

26

CHAPTER 3. A SHORT TOUR

Figure 3.10: Three Views of the Class List Folder: A tree, an icon list, and the class bar This brings up an important point about the philosophy behind the design of the JMatter framework: to the greatest extent possible, the JMatter framework strives to give the end user more control of the application, more independence from the developer. How often have you been in a position where you really wanted to make a simple change to the way an application is congured only to nd out that the change could not be performed from its user interface (i.e. it required programming)?

3.2.6

Tour Summary

Lets review what weve accomplished so far. Weve seen how to launch the Contact Manager application, log in, and create a new user if we wish to. We learned how to browse and create contacts, and once our contact list becomes very large, how to make practical use of the query feature

3.2. THE TOUR

27

to nd the information were looking for. We also know how to switch between alternate views of the same information, and have a good grasp of what JMatter applications are all about, from the end users perspective. Finally, we have a general understanding of the noun-verb metaphor that JMatter application user interfaces model. That is, the notion that one rst selects a target object on which to perform an action, and then looks for and invokes a specic action on that object. This knowledge should enable us to quickly learn the user interfaces of other applications written with JMatter, even ones were encountering for the rst time. In the next chapter, well start exploring how to write JMatter applications. Well build our own contact manager. You may or may not be surprised by now if I were to tell you that the task will take us only a few minutes.

28

CHAPTER 3. A SHORT TOUR

Part II

Tutorial Applications

29

Chapter 4

A Zero-Code Contact Manager


Lets write our own version of the contact manager. The point of this chapter is to lay the foundation for writing JMatter applications. You will learn how to create and setup a project, what information goes where, some of the conguration les and their role in a JMatter application. As the title of this chapter indicates, we will not have to write a single line of code to implement our rst application!

4.1

Creating a New Project

To create a new project in JMatter, invoke the new-project-ui ant target:


$ cd jmatter $ ant new-project-ui

We need to decide on a name for our new project. Lets call it CM (short for ContactMgr), so as not to conict with the existing demo version of the contact manager application.

31

32

CHAPTER 4. A ZERO-CODE CONTACT MANAGER

Figure 4.1: New Project User Interface We have the option of creating a standalone or dependent project. It doesnt really matter at this point. Lets go with dependent1 . Go ahead and click on the Create Project button. This action will launch an ant target that takes our input and creates a complete directory structure for us. If you didnt specify a base directory, the new project is created by default in the jmatter directorys parent directory. Go ahead and quit the new-project-ui applet. Lets navigate to our new projects base directory:
$ cd ../CM $ ls build.xml doc/ resources/ src/ test/

JMatter creates the directory structure for your project, along with its own ant build le.

4.2

The Schema

We would normally proceed by modeling our application: identifying the entities, and implementing them as Java classes. With JMatter however, things are a little different. JMatter was designed to be a framework for building business applications. As such, JMatter predenes a number of common types of business objects, including persons, their contact information, addresses, and businesses. In this chapter well reuse the predened implementations of Person and Business, whose fully-qualied class names are com.u2d.type.composite.Person and com.u2d.type.composite.Business, respectively. Before we generate our schema, we need a way to communicate to JMatter the various types of objects we would like to persist. We typically do this by adding
1 The distinction between standalone and dependent projects is discussed in chapter 16 on page 191

4.3. THE CLASS BAR

33

an annotation (@Entity) directly on the model classes that we dene. However in this case, since were using pre-existing model classes, we do this by editing the underlying template, src/persistClasses.st, directly:
.. <value>com.u2d.type.composite.Person</value> <value>com.u2d.type.composite.Business</value> ..

We simply add the fully qualied names of the two classes Person and Business to the listing. Were now ready to generate the database schema:
$ ant schema-export

Behind the scenes, JMatter introspects the classes in question and for each it generates a Hibernate database mapping le, and nally asks hibernate to generate the DDL (data denition language) instructions and send them to the database. We should now be able to inspect the contents of our database and verify that it contains these tables. By default, JMatter uses the H2 database, which is lightweight and requires no work on your part 2 . By default, JMatter created the database CMh2db in the db/ subdirectory of your project. To view its contents, you can use the H2 web-based console. First you must start the H2 server, with this command:
$ java -cp ../jmatter/lib/runtime/jdbc/h2.jar org.h2.tools.Server

Then point your web browser to http://localhost:8082/ and login to the database (default username is sa, and the password is blank). These details are much better documented by H2s own documentation, of course.

4.3

The Class Bar

Similar to the task of specifying which types to persist to the database, we also need to specify which types to expose to the user interface via the Class Bar. This step is not really necessary, because we can edit (in this case, add types to) the classbar directly from the user interface. Feel free to skip this section if you wish. The way to predene the default classbar items is to edit src/class-list.json:
2 You may of course create your own, say, PostgresQL or MySQL database and congure your application to work with it. Appendix B provides the necessary information.

34

CHAPTER 4. A ZERO-CODE CONTACT MANAGER

{ "type": "com.u2d.type.composite.Folder", "items": { "item-type": "com.u2d.type.composite.Folder", "items": [ { "name": "Model", "items": { "item-type": "com.u2d.model.ComplexType", "items": [ { "value": "com.u2d.contactmgr.Person" }, { "value": "com.u2d.type.composite.Business" }, { "value": "com.u2d.type.composite.Folder" }, ...

This le is nothing but a marshalled Folder object (in JSON format3 ). When the application starts up, the le will be unmarshalled back as a Folder object. JMatter will detect that our database is empty (it contains no classbar) and will automatically persist the folder. Each user has his or her own class list. The xml le serves as a template. This is useful since many applications have multiple users, with different roles. So different classbars can be dened for each role.

4.4

Running Your Contact Manager

Lets do one more thing before we run our application: lets give it a splash screen. Do this by dropping a le named splash.png (or splash.jpg or splash.gif ) into the resources/images folder. If you like, just copy the one from the demo application. Ok, lets run our app:
$ ant run

Thats it. We now have a working contact manager application. Go ahead and exercise it: create new person objects, etc.. (see gure 4.2).
3 JSON

stands for JavaScript Object Notation. See http://json.org/ for more information

4.5. CUSTOM VIEWS REVISITED

35

Figure 4.2: Classes organized into two subfolders: Manager and Administrative

4.5

Custom Views Revisited

In subsection 3.2.5.1 I had mentioned that the Class Bar can be customized directly from the User Interface. Were at a good place to show you how this works. Follow these instructions: 1. Launch the application and log in 2. Click on the Administrative folder in the Class Bar 3. Browse Types (right-click Types, select Browse) Weve just asked our application to show us all the types dened in our system (Note that Contact Methods is among the list of dened types, though it doesnt have an icon, and thus shows up with a question mark icon). 1. Click on the Manager folder in the Class Bar 2. Drag Contact Methods to the empty area inside the Manager folder in the class bar

36

CHAPTER 4. A ZERO-CODE CONTACT MANAGER

We have just added a type to the class list. Our class bar should now resemble gure 4.3.

Figure 4.3: Class Bar Customized with an Additional Type: Contact Methods

4.6

Project Structure

Lets take a closer look at the les in our project.

4.6.1

Files

JMatter denes certain conventions for where to place les. These conventions are probably very similar to your existing project conventions. Here is a summary of these conventions: 1. Source code resides in the src/ directory 2. You will nd certain resources, such as images, in the resources directory 3. The ant build le for your project uses the default name build.xml and resides in your projects base directory

4.6. PROJECT STRUCTURE

37

4. Your source code is compiled to the target directory build/classes 5. JMatter generates Hibernate mapping les for persisting your domain objects; these les by convention bear the sufx .hbm.xml and also are written to the build/classes directory 6. When deploying your application with Java Web Start (see chapter 18), the distribution le is placed in the dist directory 7. The doc directory contains a simple README le, serving as a quick reference or as simple setup instructions to help you get started on a new project. You are also urged to use this folder to place any relevant documentation for your project. 8. The test directory is created for you to place JUnit tests you write to ensure that your code and business logic is correct and bug-free

4.6.2

Ant Targets

You dont need to memorize the names of the ant targets that we invoke (e.g. ant run, ant schema-export); simply type:
ant -projecthelp

to view a list of all the dened targets: their name and description (Of course, if youre running GNU/Linux and have bash smart completion turned on, simply pressing the tab key will display a list of valid ant targets).

4.6.3

A Peek at the Source Code

Open the le Person.java in a text editor or IDE4 (it is located in jmatter/src/com/u2d/type/composite). Were not going to attempt to understand every line of code just yet. What I want you to notice is that a Person denes two elds: name, and contact:
protected final Name _name = new Name(); protected final Contact _contact = new Contact();

The Java classes Name and Contact are also dened in the framework. The Name class is composed of the parts that make up a name: prex, rst, middle, last, and sufx. If you dig a little deeper, you will see that Contact.java denes these elds:
4 IDE:

Integrated Development Environment

38

CHAPTER 4. A ZERO-CODE CONTACT MANAGER

private final USPhone _workPhone = new USPhone(); private final USPhone _mobilePhone = new USPhone(); private final USPhone _fax = new USPhone(); private final Email _email = new Email(); private final USAddress _address = new USAddress(); private ContactMethod _preferredContactMethod = new ContactMethod();

Here we see that JMatter has a built-in understanding of types such as a US Phone number, an Email address, a US Address and a Contact Method. If you inspect the generated database schema for our application, you will not nd a database table to hold contact information or addresses. The reason is that with JMatter, you have the choice of modeling a eld either as an association or as an aggregation. In the context of the class Person, Contact and USAddress are modeled as aggregates, and so are treated in a manner similar to value elds such as the work phone or email address. The elds that make up the contact information and address are aggregated into the parent types table. Hibernate calls these Components. If youre familiar with the concepts in the book Domain-Driven Design [5], then youre already familiar with both Aggregates and Value Objects. Well learn more about ways of modeling relationships between objects in the next chapter. Chapter 8 provides a more complete reference.

4.7

Summary

Heres a quick recap of what we learned in this chapter: 1. We learned how to create a new project skeleton with the ant new-project-ui command; 2. We are aware of two conguration les src/persistClasses.st and src/class-list.json and know a little about how to congure them; 3. Also, we learned that images go in the resources/images folder; 4. We learned the basic commands for creating our schema and running our application: ant schema-export and ant run 5. We studied the structure of a JMatter child project With the basics for setting up, conguring, and running projects under our belt, were now ready to do some real work. In the next chapter, were nally going to get a chance to write some code in the MyTunes music application.

Chapter 5

MyTunes in under 200 Lines


Tunes have become a popular topic. Lets build a music player! Before we get started, bear in mind that we wont have to build features such as Smart Lists for songs; JMatter will give us those things for free. Well be able to concentrate on the task at hand: modeling our application and implementing the behaviours of our music player, such as importing songs into our song database, and playing songs, of course. Lets get started.

5.1

Creating the Project

We know how to create our project. Ill name my project MyTunes and make it a dependent project. A nished copy of this project is already bundled with JMatter. If you wish, you can simply follow along using the existing demo application.
$ cd jmatter/ $ ant new-project-ui $ cd ../MyTunes $ ant -projecthelp

So far so good. Next, lets setup our project in our favorite IDE because were nally going to be writing code.

5.2

Setup your Project in an IDE

Technically, this step is optional. These days, the state of Integrated Development Environments (IDEs) for writing software in Java is so advanced that it is compelling to use one. These IDEs sport command completion features, intelligent assisted editing, automatic code formatting, useful hints, refactoring support, etc..

39

40

CHAPTER 5. MYTUNES IN UNDER 200 LINES

At the time of this writing, the three major IDEs for Java are Eclipse http://www. eclipse.org/, IntelliJ IDEA http://www.jetbrains.com/idea/, and NetBeans http:// www.netbeans.org/. It doesnt really matter which you use, or whether you use one at all, as long as youre comfortable in your development environment. Below is a description of the steps that I take as I setup my project in IntelliJ IDEA: 1. Launch the IDE program 2. Create New Project (launches a wizard) (a) specify the project name as MyTunes, and (b) the base directory path 3. Pick the version of Java that I wish to use (Java 5) 4. Specify that well be using a single module project 5. Select the module type: Java module 6. Specify the module name as MyTunes (accept the defaults) 7. Make sure the source directory name is src 8. Make sure the build directory path (where the compiled classes are placed) is build/classes 9. Click Finish Nothing special here. Actually, most of the defaults were already correct; that is, I mostly clicked Next > Next > Next, with one or two deviations from the defaults. My project is almost completely setup. The last thing I need to do is add the jar les in ../jmatter/lib/runtime to my project classpath so that the classes we reference can be resolved. If you created a dependent project as I did, add the directory ../jmatter/build/classes to your classpath as well. Since the specic instructions vary from IDE to IDE, and since this is such a basic operation, I wont hold your hand through this task. :-) Before getting started with coding in the next section, you might want take a quick peek at section 20.2 on page 220 to setup some JMatter-specic le templates and live templates which will make keying the code much simpler.

5.3

Getting Started

Ok, checking out my iTunes application on a nearby powerbook, I see that the main entities in a music player system appear to be Songs, Albums, Artists, and Genres. Pretty straightforward. Lets get started by modeling each of these:

5.3. GETTING STARTED

41

1. Create a package to hold your classes; mine will be com.u2d.mytunes 2. Create four classes: Song, Album, Artist, and Genre Lets take a look at a basic template for implementing the Artist JMatter class:
package com.u2d.mytunes; import com.u2d.model.AbstractComplexEObject; import com.u2d.model.Title; import com.u2d.type.atom.StringEO; import com.u2d.type.atom.TextEO; import javax.persistence.Entity; @Entity public class Artist extends AbstractComplexEObject { private final StringEO _name = new StringEO(); private final TextEO _bio = new TextEO(); public static final String[] fieldOrder = {"name", "bio"}; public Artist() {} public StringEO getName() { return _name; } public TextEO getBio() { return _bio; } public Title title() { return _name.title(); } }

Lets analyze the above: 1. The @Entity Annotation: automates having to manually edit src/persistClasses.st as we had to do in the last chapter 2. Artist extends AbstractComplexEObject In Java all the classes we write extend Object. When building JMatter applications, the base class for complex entities (ones that have more than a single eld) is AbstractComplexEObject. Just like Object gives us toString() for free, AbstractComplexEObject also gives us a few things for free. 3. Artist has two elds: name, and bio It happens to be a personal style choice of the author to name instance variables with the underscore prex. This, of course, is not necessary. 4. Funky types: name is a StringEO, bio is a TextEO Thats right. JMatter gives you a whole slew of atomic types to choose from, including types for phone numbers, social security numbers, time durations, images, email addresses, colors, and much more. Its quite easy to adapt a String as a StringEO and vice versa. There are two differences between a StringEO and a TextEO:

42

CHAPTER 5. MYTUNES IN UNDER 200 LINES

(a) StringEOs are saved to the database as varchar types (limit is typically 255) whereas TextEOs are saved as text types or some other similar large text object1 ; and (b) StringEO editors in the GUI are text elds whereas TextEO editors are text areas. Think of the EO part of the type name as being an acronym for Enhanced Object. 5. Name and Bio are marked nal! Yep. Thats part of the ValueHolder contract, these are never null. To set a value on an atomic or aggregate type, call the setValue() method. Consequently, atomic elds and aggregates in JMatter classes have only getters. 6. public static nal String[] eldOrder = {name, bio} This is essentially metadata. Youre giving JMatter a hint as to the order that youd like these elds displayed when viewed using a form view. Name should come rst, bio second. Notice that the eld names are those derived from the accessor methods according to the JavaBeans convention, not the underlying variable names. 7. public Title title() { return _name.title(); } Every JMatter class you dene must specify a title. In this case, the title for an artist object will simply be the artists name. For the Person class in the previous chapter it was a concatenation of the persons name and the value of their preferred contact method (phone number or email address). The idea for the Title class was shamelessly taken from the NakedObjects framework [1], though youll nd in it a few additional features, such as the appendParens() method which allows you to perform concatenation by wrapping the argument in parentheses. Thats it. The code is not very lengthy, but this rst-time explanation certainly is. One last note: If youre thinking right now that metadata such as the eldOrder eld above might be better modeled using Java 5 annotations, I would agree with you; I may do just that in the next version of JMatter. But this design decision has no bearing on your productivity as a software developer.

5.4

The Album Class

In a fashion similar to the way we wrote Artist, lets now write a simple implementation for an Album:
1 depending

on the rdbms you use

5.5. THE GENRE CLASS

43

package com.u2d.mytunes; import com.u2d.type.atom.StringEO; import com.u2d.type.atom.ImgEO; import com.u2d.model.AbstractComplexEObject; import com.u2d.model.Title; import com.u2d.list.RelationalList; import javax.persistence.Entity; @Entity public class Album extends AbstractComplexEObject { private final StringEO _name = new StringEO(); private final ImgEO _cover = new ImgEO(); public static final String[] fieldOrder = {"name", "cover"}; public Album() {} public StringEO getName() { return _name; } public ImgEO getCover() { return _cover; } public Title title() { return _name.title(); } }

Theres really very little new here. Its worth mentioning that were dening a eld of type ImgEO for the albums cover illustration. This basic type represents an image (gif, jpg, or png) that will be saved to database as some kind of binary large object (blob).

5.5

The Genre Class

Lets take a look at Genre next. Genre is a little more interesting. I decided to consider this type more like an enumeration. That is, that there should exist a fairly small, nite list of genres. However, unlike enumerations, we dont want to hard-code the list of genres in Java. We would like the end-user to be able to add entries to the list directly from the user interface. This is the template that JMatter denes for such database-backed enumerations:
package com.u2d.mytunes; import com.u2d.type.AbstractChoiceEO; import com.u2d.type.atom.StringEO; import com.u2d.model.ComplexType; import javax.persistence.Entity; @Entity public class Genre extends AbstractChoiceEO { private final StringEO _code = new StringEO();

44

CHAPTER 5. MYTUNES IN UNDER 200 LINES

private final StringEO _caption = new StringEO(); public static String[] identities = {"code"}; public Genre() {} public Genre(String code, String caption) { _code.setValue(code); _caption.setValue(caption); } public StringEO getCode() { return _code; } public StringEO getCaption() { return _caption; } }

JMatter will make sure to give us a database table to hold genres. Notice that weve extended a different class: AbstractChoiceEO. In the GUI, when we want to specify a genre for a song, well be picking the genre from a ComboBox (also called a select or pull-down menu). For each Genre object well specify both a code and a caption. The line
public static String[] identities = {"code"};

is metadata telling JMatter that the code column in the table should be unique for all Genres (that is, you cant have two genres with the same code, rock for example).

5.6

The Song Class

Heres a rst stab at the Song class:


package com.u2d.mytunes; [imports collapsed] @Entity public class Song extends AbstractComplexEObject { private final StringEO _title = new StringEO(); private final TimeEO _duration = new TimeEO(); private Album _album; private final Genre _genre = new Genre(); private Artist _artist; public static String[] fieldOrder = {"title", "duration", "artist", "album", "genre"};

5.6. THE SONG CLASS

45

public Song() {} public StringEO getTitle() { return _title; } @Fld(format="m:ss") public TimeEO getDuration() { return _duration; } public Album getAlbum() { return _album; } public void setAlbum(Album album) { Album oldAlbum = _album; _album = album; firePropertyChange("album", oldAlbum, _album); } public Genre getGenre() { return _genre; } public Artist getArtist() { return _artist; } public void setArtist(Artist artist) { Artist oldValue = _artist; _artist = artist; firePropertyChange("artist", oldValue, _artist); } public Title title() { return _title.title().appendBracket(_duration); } }

So far, this is more of the same, with a few new concepts. Lets review this class: 1. The song class denes the elds: title, duration, album, genre, and artist. As usual, we dene the eldOrder String array as a means of specifying the order in which these elds are to be displayed. 2. The duration eld is of a type we havent seen before: TimeEO. This type can be used to specify a certain length of time. 3. @Fld(format="m:ss") Were specifying through a eld annotation parameter that in this application were going to want to format durations using minutes and seconds. The format string complies with the contract specied by java.text.SimpleDateFormat. 4. Accessors and Mutators Finally we see that not all elds are owned by the Song class. The elds album and artist are associations to other entities. The convention for dening and specifying the accessors and mutators for association elds is different. It complies with the JavaBeans convention for bound properties. Notice we: (a) provide both a getter and a setter, and (b) re a PropertyChangeEvent after the assignment.

46

CHAPTER 5. MYTUNES IN UNDER 200 LINES

5. Here we have a better example of a title() method. First, dont confuse the song title with the song types title() method. Theyre two different things. We want songs to display their titles and durations and so we concatenate the two. I use the utility method appendBracket to display the song duration in square brackets.

5.7

Running our Application

Weve been a little zealous here and dened all four classes Artist, Album, Genre, and Song at once. This is not an example of good incremental coding practice. However, we made sure to keep these classes really simple. We didnt implement any behavior, we simply dened four types along with some pretty basic properties on each, such as the Artists name, a Songs title. If you like, feel free to keep the Song class even more simple by just giving it a title for now.

5.7.1

Conguration

Technically there is no conguration left to do. However, it might be simpler for us to specify the contents of the classbar for our application in xml form. Again, this is optional. The le to edit is src/class-list.json. Heres a sample thatll do nicely:
{ "type": "com.u2d.type.composite.Folder", "items": { "item-type": "com.u2d.type.composite.Folder", "items": [ { "name": "Model", "items": { "item-type": "com.u2d.model.ComplexType", "items": [ { "value": "com.u2d.mytunes.Song" }, { "value": "com.u2d.mytunes.Album" }, { "value": "com.u2d.mytunes.Artist" }, { "value": "com.u2d.mytunes.Genre" }, { "value": "com.u2d.app.User" }, { "value": "com.u2d.type.composite.Folder" }, { "value": "com.u2d.find.CompositeQuery" }, { "value": "com.u2d.type.composite.LoggedEvent" } ] }

5.7. RUNNING OUR APPLICATION

47

} ] } }

5.7.2

Finally Running the Application

Nothing new here. Lets run our app:


ant schema-export ant run

After logging in we should see something that looks like gure 5.1.

Figure 5.1: A rst look at MyTunes This is problematic: we havent specied any icons for our types. Let me tell you (and I speak from experience) that the choice and quality of your icons is as important to the success of your application than the quality of the code itself. I strongly believe that all aspects of our application must be of high quality, regardless of

48

CHAPTER 5. MYTUNES IN UNDER 200 LINES

whether its the code under the hood or perhaps cosmetic items that many developers often perceive as being outside their jurisdiction, or outside their realm of expertise. Heres how to specify icons for each type: in the resources/images directory, place 16x16 and 32x32 pixel versions of an icon for each type. The naming of these image les is important. It is via a le naming convention that JMatter knows to associate an image with a type. This idea again was shamelessly taken from the NakedObjects framework. If you havent guessed it by now, NakedObjects [1] had a strong inuence on my thinking. Ok, images can be of type jpg, png, or gif, or anything that Java Standard Edition supports. Here is a listing of my resources/images folder:
eitan@ubuntu:~/projects/ds/MyTunes$ ls -lF resources/images/ total 40 -rwxr-xr-x -rwxr-xr-x -rwxr-xr-x -rwxr-xr-x -rwxr-xr-x -rwxr-xr-x -rwxr-xr-x -rw-r--r--rwxr-xr-x -rwxr-xr-x 1 eitan eitan 855 2005-11-28 21:38 Album16.png* 1 eitan eitan 1961 2005-11-28 21:39 Album32.png* 1 eitan eitan 1961 2005-11-29 07:56 App32.png* 1 eitan eitan 859 2005-11-28 21:39 Artist16.png* 1 eitan eitan 2170 2005-11-28 21:40 Artist32.png* 1 eitan eitan 925 2005-11-28 21:39 Genre16.png* 1 eitan eitan 2596 2005-11-28 21:39 Genre32.png* 1 eitan eitan 753 2005-11-28 21:13 README 1 eitan eitan

696 2005-11-28 21:38 Song16.png* 1 eitan eitan 1720 2005-11-28 21:38 Song32.png* eitan@ubuntu:~/projects/ds/MyTunes$

The basic convention is quite simple: [ClassName]16.png and [ClassName]32.png for each class. But thats not the whole story on icons. For a complete description of the icon conventions, see section 8.4.4. If, like me, producing icons is not your forte, then I highly recommend the incors professional icons collection http://www.iconexperience.com/. Ok, now things should look a little bit nicer (see gure 5.2).

5.8. BACK TO THE CODE

49

Figure 5.2: MyTunes with Icons Thats much better, dont you agree? We can play with the user interface some more and create genres, songs, and so on, but were not quite nished with our application.

5.8

Back To the Code

Our applications foundation is laid; we have a basic object model. But were missing something: an album should dene and maintain a list of songs. We already have the other side of that association in Song.album. Lets add that oneto-many relationship right now. In Album.java, add these:

private final RelationalList _songs = new RelationalList(Song.class); public static final Class songsType = Song.class; public RelationalList getSongs() { return _songs; }

If youre thinking that the above might be better modeled using Java 5 generics, I would agree with you; I may do just that in the next version of JMatter.

50

CHAPTER 5. MYTUNES IN UNDER 200 LINES

We dened a relational list of type song. The reason for the static Class songsType is to allow JMatter to introspect the list type statically. Its not pretty but it will do for now. One last thing: we have a bidirectional one-to-many relationship between a song and an album. We need to add two more lines of metadata to tell JMatter about it. In Album:
public static String songsInverseFieldName = "album";

And in Song:
public static final String albumInverseFieldName = "songs";

Our model might quickly get of sync with the database tables we generated when we add new elds to types. There are two ways to bring them back in sync. The easy way:
ant schema-update

The harder, possibly more correct way: 1. Dump your data out of the database 2. ant schema-export (wipes out the data) 3. restore the data The restoration of data usually needs to be broken down into at least these steps: 1. drop constraints on your schema 2. restore the data 3. add the constraints back in Anyhow, in our case, we dont have any precious data to save and restore yet so well go the easy route of either using schema-update or schema-export.

5.9. VALIDATION

51

5.9

Validation

You might have also noticed that you can now create albums or songs with no name or title. This is a little disconcerting. There are two ways to address this issue. The rst might be to specify that a songs title or albums name should be unique. Weve seen this already with Genre: you can specify the eld metadata identities to enforce this. So in Album, you can add this:
public static String[] identities = {"name"};

Like eldOrder, you can specify multiple identity elds if necessary. The eld is agged with the unique database constraint and in addition, JMatter treats identity elds as required. In this case, it happens to be a coincidence that the elds we wanted to mark as required also happened to be unique (i.e. you should denitely not go about marking elds unique for the purpose of making the user interface treat them as required elds). To mark elds as required, edit the le resources/model-metadata.properties like so:
# Song.title.required=true Album.name.required=true Artist.name.required=true #

Now JMatter will give you built-in validation support in the user interface: 1. Required elds captions are automatically styled in blue; (you can change the styling of required elds by modifying the rule .required in the le resources/styles.css2 ) 2. Validation checks will automatically be performed when attempting to create or save instances; 3. The user interface will automatically display validation error messages in the proper locations on the form Figure 5.3 shows the behavior of the JMatter user interface after the change.
2 See

chapter 17 for more about styling the user interface using CSS

52

CHAPTER 5. MYTUNES IN UNDER 200 LINES

Figure 5.3: Validation I attempted to create a new Artist, leaving the name blank. So JMatter is prewired to support validation. This mechanism we just specied is the simple way, for required elds. Theres an additional method validate() that we can override in any of our types to specify more complex validation rules that have dependencies on multiple elds. For a more complete treatment of validation in JMatter, see chapter 9.

5.9.1

A word about the model-metadata.properties File

Although the mechanism of specifying model metadata in a text le may continue to exist in the future, it is the goal of the JMatter framework to move all of that work directly into the GUI. Whether a eld is required, a elds default value, its caption and more will all be entered in the same way one enters the username for a new User. The intent is for Field types (and meta-types in general) to become full-edged JMatter objects, with a GUI, editability, and so on. One can denitely imagine a new role for a JMatter user: the conguration manager, who uses a JMatter application to congure a JMatter application before releasing it to its user population. In fact, I recall reading early versions of the

5.10. BEHAVIOUR

53

J2EE specication years ago where they outlined a number of roles in application development.

5.10

Behaviour

So far, we seem to have nice, working model for a music application: we can create songs, albums, associate them. We can dene artists like the famous Shlomo Artzi for example. This modeling is important, dont get me wrong. After weve dened a thousand songs, well have powerful search features at our disposal to nd that one special song. Whats missing is behaviour: the ability to play songs! Also, it would be awfully tedious to enter all that information by hand. Cant we just import that stuff from our iTunes library? So, weve just dened some additional work for ourselves: wed like to be able to play songs and wed like to be able to import songs listings. A short glance at the Java sound API javadocs tells us that we can attempt to play an mp3 le with this bit of code:
try { AudioClip clip = Applet.newAudioClip(_path.fileValue().toURL()); clip.play(); } catch (MalformedURLException ex) { System.err.println(ex); }

Ok, so we need to keep track of the path where our song le is located. So well need to add a new eld to Song:
private final FileEO _path = new FileEO();

And add the new eld to our eldOrder array:


public static String[] fieldOrder = {"title", "duration", "artist", "album", "genre", "path"};

It sure would be nice to construct a song in a single line, so lets add this constructor:

54

CHAPTER 5. MYTUNES IN UNDER 200 LINES

public Song(File path) { _title.setValue(path.getName()); _path.setValue(path); }

Dont forget the accessor method for _path:


public FileEO getPath() { return _path; }

Finally we need to expose a play command to our user interface. Since were already there, why not also add a pause command?
private AudioClip _clip; @Cmd(mnemonic=p) public Object Play(CommandInfo cmdInfo) { try { _clip = Applet.newAudioClip(_path.fileValue().toURL()); vmech().message("Playing song.."+this); _clip.play(); return null; } catch (MalformedURLException ex) { System.err.println(ex); return ex.getMessage(); } } @Cmd public void Pause(CommandInfo cmdInfo) { if (_clip != null) _clip.stop(); }

It turns out this will work for certain audio les but not for MP3s. A quick google and we discover a nice little utility that gives us an MP3 Service Provider Interface (SPI) for the Java Sound API. We download it. Its README.txt le tells us we just need to add three jar les to our classpath:
cp mp3spi1.9.3.jar ~/jmatter-complet/demo-apps/MyTunes/lib/src cp lib/*.jar ~/jmatter-complet/demo-apps/MyTunes/lib/src

5.11. ANALYSIS

55

Now were in business3 . Lets give it a shot:


$ ant schema-export $ ant run [create a song, specify a path to an mp3 file, save, and click Play]

On my machine, Ubuntu took perhaps 2-3 seconds to load the mp3 song and then started playing Amour Perdu, by Adamo (see gure 5.4).

Figure 5.4: Playing Amour Perdu Time to slow down and explain some of what we just did..

5.11
5.11.1

Analysis
FileEO

JMatter provides editors for all kinds of basic types including Files. Our path was of type FileEO. This implies to the user interface to use the designated editor for
3 And you thought that the part in the movie The Matrix where a helicopter manual is summoned a few seconds prior to ying one was pure science ction. :-)

56

CHAPTER 5. MYTUNES IN UNDER 200 LINES

the type FileEO when selecting a song: a File Chooser. Simple enough.

5.11.2

Commands

Exposing commands on types in JMatter is as simple as exposing types. A command in the user interface maps to a method implementation on my class, just as a type in the UI is implemented via a Java class. The convention to follow for commands is to decorate the method with the @Cmd annotation. This annotation accepts a number of options, including the mnemonic character that the user interface will use to make the command keyboard-accessible. Theres one additional requirement, that these methods take a CommandInfo argument. We dont actually need that information in this particular case but there exist situations when we do. Anyhow, its part of the current convention established by JMatter. The caption that JMatter uses in menu items and buttons representing a command method is derived from the method name. For an annotated method named ProduceHCFA_WithForm, for example, the caption will be Produce HCFA With Form. Notice that we did not have to worry about launching the song in a separate thread. JMatter does all this for us. Our user interface remains responsive the entire time. Although the UI replaces the mouse cursor with a WAIT_CURSOR (which these days seems to be some kind of spinning wheel on Ubuntu Linux anyway) to indicate that the song has not nished playing, we have full control over the UI and can close our window, open new ones, perform queries, etc.. all while our Song plays in the background.

5.11.3

message()

Theres a curious line of code in the middle of the command implementation:


vmech().message("Playing song.."+this);

vmech() returns a reference to the view mechanism. message() signals to the view mechanism to display a message. The Swing view mechanism displays the message in a large font in a semitransparent window that automatically dismisses itself after two second.

5.11.4

Return Type

Our command method returns an Object. Here is yet another simple convention established by JMatter that if for some reason your command returns a bit of text, that bit of text will be displayed to the GUI. Notice that if for some reason we

5.12. IMPORTING SONGS

57

get an exception attempting to play our song, were returning an error message, which will be displayed to the user. JMatter tries to do this in good taste. Rather than display some kind of dialog box that one is forced to dismiss, JMatter displays a timed, semi-transparent, borderless dialog with the message which automatically disappears after a few seconds or when clicked on. Lets proceed and implement our second task: a mechanism for importing songs from our iTunes library.

5.12

Importing Songs

So heres the issue: sitting in my ~/music/iTunes Music/ folder are a bunch of mp3 les. I dont want to add them to my system one by one. Id like to basically right-click on Songs and request that MyTunes scan for songs on my disk, from a specic base path. I decided to call my command Scan From Base Path and so will name my command method accordingly:
@Cmd public static Object ScanFromBasePath(CommandInfo cmdInfo, @Arg("Base Path") FileEO basePath) { if (!basePath.fileValue().isDirectory()) return "You must specify a directory as the base path"; List songFiles = basePath.listRecursive(mp3Filter); Set songs = new HashSet(); for (int i=0; i<songFiles.size(); i++) { songs.add(new Song((File) songFiles.get(i))); } HBMSingleSession pmech = (HBMSingleSession) Context.getInstance().getPersistenceMechanism(); pmech.saveMany(songs); return "Finished importing MP3s"; } private static FileFilter mp3Filter = new FileFilter() { public boolean accept(File file) { return file.getName().toLowerCase().endsWith(".mp3"); } };

Lets study this bit of code:

58

CHAPTER 5. MYTUNES IN UNDER 200 LINES

1. Our method is dened as static to ensure that our command is added to the Song type, and not to song instances. The command will be accessible from the Class Bar (right-click on Song). 2. Next, we see that we use the same little trick of returning a string if the specied path is not a directory. So the user will get an error message when they pick a base path that is invalid. Wait a minute. Where or when did we tell JMatter to give us a base path? Notice that the command method takes an additional argument of type FileEO. When this command is invoked, JMatter will see that this method needs a path and will prompt the user for it. 3. Look towards the bottom of the listing: were dening a plain old Java le lter (POJFF) to let through only les with a .mp3 sufx. Then we invoke a method listRecursive() on FileEO, passing in the le lter. Now we have a listing of all the mp3 les nested inside the users specied base directory. 4. Now all we need to do is create a Song object for each le and save all these songs. Not bad for ~ 10 lines of code, if I may say so. Lets try this out. No persistence-related changes have taken place so we can just re-run our app:
$ ant run

Figure 5.5 shows the song listing of the base directory after invoking Scan From Base Path on Song.

5.13. NOT COMPLETELY FINISHED

59

Figure 5.5: Song Listing after Import The operation created 159 Song objects or eleven pages worth. The durations are not correct of course. A better way to solve this problem would be to interpret the iTunes xml le, which contains all sorts of song metadata besides the basic song le information.

5.13

Not Completely Finished

If we take a moment to think about our implementation, well realize that our work is not exactly done. Although our songs actually play, our implementation is naive. Is the song actually streamed? Are resources disposed of properly? A little more research into Java sound shows us that the API were using is really outdated. There is a newer Java sound API in the javax.sound package. Furthermore, even that API has been somewhat deprecated by the Java Media Framework, which is an add-on to the standard Java distribution. Finally, we discover that JMF itself has been in maintenance mode for a number of years now. Some advocate using Apples QuickTime for Java API (QTJ). I personally have an issue with using QTJ: it doesnt run on my computer. That is, Apple does not write their APIs or software applications to run on GNU/Linux, even though they had no qualms about pillaging open source code for their operating system kernel, or for their Safari web browser, just to name a few situations. I suppose giving is a one-way street.

60

CHAPTER 5. MYTUNES IN UNDER 200 LINES

Here is a list of enhancements we can think of for our MyTunes player: 1. Replace our audio playing implementation with one that is based on the Java Media Framework 2. Write a second, alternative import implementation that interprets iTunes XML metale 3. Revise our model to dene the notion of a current playlist, add a command to Song to add it to the playlist, and nally, move the play and pause commands from Song to the new PlayList. This revised model seems to make a little more sense. It turns out that if we discard the Java Sound API and the MP3 provider interface we downloaded, and instead use the JLayer library and its API, we get beautiful mp3 streaming for free in Java. The MyTunes demo application in the JMatter distribution was revised to use JLayer directly and mp3 les of all sizes play immediately without consuming gobs of memory. I leave the study of the nal application to you as an exercise. The point here is that JMatter frees you to work on the important things, like properly importing or playing a song. You dont have to worry about infrastructure services such as persistence, queries, or a user interface. In very little time, we created a basic music player with Smart Lists. Figure 5.6 shows the quick search feature built into JMatter where you can just type in a song title in a listings searchbar to lter the list accordingly.

5.14. SUMMARY

61

Figure 5.6: That One Special Song..

5.14

Summary

To say that we covered a lot of ground in this chapter would be an understatement. And yet, if we go through the due diligence of measuring how much code we actually produced:

eitan@ubuntu:~/projects/ds/MyTunes/src/com/u2d/mytunes$ wc -l *.java 28 Album.java 21 Artist.java 24 Genre.java 119 Song.java 192 total eitan@ubuntu:~/projects/ds/MyTunes/src/com/u2d/mytunes$

We discover that we wrote our music player in under 200 lines of code! Thats readable. Thats workable. But not just 200 lines of code: a full-edged music player in under an hour? Thats a paradigm shift. Lets quickly review what we learned in this chapter: 1. We learned how to setup our project in an IDE.

62

CHAPTER 5. MYTUNES IN UNDER 200 LINES

2. Weve learned the basic class template for our business objects in JMatter: our classes extend AbstractComplexEObject, they have aggregate properties that adhere to the ValueHolder pattern, and they have associations to other objects that follow the JavaBeans accessor-mutator pattern. 3. We learned how to control the eld order in the GUI with the eldOrder static member; we can specify that a property is unique by including it in the identities static member. 4. We learned how to associate icons with types by placing our icons in the resources/images folder, and following a specic naming convention. 5. We learned how to expose both instance and class (static) actions to the UI. Weve also seen how to write actions that take arguments. 6. Weve been exposed to some of the atomic types that JMatter provides out of the box, including: StringEO, TextEO, ImgEO, TimeEO, and FileEO. 7. Weve also been exposed to a simple mechanism for specifying eld metadata, such as whether a eld is required or not. Although we have begun to dig deeper into this framework, there are many more features that we have yet to discuss and uncover. A small but useful additional feature that were going to use in the next chapter is the ability to customize icons on a per-instance basis. That is, we can use the artists photo as the basis for its icon in the MyTunes user interface; though well introduce this feature in the context of a new application, the Conference Manager Sympster. Some other, more serious features in JMatter include 1. Integration with JFreeReport for producing PDFs 2. Calendaring (well see this in the next chapter) 3. Wizards 4. Polymorphic modeling support including interface-based modeling

Chapter 6

A Conference Manager
In this chapter were going to build a conference management application. The idea for this application came to me while a speaker in a real series of conferences: The No Fluff Just Stuff Java and Open Source symposia. Here are some of the features of JMatter that I will be introducing in this chapter: 1. Reinforcing our understanding of modeling a domain according to the conventions of the JMatter framework 2. More metadata 3. How to use an objects image eld as its icon representation 4. How to add Calendaring support to your application 5. Polymorphic modeling

6.1

Analysis

Lets begin by reviewing the nouffjuststuff.com web site to get a feel for the business domain were going to be working with. From the home page: 1. click on Speakers in the toolbar 2. Browse through the list of speakers 3. Drill down to a specic speaker

63

64

CHAPTER 6. A CONFERENCE MANAGER

4. We note that a speaker has a name and a biography, as well as a list of presentations 5. A presentation appears to have a title, an abstract, and an association back to the speaker Lets now take a look at upcoming or past symposia. Looking at the list of past symposia, I see that the Rocky Mountain Software Symposium took place during the weekend of November 11 2005. Click on a specic symposium and youll see a list of speakers, and a list of sessions. If you click on the link for the agenda, youll see another view of the sessions for this particular symposium. Note that conferences will often have multiple sessions taking place at the same time, but at different presentation rooms. So we can derive from this little stroll through the NFJS web site that some of the basic entities in a conference management system include a Speaker, a Talk (or Presentation), a Session, a Symposium, and probably a Room. We also have a fairly good understanding of how these types interrelate. We can say that: 1. A conference management system is essentially a list of symposia 2. Each symposium consists of a list of sessions 3. A session is essentially a talk given at a specic location, at a specic time, with a specied duration 4. A Talk is given by a Speaker, who might have an entire portfolio of talks We could also think about how such a software application might assist in the task of planning a new symposium, perhaps with scheduling sessions, printing agenda and other materials needed for the conference.

6.2

Setting up the Project

Setting up our project should be a familiar task by now. The demo application in JMatter that corresponds to this chapter is called Sympster.
$ cd jmatter $ ant new-project-ui ... $ cd ../Sympster

Go ahead and setup your project in your favorite IDE (see section 5.2). We proceed by writing our model classes.

6.3. THE MODEL

65

6.3

The Model

In our analysis, we came up with a list of the primary types we wanted in our system: Symposium, Speaker, Talk, Session, and Room. Lets create a Java package where our classes will reside; proceed by creating a class for each of these types.

6.3.1

Type Icons and Cong File Setup

For each type, we need to: 1. provide a pair of icons, name them <typename>16.png and <typename>32.png, and place them in resources/images 2. for startup ease, specify the fully-qualied type name in src/class-list.json

6.3.2

The Symposium Class

Heres a simple implementation for a Symposium:


package com.u2d.sympster; import com.u2d.model.AbstractComplexEObject; import com.u2d.model.Title; import com.u2d.type.atom.StringEO; import javax.persistence.Entity; @Entity public class Symposium extends AbstractComplexEObject { private final StringEO name = new StringEO(); public Symposium() {} public StringEO getName() { return name; } public Title title() { return name.title(); } public static String pluralName() { return "Symposia"; } }

Were extending the base class AbstractComplexEObject. We dened a single eld so far: the symposiums name. We have a getter method for the name eld, and our title() method. The new bit is the optional implementation of the static method pluralName(). The default derivation of the plural name for Symposium is not intelligent enough in this case so we provide it. Weve already seen how a types plural name is used in JMatters user interface: each entry in the classbar displays it; the titlebar for listings also displays the list item types plural name.

66

CHAPTER 6. A CONFERENCE MANAGER

6.3.3

The Speaker Class

Again, the code here is fairly bare bones:


package com.u2d.sympster; import com.u2d.model.AbstractComplexEObject; import com.u2d.model.Title; import com.u2d.type.atom.StringEO; import com.u2d.type.atom.TextEO; import com.u2d.type.atom.ImgEO; import com.u2d.list.RelationalList; import javax.persistence.Entity; @Entity public class Speaker extends AbstractComplexEObject { private final StringEO name = new StringEO(); private final StringEO title = new StringEO(); private final TextEO bio = new TextEO(); private final ImgEO photo = new ImgEO(); private final RelationalList talks = new RelationalList(Talk.class); public static Class talksType = Talk.class; public static String talksInverseFieldName = "speaker"; public static String[] fieldOrder = {"name", "title", "photo", "bio", "talks"}; public Speaker() {} public StringEO getName() { return name; } public StringEO getTitle() { return title; } public TextEO getBio() { return bio; } public ImgEO getPhoto() { return photo; } public RelationalList getTalks() { return talks; } public Title title() { return name.title(); } }

We see that speakers have a name, title, short biography, and a photo. Speakers also have a portfolio of talks, modeled as a list, or one-many relationship. Since I plan to make this relationship bidirectional (a talk will have a reference to its speaker), I also specied the inverse elds name. We also see the eldOrder metaeld used to specify the display order of a speakers elds. Notice that I could have chosen to use a Name type to represent the speakers name. In this instance I chose to keep the name simple as a single atomic eld.

6.3. THE MODEL

67

6.3.4

The Talk Class

Were still in the process of laying the foundation for our application. Heres the code for our rst pass implementation for a Talk:
package com.u2d.sympster; import com.u2d.model.AbstractComplexEObject; import com.u2d.model.Title; import com.u2d.type.atom.StringEO; import com.u2d.type.atom.TextEO; import javax.persistence.Entity; @Entity public class Talk extends AbstractComplexEObject { private final StringEO title = new StringEO(); private final TextEO talkAbstract = new TextEO(); private Speaker speaker; public static String speakerInverseFieldName = "talks"; public static String[] fieldOrder = {"title", "talkAbstract", "speaker"}; public Talk() {} public StringEO getTitle() { return title; } public TextEO getTalkAbstract() { return talkAbstract; } public Speaker getSpeaker() { return speaker; } public void setSpeaker(Speaker speaker) { Speaker oldSpeaker = this.speaker; this.speaker = speaker; firePropertyChange("speaker", oldSpeaker, this.speaker); } public Title title() { return title.title(); } }

A talk has a title, an abstract, and a reference to its speaker. We see again that toone associations use the JavaBeans bound property conventions and re an event when theyre set.

6.3.5

The Room Class

Here is the implementation:


package com.u2d.sympster; import com.u2d.model.AbstractComplexEObject; import com.u2d.model.Title;

68

CHAPTER 6. A CONFERENCE MANAGER

import com.u2d.type.atom.StringEO; import javax.persistence.Entity; @Entity public class Room extends AbstractComplexEObject { private final StringEO name = new StringEO(); public Room() {} public StringEO getName() { return name; } public Title title() { return name.title(); } }

Nothing new here.

6.3.6

The Session Class

Session is a little more interesting, as it relates Talk and Room entities.


package com.u2d.sympster; import com.u2d.model.AbstractComplexEObject; import com.u2d.model.Title; import com.u2d.type.atom.TimeSpan; import javax.persistence.Entity; @Entity public class Session extends AbstractComplexEObject { private final TimeSpan time = new TimeSpan(); private Talk talk; private Room location; public static String[] fieldOrder = {"talk", "time", "location"}; public Session() {} public TimeSpan getTime() { return time; } public Talk getTalk() { return talk; } public void setTalk(Talk talk) { Talk oldTalk = this.talk; this.talk = talk; firePropertyChange("talk", oldTalk, this.talk); } public Room getLocation() { return location; } public void setLocation(Room location) { Room oldLocation = this.location; this.location = location; firePropertyChange("location", oldLocation, this.location);

6.3. THE MODEL

69

} public Title title() { return time.title().append(":", talk).append(" in", location); } }

Again, very little new here. We have three elds: the talk, the location, and the time span. TimeSpan is yet another basic type provided by the framework. Its a combination of a date-time eld and a duration. You can also think of a time span as having both a start time and end time elds. Actually, this is how its default renderer and editor depict it. The title() method is also somewhat interesting as it attempts to concatenate the time span along with the talks title and location title.

6.3.7

A First Look

I realize that Ive been rushing through this a little. We could have easily written one class at a time and each time ran our application, thus building our application more incrementally. This in fact is a very good practice and a highly recommended one. Feel free not to follow me to the letter here. Lets take our rst-draft for a spin:
$ ant schema-export $ ant run

Log in using the admin/admin credentials and you should see a screen similar to gure 6.1.

70

CHAPTER 6. A CONFERENCE MANAGER

Figure 6.1: First Look at our Conference Manager Lets go ahead and exercise our objects a little. Go ahead and create a Symposium, give it a name and save it. Similarly, create a room. Then go ahead and create a speaker and assign him or her a photo. Since a speaker has a list of talks, you can create and associate a talk to your speaker very simply by clicking the plus (+) icon, which is a popup menu, and selecting the New action, and then entering the information about the talk. The association will be made for you automatically. Alternatively, you can create a talk separately and then drag and drop the talk onto the speakers talks listing. Figure 6.2 is a snapshot of my screen after creating a speaker and a talk.

6.3. THE MODEL

71

Figure 6.2: A Speaker and Associated Talk Now that we have created a talk and a room, go ahead and create a session object. The timespan can be edited by specifying the date and start and end times. Notice that the date editor provides a date picker to facilitate entry. The time editors likewise attempt to facilitate entry by providing small spinner arrows for incrementing and decrementing the hour and minute elds. To associate a talk and a room, again you have two choices: 1. Drop a talk onto the talk eld of the session object (and similarly for the location eld, drop a room object), or 2. Right-click Browse, Find, or New to browse and select an existing talk to associate to this session, to query for and select a talk, or to create a new talk and then associate it to the session in question Here is a snapshot of my screen after creating and setting a session:

72

CHAPTER 6. A CONFERENCE MANAGER

Figure 6.3: Creating and associating a Session

6.4

Enhancements

Lets get back to our code and make a few additions, enhancements.

6.4.1

Type Color Coding

Heres a useful piece of metadata to help distinguish between different types of objects in our system: color-coding. Heres an example of how to specify this metadata:
public static Color colorCode = new Color(0xffff00);

Just add the above line to any of your model classes (Room, Talk, Speaker, and so on) using a different color value for each, of course. The titlebar for each object will automatically be painted with a gradient background that starts with the specied color. Also, type listings paint the background color of alternating lines

6.4. ENHANCEMENTS

73

using that color code combined with a semi-transparent alpha value. This should help users quickly distinguish various listings or types of objects in your user interface.

6.4.2

Speakers Photo for Speaker Icon

We have a nice little icon representing a speaker. However, we have an even nicer one, and one that could help distinguish between speakers: their photo. Cant we simply use the speakers photo as the basis for that instances icon? Certainly. Heres the magic bit of code:
private transient PhotoIconAssistant assistant = new PhotoIconAssistant(this, photo); public Icon iconLg() { return assistant.iconLg(); } public Icon iconSm() { return assistant.iconSm(); }

JMatter provides a class named PhotoIconAssistant that you simply instantiate, passing in a reference to the containing object, and to the photo eld in question. Then simply override the superclasss iconLg() and iconSm() methods and delegate the work to your assistant. Pretty simple.

6.4.3

A Second Look

Lets check out our application with the changes in place.


$ ant run

I went ahead and created a few Speaker instances so wed have something to look at. Figure 6.4 shows two views of the speakers listing along with a maximized view of Jason Hunter, a long-time NFJS speaker.

74

CHAPTER 6. A CONFERENCE MANAGER

Figure 6.4: Speaker Icon using Photo Property By opening other listings and other types of instances we can also quickly see the color-coding in effect. These are small, nice, and valued enhancements to our user interface.

6.5

Calendaring

One of the main tasks of managing conferences (or symposia, as theyre called here) is scheduling them, determining what sessions will be offered: where and when talks are to be given. What will it take to build these features into our application? Lets begin by studying the way JMatter models calendaring.

6.5.1

How JMatter Models Calendaring

The JMatter framework denes three main types of objects that work together to provide calendaring features:

6.5. CALENDARING

75

1. Calendar Events These are basically items that one puts on a calendar. A meeting is a calendar event, for example. A visit between a physician and a patient is another example. Heres a third example: a session at a conference. 2. Resources, or Schedulables As its name implies, a Resource is something that can be occupied or consumed for a span of time. In our example, a room where a presentation is given is a resource. In the code, JMatter calls them schedulables. In a physicians clinic, the physician becomes the resource. 3. Grouping of Resources, or Calendarables Finally, its important to get a view of how multiple resources are utilized in time. Wed like to be able to see what sessions are going on at the same time in six different rooms, so we can pick which presentation we want to attend, for example. A nurse would like to see which physicians are available during a specic block of time, and so on. So in our system, the Calendar Events are our Sessions, the resource is the Room, and nally our Calendarable is the Symposium. We can have many symposia and so each one will have its own calendar. Each room will have its own schedule. Technically, we need to extend our model to make this work in the eld: symposia can take place in different venues. One could take place at a hotel in New York City, another at a convention center in San Francisco, and a third could be taking place at a university campus in Austin. Each venue would then have its own list of rooms where presentations are held. For now were going to keep the venue constant. Well extend the model to support multiple types of venues in section 6.6. JMatters calendaring model can be found in the package com.u2d.calendar

6.5.2

Enhancing Sympster to Support Calendaring

Ok, lets get to the code. Here is the simplest way to introduce calendaring to our application. Now that weve identied the relative roles of Session, Room, and Symposium and how they map to JMatters model for calendaring, we can proceed to enhance our code base. Lets start with Session. 6.5.2.1 Enhancing Session

We need to: 1. make session a subclass of CalEvent;

76

CHAPTER 6. A CONFERENCE MANAGER

2. implement the contract for CalEvent. The rst revision is easy:


public class Session extends CalEvent

The second is pretty easy too:


public static String timespanFieldname = "time"; public static String schedulableFieldname = "location"; public Title calTitle() { if (talk == null) return new Title("--"); else return talk.title(); }

Were required to provide the name of the eld in the class Session that corresponds to its timespan, so that JMatter knows how to display sessions in a calendar or a schedule widget. The name of this eld happens to be time. Likewise, our calendar will display calendar events for different resources, so we also need to provide the name of the schedulable eld on Session: location. The third requirement, the calTitle() method could have been made optional but it is required by JMatter at the moment. It gives you a chance to specify a title for a Session object that is more appropriate in the context of a calendar. For example, the calendar will make obvious the time and duration and location of the session, so you might not want to repeat that information in the title. In this case, we specify the talks title as the calendar-context title for Session. Thats it for Session. Lets look at Room next. 6.5.2.2 Enhancing Room

We need to: 1. make Room a subclass of ScheduleEO; 2. implement the contract for ScheduleEO. Here they are:
public class Room extends ScheduleEO

6.5. CALENDARING

77

And:
public Class eventType() { return Session.class; }

Pretty easy? We specify that events in Rooms are of type Session. 6.5.2.3 Enhancing Symposium

Here again, we need to: 1. make Symposium a subclass of CalendarEO; 2. implement the contract for CalendarEO. The rst change:
public class Symposium extends CalendarEO

And for the second, add this code:


public AbstractListEO schedulables() { return ComplexType.forClass(Room.class).list(); } public Class defaultCalEventType() { return Session.class; }

We implement the method schedulables(), which returns a list of all the resources that this calendar maintains. If each symposium had its own venue, the implementation would simply have been:
return getVenue().getRooms();

In our case, we decided to keep our venue constant so we return the entire list of rooms. The second requirement is to provide the default calendar event type, which again is Session. Thats it. Were done.

78

CHAPTER 6. A CONFERENCE MANAGER

6.5.3

A Third Look

Lets look at what we get in return for our efforts.


$ ant run

Browse the list of symposia you created and right-click the command Show Calendar. This command was inherited by CalendarEO. We see a calendar widget, similar to the one shown in gure 6.5.

Figure 6.5: Symposium Calendar, along with a few Sessions Feel free to explore this widget. It has a few useful features: 1. A week view and a day view 2. The ability to view the calendar using a time resolution of 15 minutes, 30 minutes, or 60 minutes per row 3. The ability to navigate to the next day or week by clicking on the navigation arrows (in day view, youll be navigating to the next or previous day, in week view, youll be navigating to the next or previous week)

6.5. CALENDARING

79

4. A mini month calendar, for quickly navigating to a specic date in another month or year 5. A date navigation text eld, to quickly navigate to a specic date by simply entering it and pressing enter (e.g. 10212004 will take you to Oct 21 2004) 6. The ability to toggle any schedule on or off the calendar 7. You can create a new session at a specic time and location by doubleclicking on a cell in day view 8. You can create a new session at a specic time and location, with a specic talk by simply dropping a talk onto a cell in day view 9. You can alter the default session duration by right-clicking on the Session classs (in the class bar) Set Default Duration Hrs command. 10. You can alter the time or location of a session by simply dragging it onto another cell 11. You can open an existing session by double clicking on its representations titlebar in the calendar 12. You can invoke any commands on a session displayed in the calendar by right-clicking on its titlebar I think youll agree that here again, JMatter provides tremendous leverage. The designers of the JMatter framework are reusing this calendar across different applications that span entirely different business domains. As the features of this calendar improve, all JMatter applications will inherit these improvements. One more time we ask you to compare the effort required to build such a feature traditionally into an existing software application and what it took to integrate scheduling into Sympster here.

6.5.4

Inheritance vs Interfaces

In order to gain the benets of calendaring, we had to extend existing classes in our system. Luckily, our Session, Room, and Symposium did not already extend another base class. Designing by inheritance has its problems in a world where multiple inheritance is not supported. But you dont have to be locked in to it. It turns out that JMatter does not require that you extend ScheduleEO or CalendarEO to obtain these benets. You can implement the Calendarable and Schedulable interfaces directly yourself and they really dont require that much effort. Have a look at the source code for CalendarEO and ScheduleEO. They do very little indeed. All they do is instantiate a Calendar and Schedule object respectively, and expose an accessor method on it. Thats basically it.

80

CHAPTER 6. A CONFERENCE MANAGER

At the moment, the same cannot be said about a CalEvent. We are required to subclass CalEvent. As we rene JMatters calendaring feature further, we expect this requirement to be removed1 .

6.6

Inheritance-Based Polymorphism

Lets discuss how we would revise our application to accommodate symposia with different venues: 1. Dene a new eld on Symposium called venue The goal is for a venue to be a base type for multiple specializations, such as a Hotel, a Conference Center, or a Campus (each of these three would be concrete implementations of a Venue) 2. Dene the base type Venue At the very least, a venue should have a name and a list of rooms. So Venue would likely include two methods: getName() and getRooms() 3. Revise the implementation of Symposium.schedulables() to return venue.getRooms() 4. Update our schema 5. Possibly add one or more of these new types to one of our Class Bar subfolders (or edit the Class Bar directly from the GUI) This particular situation lends itself nicely to implementing polymorphism via inheritance. Heres what Venue might look like:
public abstract class Venue extends AbstractComplexEObject { protected final StringEO name = new StringEO(); protected final RelationalList rooms = new RelationalList(Room.class); public static Class roomsType = Room.class; public StringEO getName() { return name; } public RelationalList getRooms() { return rooms; } public Title title() { return name.title(); } }

Pretty simple really. We can now extend Venue for Hotel, Campus, and ConferenceCenter. Here is Hotel:
1 One area worth researching JVM-compatible programming languages which support features such as mixins or traits

6.6. INHERITANCE-BASED POLYMORPHISM

81

public class Hotel extends Venue { public Hotel() {} }

Hotel is ready to be extended with specialized behaviours. We can similarly dene Campus and ConferenceCenter. We can distinguish these three types by the icon we choose to represent each type. Finally, here are the changes Ive made to Symposium:
private Venue venue; public Venue getVenue() { return venue; } public void setVenue(Venue venue) { Venue oldVenue = this.venue; this.venue = venue; firePropertyChange("venue", oldVenue, this.venue); } public AbstractListEO schedulables() { // return ComplexType.forClass(Room.class).list(); return venue.getRooms(); }

We need to synchronize our database to the model changes weve made:


ant schema-update

In this particular case, JMatter generates hibernate mapping les using the joined subclass inheritance mapping strategy. And we should be ready to check out our application:
$ ant run

I added Venue to the class list. Remember that Venue is an abstract base type. Figure 6.6 shows two things: 1. Right-clicking Browse on Venues in the Class Bar will perform a polymorphic query and return a listing including hotels, campuses, and conference centers.

82

CHAPTER 6. A CONFERENCE MANAGER

2. Right-clicking New on Venues will prompt the user to select which concrete type they would like to instantiate. This is baked in to the user interface. When associating a venue to a symposium, right-clicking New, Browse, or Find on the symposiums venue association eld will do the right thing.

Figure 6.6: Sympster Extended with Venues JMatter supports both inheritance-based polymorphism (as shown in this example) and interface-based polymorphism.

6.7

Interface-Based Polymorphism

We are taught that interface-based modeling is preferred over models that do not employ interfaces. I concur. Id like to demonstrate how to do interface-based modeling in JMatter. As an illustration, lets extend our Sympster application further. Right now, we can dene a symposium, speakers, their talks, and we can schedule sessions. A session is dened as a talk given at a specic date and time, and with a specic duration, at a specic location.

6.7. INTERFACE-BASED POLYMORPHISM

83

Id like to broaden the denition of a session to include events other than speakers presentations. What about BOFs (Birds of a Feature session) for example? Or maybe a panel discussion including a number of participants. At NFJS symposia, we actually hold informal BOFs with 2-3 participants where we discuss a particular topic. Lets walk through the code. The rst thing I do is dene the interface Event:
public interface Event extends ComplexEObject { public StringEO getTitle(); }

Were basically going to require that each event provide a title. Talk already does and BOFs will too. I still want to dene this interface as it serves as a mechanism for qualifying event types. Next, lets go ahead and dene a new object to model a BOF:
public class BOF extends AbstractComplexEObject implements Event { private final StringEO title = new StringEO(); private final RelationalList participants = new RelationalList(Speaker.class); public static Class participantsType = Speaker.class; public static String[] fieldOrder = {"title", "participants"}; public BOF() { } public StringEO getTitle() { return title; } public RelationalList getParticipants() { return participants; } public Title title() { return title.title().append(" with", participants); } }

Finally, lets retrot our existing class Talk:


$ svn diff -r83:84 Talk.java Index: Talk.java =================================================================== --- Talk.java (revision 83) +++ Talk.java (revision 84) @@ -7,7 +7,7 @@ import com.u2d.reflection.FieldAt;

84

CHAPTER 6. A CONFERENCE MANAGER

import java.awt.Color; -public class Talk extends AbstractComplexEObject +public class Talk extends AbstractComplexEObject implements Event { private final StringEO title = new StringEO(); private final TextEO talkAbstract = new TextEO();

As you can see from the above diff, all I had to do was specify that Talk implement Event. Finally, remaining is broadening Sessions denition. Rather than dene an association to a Talk, well revise that to be be an association to an Event. I wont show you all the edits. Heres the gist of the change:
- public Talk getTalk() { return talk; } - public void setTalk(Talk talk) + public Event getEvent() { return event; } + public void setEvent(Event event)

And thats it. Now lets take a look at how these changes manifest themselves in our application:

Figure 6.7: Polymorphic Queries: Listing Events

6.7. INTERFACE-BASED POLYMORPHISM

85

JMatter models the polymorphic association using Hibernates implicit polymorphism mechanism, otherwise known as *any* associations.

Figure 6.8: Polymorphic Instantiation: Creating a new Event JMatter will prompt the user whether they wish to create a talk or a BOF.

86

CHAPTER 6. A CONFERENCE MANAGER

Figure 6.9: Events Calendar We see two events on this calendar. The rst is a talk on JMatter, and the second is a BOF on Programming. :-)

6.8

Summary

I hope you enjoyed this chapter. We didnt have to work too hard and yet we developed a fully-functional conference manager. In summary, new features of JMatter covered in this chapter include: 1. type color coding, 2. using an image eld as the basis for an instances icon, 3. calendaring, and 4. polymorphism, using either inheritance or interface-based modeling Lets do our due diligence once again and get a feel for the amount of leverage we derived from JMatter in this application:

6.8. SUMMARY

87

~/work/jmatter-complet/demo-apps/Sympster/src/com/u2d/sympster$ wc -l *.java 29 BOF.java 9 Campus.java 9 ConferenceCenter.java 17 Event.java 9 Hotel.java 28 Room.java 54 Session.java 64 Speaker.java 56 Symposium.java 38 Talk.java 21 Venue.java 334 total

Not bad. If youre not convinced by now of the implications of this new mode of developing software, this might be a good time to pick up another book :-). In the next chapter were nally going to take a look at the Issue Manager demo application, the one referenced in the introduction. Well be focusing on JMatters support for objects with lifecycles.

88

CHAPTER 6. A CONFERENCE MANAGER

Chapter 7

Issue Manager
In this chapter, were going to discuss JMatters support for business objects with lifecycles. Were going to write an Issue Manager, a familiar application for software developers who use such systems to help manage the development of software. Examples of issue managers include Bugzilla, Trac, and JIRA.

7.1

Analysis

The central type in this application is the Issue. The interesting aspect of issues is that they have a life cycle. An Issue is created and assigned to a developer. The developer accepts the issue and begins working on a x. After resolving the issue, the person who opened the issue veries that the resolution is indeed satisfactory, and proceeds to close the issue. If the issue is not resolved to satisfaction, the issue can be reopened. Its also important to keep some kind of trail of activity: who opened the issue? Who resolved it and when? An end user should have the ability to attach notes to an issue, to specify a description of the issue, steps to reproduce the problem (if applicable). The main trait of objects with life cycles is that their behaviour depends on their state. For example, one cannot attempt to accept an issue if its already been closed. We can identify the various states for an Issue, and dene its lifecycle with the aid of state diagrams, transition tables, etc.. Software developers will typically model such objects using the State Design Pattern1 . I have decided to model an Issue with ve states:
1 The

State Pattern is documented by the Gang of Four in their book, Design Patterns

89

90

CHAPTER 7. ISSUE MANAGER

1. New 2. Assigned 3. Accepted 4. Fixed 5. Closed In a normal ow, an issue moves sequentially through these states. An issue is created (New state), then assigned to a developer (Assigned state), and accepted by the developer (Accepted state). The person who opened the issue has the option of rejecting the x (in which case its state reverts to Accepted) or approving it, moving Issue to the Closed state. An issue can also be reassigned to a different developer.

7.1.1

Modeling States in Java

In Java, the State pattern is often and conveniently modeled using inner classes. Each state is implemented as an inner class which controls the behaviour of the Context object (in this case, Issue) when in that state. Also, many texts encourage the design to use static inner classes for improving the performance of the system. That is, rather than create an instance of each inner class per Issue, a single instance of each inner class exists for all issues. The issue that is to be operated upon is passed in as an argument to that inner classs methods. Although theres no denying the improvement in memory requirements, I personally nd this design less than ideal, from an object-oriented point of view. I nd it akin to removing the implicit this keyword in instances and passing a reference to self with each method.

7.2

Getting Started

Were about to start building our fourth application. Since weve done this together three times already, Im not going to walk you through the steps of creating a new project and conguring it Please refer to previous chapters for specic instructions. I named my application IssueMgr. Ok, we need to model Issue. As a rst pass, lets not worry right away about the various states we identied in the previous section. Lets instead start be dening the various properties we want an issue to have. Here are the properties Ive come up with:

7.2. GETTING STARTED

91

private final StringEO _title = new StringEO(); private final TextEO _description = new TextEO(); // a loose definition (using a numeric value instead of an enumeration) private final IntEO _priority = new IntEO(); private final IntEO _severity = new IntEO(); private Issue _dependsOn; private final RelationalList _notes = new RelationalList(Note.class); public static Class notesType = Note.class; private User _openedBy; private User _assignedTo; private final RelationalList _history = new RelationalList(LoggedEvent.class); public static Class historyType = LoggedEvent.class;

An issue then will have a title and a detailed description. Note how the description eld is dened as a TextEO which causes it to be rendered using a text area, and saved as in the database as a large text type. Ive decided for a rst-pass to keep severity and priority really simple, as numeric values. The next one: dependsOn is interesting and fairly self-explanatory. It will give us the knowledge that Issue A will not be resolved before the issue it depends on (say Issue B) is resolved, for example. The next eld, notes, will allow us to tack on notes to an issue (as many notes as we want in fact). A Note is yet another predened type in JMatter. It has a subject, a time stamp, an author, and the note text itself. When creating a note, the author is automatically assigned to the user who is currently logged in. The next two elds, openedBy and assignedTo are self-explanatory. The last eld is an interesting one. The idea is that Id like to keep track of the history of an issue: when was it opened, assigned, accepted, xed, etc.. Furthermore, when an issue is xed, i want to require the developer to enter both a summary description of the x and a lengthier one. I want to capture that information. After thinking about this for a little while, I realized that JMatters built-in LoggedEvent type would be a perfect candidate for recording this information. Its already designed to hold precisely this type of information. It has a timestamp, a message, long message, it records the user who performed the action, it can even record what action was performed, and nally, has an association back to the object upon which the operation was performed. In the context of the issue manager, well be able to navigate from a log entry (with message Issue xed at 4:30 pm) back to the issue it is associated to. Ok, it looks like we have a fairly complete list of elds to start with. Of course, its not enough to just dene these elds, the JMatter conventions must be followed: dene accessor methods for aggregate types and both accessors and mutators for association types, following the JavaBeans bound property convention.

92

CHAPTER 7. ISSUE MANAGER

public StringEO getTitle() { return _title; } public TextEO getDescription() { return _description; } public IntEO getPriority() { return _priority; } public IntEO getSeverity() { return _severity; } public Issue getDependsOn() { return _dependsOn; } public void setDependsOn(Issue issue) { Issue oldValue = _dependsOn; _dependsOn = issue; firePropertyChange("dependsOn", oldValue, _dependsOn); } public RelationalList getNotes() { return _notes; } public User getOpenedBy() { return _openedBy; } public void setOpenedBy(User user) { User oldValue = _openedBy; _openedBy = user; firePropertyChange("openedBy", oldValue, _openedBy); } public User getAssignedTo() { return _assignedTo; } public void setAssignedTo(User user) { User oldValue = _assignedTo; _assignedTo = user; firePropertyChange("assignedTo", oldValue, _assignedTo); } public RelationalList getHistory() { return _history; }

Here is the context within which all this code is written:


@Entity public class Issue extends AbstractComplexEObject { public static String[] fieldOrder = {"title", "description", "notes", "openedBy", "assignedTo", "history", "severity", "priority"}; public Issue() {} ... public Title title() { return _title.title().appendParens(""+getID()); } }

We added the familiar eldOrder metadata and the required title() method. Since it is customary to refer to issues by some unique numeric ID, Im exposing the

7.3. MODELING ISSUES LIFECYCLE

93

issues ID property in its title. This property is inherited from AbstractComplexEObject. We normally do not edit src/persistClasses.st by hand: the @Entity annotation takes care to add Issue to the list automatically. However here were using a predened entity Note and for it we do need to manually add an entry to our persistClasses.st le, like so:
.. <value>com.u2d.type.composite.Note</value> ..

We can now generate and export our schema, run the application and create a few issues.

7.3

Modeling Issues Lifecycle

The time has come to model issues lifecycle. There are a number of concerns here. The rst is keeping track of the state of our issue. And more specically, to ensure that when an issue is persisted to the database, that its state is remembered and properly restored at a later point in time. A simple way to do this is to dene yet another eld to hold the name of the state. This eld will be persisted to the database just like Issues other elds, and can be the basis for restoring Issues state when reloading issues from the database.
private final IssueState _status = new IssueState(NEW);

Where NEW is one of a number of static string-based constants:


static final String NEW = "New"; static final String ASSIGNED = "Assigned"; static final String ACCEPTED = "Accepted"; static final String FIXED = "Fixed"; static final String CLOSED = "Closed";

We have identied ve states and theyre not likely to change. JMatter provides a mechanism for modeling enumerations by extending the JMatter type ChoiceEO. Here is the implementation of the contract to dene the IssueState enumeration:

94

CHAPTER 7. ISSUE MANAGER

public class IssueState extends ChoiceEO { public IssueState() {} public IssueState(String value) { setValue(value); } private static Set STATUS_OPTIONS = new HashSet(); static { STATUS_OPTIONS.add(Issue.NEW); STATUS_OPTIONS.add(Issue.ASSIGNED); STATUS_OPTIONS.add(Issue.ACCEPTED); STATUS_OPTIONS.add(Issue.FIXED); STATUS_OPTIONS.add(Issue.CLOSED); } public Collection entries() { return STATUS_OPTIONS; } }

Nothing too interesting really. We also must remember to add an accessor method for status:
public IssueState getStatus() { return _status; }

7.3.1

Dening the State Inner Classes

Below Ive dened ve inner classes, one for each of the states that Issue can be in.
public class NewState extends ReadState {} public class AssignedState extends ReadState { @Cmd(mnemonic=a) public void Accept(CommandInfo cmdInfo) { transition(_acceptedState, makeLog("Issue accepted by developer")); } } public class AcceptedState extends ReadState { @Cmd public void Fix(CommandInfo cmdInfo, @Arg("Fix") StringEO fix, @Arg("Description") TextEO description)

7.3. MODELING ISSUES LIFECYCLE

95

{ transition(_fixedState, makeLog("Fix: "+fix.stringValue(), description)); } } public class FixedState extends ReadState { @Cmd public void RejectFix(CommandInfo cmdInfo, @Arg("Explanation") TextEO explanation) { transition(_acceptedState, makeLog("Fix rejected", explanation)); } @Cmd public void Close(CommandInfo cmdInfo, @Arg("Explanation") TextEO explanation) { transition(_closedState, makeLog("Issue Closed", explanation)); } } public class ClosedState extends ReadState {}

Notice that the convention for dening commands on these states is the same as the mechanism used for dening commands in general. The difference is that JMatter will ensure that these commands are accessible in a valid state. The @Arg annotations values are a means of specifying the captions used to prompt the end user for each of the method parameters. Although weve dened the classes, we must also create an instance for each:
private transient final State _newState, _assignedState, _acceptedState, _fixedState, _closedState; { _newState = new NewState(); _assignedState = new AssignedState(); _acceptedState = new AcceptedState(); _fixedState = new FixedState(); _closedState = new ClosedState(); _stateMap.put(_newState.getName(), _newState); _stateMap.put(_assignedState.getName(), _assignedState); _stateMap.put(_acceptedState.getName(), _acceptedState); _stateMap.put(_fixedState.getName(), _fixedState); _stateMap.put(_closedState.getName(), _closedState); }

96

CHAPTER 7. ISSUE MANAGER

In addition to instantiation, Ive also added each state to a map, dened in Issues superclass. At the moment, this is a requirement of the framework. We havent yet specied the starting state, so lets do that:
public State startState() { return _newState; }

We also need to provide a mechanism for the Issues state to be restored after an issue is fetched from the database:
public State restoredState() { return (State) _stateMap.get(getStatus().code()); }

Both of these are really simple. Here we see that we use the value of the issues status (which was fetched from the database) as a means to fetch the state object from the state map. I have not yet showed you the support code for the transitions. In each state where a command is dened a transition takes place. A logged event is created and passed in to the method named transition(). Heres how I create the logged event:
private LoggedEvent makeLog(String msg) { LoggedEvent evt = (LoggedEvent) createInstance(LoggedEvent.class); evt.getMsg().setValue(msg); evt.getType().setValue(LoggedEvent.INFO); evt.setUser(currentUser()); evt.setObject(this); return evt; } private LoggedEvent makeLog(String msg, TextEO longMsg) { LoggedEvent evt = makeLog(msg); evt.getLongMsg().setValue(longMsg); return evt; }

I provide two utility methods for constructing logged events. The rst does not require a long message, the second is an overloaded version that also sets the long message. Notice how commands such as Fix, Close and RejectFix specify arguments. Recall that JMatter automagically prompts the end user for these arguments in the user interface and then feeds them to the commands when invoking their methods. These values are then passed in to the makeLog() methods. Finally, here is the implementation of the transition() method:

7.4. PER-STATE ICONS

97

private void transition(State state, LoggedEvent evt) { _history.add(evt); setState(state, true); _status.setValue(state.getName()); persistor().updateAssociation(this, evt); }

We see here that the logged event is added to the history eld, the state transition takes place, the status eld is updated accordingly (kept in sync with the issues state). The nal statement ensures that the updated issue and its association to the newly created logged event are saved to the database.

7.4

Per-State Icons

Up until now, youve been told that for each type of object you dene, that JMatter will look for an image le with a specic naming convention to use to represent objects of that type. This is true, but its not the whole story. Lets take an example. For the class Issue, we provide Issue32.png and Issue16.png. However, youre also free to provide additional icons, one for each state: IssueAssigned32.png, IssueAccepted32.png, etc.. So we see here an extension of the convention. For objects with lifecycles, the icon can be made to further reect the state of the object youre viewing. I have specied custom icons for each of Issues ve states. Heres (gure 7.1) a screenshot of the icons in my resources/images directory, along with their corresponding le names.

98

CHAPTER 7. ISSUE MANAGER

Figure 7.1: State-Specic Icon Support

7.5

Additional Metadata

Weve dened a number of commands, such as Fix(CommandInfo cmdInfo, StringEO x, TextEO description). We customized the captions for the two arguments x, and description so the end user is clear about what information he or she will have to enter. We did this by annotating the methods arguments with @Arg annotations, like this:
public void Fix(CommandInfo cmdInfo, @Arg("Fix") StringEO fix, @Arg("Description") TextEO description)

The annotation takes a single argument, the parameter caption. Theres a second, much more important issue that needs to be addressed though. In the case of our issue manager application, its not enough that the command

7.6. A FEW LOOSE ENDS

99

accept be only accessible in Assigned state. Only the developer who has been assigned the particular issue should be allowed to accept the issue. The same applies to the x command. For rejectFix and close, the same idea applies: only the user who opened the issue should be allowed to close it, not the developer. JMatter provides a means to specify what user is the owner of a command. A commands owner is the only user who will be allowed to invoke it. JMatter will not even display the commands views (a button or a menu item) to any other user. Heres how this is done:
static { ComplexType type = ComplexType.forClass(Issue.class); type.command("Accept", AssignedState.class).setOwner(type.field("assignedTo")); type.command("Fix", AcceptedState.class).setOwner(type.field("assignedTo")); type.command("RejectFix", FixedState.class).setOwner(type.field("openedBy")); type.command("Close", FixedState.class).setOwner(type.field("openedBy")); }

I hope youll agree this is fairly terse, yet clear and legible code. The last line, for example, interprets to the owner for the command named Close (in Fixed state) is the value of the issues openedBy eld. In other words, whoever opened the issue is the one authorized to close it.

7.6
7.6.1

A Few Loose Ends


Default Assigned-To Developer

It sure would be nice if each time I created a new issue, a certain developer would be the default user assigned to the issue. One way to do this is to specify the default in the le resources/model-metadata.properties, like this:
# Issue.assignedTo.default=from User as user where user.username=eitan

Weve already used this le to specify eld metadata such as whether and which elds are required. Here were specifying a default. We can either hard-code it, or specify any valid hql (hibernate query language) that will return an instance of a valid type.

100

CHAPTER 7. ISSUE MANAGER

7.6.2

Automatically Setting OpenedBy

Each time we create an issue, the person who opened the issue is by denition the currently logged in user. How do we programmatically specify that this should automatically happen? Here is one way to do this:
public void onBeforeCreate() { super.onBeforeCreate(); setOpenedBy(currentUser()); }

This method overrides a superclass method, one that is notied prior to the creation of an object. It turns out that persistent objects (such as Issue) are not the only ones that can listen to various object persistence lifecycle events. JMatter provides a generic notication mechanism that any object can take advantage of. Each type of event is dened by a string constant, such as DELETE, SAVE, BEFORECREATE, CREATE. Youll see an example use of this mechanism shortly. Its also worth noting that besides object persistence events, JMatter provides hooks for application events such as login and logout events.

7.6.3

Transitioning to AssignedState

You might have noticed that I have left a glaring omission: how exactly does an issue transition to assigned state? The transition should take place when a user is associated to the assignedTo property of Issue. We need to be careful here. The setter method is called not only when an association is made but also when the object is restored from the persistence store (the database). To distinguish between these two contexts, JMatter allows the denition of an additional method, the associate method. It works like this: if both a setter and an associator are dened, JMatter will make sure to call the associator only when associating (calling only the setter when restoring the property from db). Heres the implementation:
public void associateAssignedTo(User user) { setAssignedTo(user); if (_assignedTo != null && !_assignedTo.isEmpty()) { if (isEditableState())

7.7. ISSUE CATEGORIES

101

{ addAppEventListener(ONCREATE, new AppEventListener() { public void onEvent(AppEvent appEvent) { transition(_assignedState, makeLog("Assigned to "+_assignedTo)); } }); } else { transition(_assignedState, makeLog("Assigned to "+_assignedTo)); } } }

This code looks a little complicated. It has to concern itself with a specic issue. A call to the transition() method has the side effect of saving everything and putting the object in read state. We want to delay the call to transition if the association is made while the issue is in an editable state (before it has been saved, while its being edited). Im resorting to using JMatters application event notication mechanism. If the association is made in read state, I simply transition. Otherwise, I delay transitioning until after the editing is complete.

7.7

Issue Categories

Our implementation of Issue is now complete. Lets add one last feature. It might be helpful to dene various categories of issues and classify issues according to these categories. The rst thing we do is dene an issue category type:
@Entity public class IssueCategory extends AbstractComplexEObject { private final StringEO _name = new StringEO(); public IssueCategory() {} public StringEO getName() { return _name; } public Title title() { return _name.title(); } }

102

CHAPTER 7. ISSUE MANAGER

Nothing fancy here. An issue category is dened to have a single eld: a name. Rather than dene a to-many relationship to issue, Im going to add a command that will fetch the categorys issues from the database and return a paged list:
@Cmd public Object Issues(CommandInfo cmdInfo) { ComplexType type = ComplexType.forClass(Issue.class); FieldPath path = new FieldPath("com.u2d.issuemgr.Issue#category"); QuerySpecification spec = new QuerySpecification(path, new IdentityInequality().new Equals(), this); SimpleQuery query = new SimpleQuery(type, spec); return new PagedList(query); }

Im not entirely satised with the implementation. Id like to be able to use plain old hql or the hibernate API to dene this query. The above uses JMatters own API for dening queries, which basically says: fetch all issues where the category equals this. On the issue side, we need to add a to-one association to the issue category:
private IssueCategory _category; public IssueCategory getCategory() { return _category; } public void setCategory(IssueCategory category) { IssueCategory oldValue = _category; _category = category; firePropertyChange("category", oldValue, _category); }

We also need to update our eldOrder metaeld:

public static String[] fieldOrder = {"status", "title", "description", "notes", "openedBy", "assignedTo", "history", "severity", "priority", "category"};

Thats it for the coding. Make sure to update the schema and lets run the application.

7.8. THE APPLICATION

103

7.8

The Application

Just because we nished coding does not mean that were done conguring our application. For example, it might be useful to dene a few standard queries such as List Outstanding Issues and List Closed Issues that pre-lters the listing (using JMatters Smart List mechanism). Figure 7.2 below shows the issue manager in action. Im listing all issues to illustrate how the issues icon reects its state (the ones with a lock are closed issues, the ones with the pencil are accepted, and supposedly, being worked on). Im also showing two smart lists that Ive created and that I often use to check out outstanding issues.

Figure 7.2: The Issue Manager I also often view issues in tabular view, which allows me to sort issues by priority or severity (sorting is invoked by clicking on the table column header).

104

CHAPTER 7. ISSUE MANAGER

7.9

Summary

As in previous chapters, allow me to show you the stats for this application, in terms of lines of code:

eitan@ubuntu:~/projects/ds/IssueMgr/src/com/u2d/issuemgr$ wc -l *.java 40 IssueCategory.java 232 Issue.java 28 IssueState.java 300 total

Three classes totaling 300 lines of code. The current state of lifecycle support in JMatter is pretty strong. Its implementation is a natural extension of the conventions already established for simpler business objects. Nevertheless, I believe the implementation can be streamlined further and place even less requirements on the developer. For example the requirement to add the various states to a state map could be done by the framework. In summary, support for business objects lifecycle is a necessary component of supporting the development of business applications in general. Many business objects naturally embody lifecycles, including orders (new, conrmed, fullled, etc..), visits (scheduled, canceled, conrmed, ongoing, archived), etc.. We have now covered four distinct applications: a contact manager, the MyTunes application, the Sympster conference manager, and nally our issue manager in a very short time. JMatter also comes with a movie library application, that, among other things, illustrates many-to-many relationships, as well as two other demonstration applications that illustrate how to integrate custom views into your application (the topic of chapter 14 on page 171). Lets now turn our attention to part III on the facing page, which covers the JMatter framework in detail.

Part III

Framework Reference

105

Chapter 8

Dichotomy of a Model Object


Lets begin by taking a look at a very simple model for a Person:
package com.u2d.contactmgr; import ... @Entity public class Person extends AbstractComplexEObject { private final StringEO name = new StringEO(); public Person() { } public StringEO getName() { return name; } @Cmd public String SayHello(CommandInfo info) { return "Hi"; } public Title title() { return name.title(); } }

We see that: 1. At the most basic level a class denition consists of data and behaviour, implemented as elds and commands (or methods), known as the types members. 2. JMatter relies heavily on conventions for the purpose of inferring information about a type. Here are some of the conventions: 1. Our class must extend the base type AbstractComplexEObject. This base class is a partial implementation of the ComplexEObject interface.

107

108

CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

2. We have a eld, the persons name, dened via a private variable but inferred from a getter method 3. We have a command, Say Hello, implemented of course as a method. 4. Every type must also provide an implementation of the method title(), which in a sense denes instances labels, or captions in the applications user interface. The Title class exists simply to facilitate the task of constructing a title when we wish those titles to be constructed by concatenating various eld values. 5. We use the @Entity annotation to mark the type as one that we want to persist to database. 6. We mark a method with the @Cmd annotation to indicate that we wish to expose this method to the user interface. There exist a number of subtleties too. Here are some examples: 1. For command methods that return a String, the returned string is implied to be a message returned by the action that JMatter will display to the user. 2. Commands can accept arguments (Ill have more to say about that later). 3. Type commands can be dened by marking the method as static. 4. JMatter infers the type names and captions, member names and captions from our choice of class name, getter method name, and command method name. This is done via run-time reection in Java. The total sum of conventions and features supported by JMatter is much lengthier than this basic introduction. Let us then delve into the details.

8.1

Types

When building a JMatter application, your job as a developer is to develop the model completely, using object-oriented techniques: accounting for both data and behaviour. You can think of the complete application as having a model-view-controller design. In the case of JMatter, the view and controller are generic, and already implemented. This frees you to focus on the model. From a persistence perspective, all types inherit three elds or pseudo elds:

8.2. FIELDS

109

Field id version

createdOn

Description Serves as surrogate primary key. You do not need to dene a primary key for your types. The framework does this for you. This eld is used by the underlying hibernate persistence framework to keep track of whether two objects are being edited at the same time, used for optimistic locking. A read-only eld that records the date and time that an object is created. When displaying a view of an object in form view, the value of this eld is displayed at the bottom, in the views status bar.

8.2

Fields

JMatter makes a distinction between atomic elds and complex elds, where atomic elds have a single value, while complex elds are in a sense composed of atomic and other elds. Theres a second distinction that has to do with ownership of a eld. Composite, or aggregate elds are ones that are wholly owned by their parent object. All atomic elds are aggregates. Associations on the other hand are elds that represent relationships to other objects, or entities; these relationships can be set or severed. Field ownership has implications on specic operations. For example, if the parent object is deleted, associations are only severed, but the associated object is not deleted. That is, the delete operation does not cascade to associations. A deletion on the other hand implies the deletion of child aggregate elds. It turns out that JMatters domain design happens to match the rules set forth by Eric Evans in his book Domain Driven Design [5]. If youre familiar with this work, then the notions of entities, value objects, and aggregates and their interrelationships should already by familiar to you. We also need to discuss how to model elds with different cardinalities. There are of course to-one relationships, and * or to-many relationships.

8.2.1

Atomic Fields

JMatter denes and provides implementations for a variety of types of atomic elds. Developers are required to use the frameworks denitions. That is, a string-based eld must be dened as a com.u2d.type.atomic.StringEO and not a java.lang.String. Internally the frameworks atomic type implementations often wrap or encapsulate the more primitive type. The frameworks atomic types are modeled as value objects. JMatter denes an interface for Atomics, com.u2d.model.AtomicEObject.

110

CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

The framework requires that all aggregate type elds be implemented as nal elds. Consequently accessor methods for these elds comprise of only a getter method. The denitions look like this:
private final StringEO name = new StringEO(); public StringEO getName() { return name; }

You may wonder then how one sets the value of an objects name eld? All value objects have a method:
public void setValue(EObject value);

to provide a means for setting the value. That is, the reference to the object never changes, only its contained value. StringEO has an additional convenience method:
public void setValue(String value);

Other atomic types have similar conveniences. IntEO for example (which represents an integer) has this convenience method:
public void setValue(int value);

These types also have a corresponding way of getting the represented value as a simple Java primitive or object. IntEO has:
public int intValue();

StringEO has:
public String stringValue();

..and, you guessed it, DateEO has:


public Date dateValue();

Finally, all these atomic types are ChangeNotiers, which means that they publish (or re, in pub/sub speak) change events that you can listen to. This can be useful for building lotus123-style dependencies between objects (when A changes, update B). This is also useful internally to keep the user interface in sync with its underlying model.

8.2. FIELDS

111

8.2.1.1

Build-In Atomics

Here is a listing of the various JMatter atomic types:

BooleanEO, CharEO, ChoiceEO, ColorEO, DateEO, DateTime, DateWithAge, Email, FileEO, FileWEO, FloatEO, ImgEO, IntEO, Logo, LongEO, Password, Percent, Photo, SSN, StringEO, TextEO, TimeEO, TimeInterval, TimeSpan, URI, USDollar, USPhone, USZipCode.

They are all dened in the package com.u2d.type.atom. Writing your own additional types is quite straightforward. The existing implementations represent a wealth of examples that one can draw from.

8.2.2

Composite Fields

There isnt much to say about composite (or aggregates) elds that I havent already. Again, what makes a eld an aggregate in the framework is the fact that its member is dened as a value object: dene a nal eld, and only a getter method. Heres an example:

public class Person extends AbstractComplexEObject implements Emailable { protected final Name _name = new Name(); public Name getName() { return _name; } ... }

The setValue() method applies to composite elds. For example, to copy one contacts address to another by value, you might do this:
public void copyAddress(Contact fromContact, Contact toContact) { toContact.getAddress().setValue(fromContact.getAddress()); }

8.2.2.1

Composite Types Provided with the Framework

The framework predenes a number non-atomic, or higher-level types. Theyre reside in the package com.u2d.type.composite. Heres a list of type names:
Name, USAddress, ContactMethod, Contact, BusinessContact, EmailMessage, Folder, Note, Person, Business, LoggedEvent

112

CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

8.2.2.2

Composite Indexed Field

JMatter provides a means for modeling a composite eld with a to-many (*) cardinality. A prototypical example is the relationship between an Order and its list of OrderItems. JMatter provides the type com.u2d.list.CompositeList for the task. Heres an example eld denition inside an Order class:
private final CompositeList _orderItems = new CompositeList(OrderItem.class, this, "order"); public static final Class lineItemsType = OrderItem.class; public CompositeList getLineItems() { return _orderItems; }

Heres the constructor method signature:

public CompositeList(Class clazz, ComplexEObject parent, String parentFldname);

The rst argument is the child type (Order Items). The second is a reference to the parent object (this). Finally, theres a convention where CompositeList can automatically give child objects a reference to its containing, parent object. This is done by writing a setter method in the child type denition:
private Order _order; public void setOrder(Order order) { _order = order; }

and passing the name of the eld (order) as an argument to the CompositeList constructor. Notice that you also must (at the present time) provide metadata for the framework to introspect the list type statically. The framework looks for a public static variable name of type Class of the form <eldname>Type. In the user interface, JMatter provides an tabular component that provides means for adding child items, deleting them, editing them, etc..

8.2.3
8.2.3.1

Associations
To-One Associations

A to-one association denition is essentially the implementation of a JavaBeans bound property. Lets look at an example, Song.artist:

8.2. FIELDS

113

private Artist _artist = null; public Artist getArtist() { return _artist; } public void setArtist(Artist artist) { Artist oldValue = _artist; _artist = artist; firePropertyChange("artist", oldValue, _artist); }

Thats about it. 8.2.3.2 To-Many Associations

For an indexed association, use the type com.u2d.list.RelationalList. Heres an example, from the Sympster demo application (Speaker.talks):
public class Speaker extends AbstractComplexEObject { ... private final RelationalList talks = new RelationalList(Talk.class); public static final Class talksType = Talk.class; public RelationalList getTalks() { return talks; } .. }

We do three things: 1. dene a nal member variable, talks 2. provide metadata for the framework to statically introspect the type to determine the list type 3. supply a getter method 8.2.3.3 Bidirectional Associations

We often like to be able to navigate an association from both directions. Take the example of a speaker and his or her list of presentations. The presentation would have an association to its speaker, and the speaker may have a to-many association called presentations. You can dene both associations in the manner described in the two previous subsections:

114

CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

public class Speaker.. { ... private final RelationalList talks = new RelationalList(Talk.class); public static final Class talksType = Talk.class; public RelationalList getTalks() { return talks; } .. } public class Talk.. { ... private Speaker speaker; public Speaker getSpeaker() { return speaker; } public void setSpeaker(Speaker spk) { Speaker oldValue = this.speaker; this.speaker = spk; firePropertyChange("speaker", oldValue, this.speaker); } }

In addition, you need to supply metadata for the framework to infer the other side of the relationship. The implementation at the moment is not too elegant but is nevertheless simple enough. In class Talk, add:
public static String speakerInverseFieldName = "talks";

And in Speaker:
public static String talksInverseFieldName = "speaker";

Basically, the eld name is of the form: <eldname>InverseFieldName. Speaker has a eld named talks, so the variable name is talksInverseFieldName. Its value is the name of the inverse eld: the talks speakers eld name is speaker. Both sides must dene the bit of metadata.

8.2.4

Choice Types

The notion of a Choice in JMatter is somewhat analogous to what programmers call enumerations. JMatter provides two avors of choices. The rst and more basic avor is the ChoiceEO and is implemented as an atomic object. This avor is suitable for enumerations (or small lists) that are static; i.e. they do not change. The framework itself implements a couple of types as ChoiceEOs.

8.2. FIELDS

115

As part of my work on providing access control to information, I dene a FieldRestrictionType (in package com.u2d.restrict) as follows:
public class FieldRestrictionType extends ChoiceEO { public FieldRestrictionType() {} public FieldRestrictionType(String value) { setValue(value); } private static Set STATUS_OPTIONS = new HashSet(); static { STATUS_OPTIONS.add(FieldRestriction.NONE); STATUS_OPTIONS.add(FieldRestriction.READ_ONLY); STATUS_OPTIONS.add(FieldRestriction.HIDDEN); } public Collection entries() { return STATUS_OPTIONS; } }

We also wrote a ChoiceEO in chapter 7 to dene the various states for an Issue. Basically the way to dene such enumerations is by extending the base type ChoiceEO and implementing the method entries(). The editors for these types are Swing JComboBoxes (pick lists). The second avor is modeled as a ComplexEObject. The data is not hard-coded and the type is dened as an entity in the database. These lists are more versatile in that one can dene new entries, new choices as a system evolves. We developed an example implementation in the MyTunes tutorial chapter, to dene song genres. The framework provides full create/edit/delete capabilities for these types. They are dened by extending the type AbstractChoiceEO. The framework itself denes four such types of choices: US States, Sex, Marrital Status, Contact Method (instances of these four types are pre-populated from the xml les located in jmatter/resources/data). Both avors adhere to the Choice interface:
public interface Choice { public String code(); public String caption(); }

116

CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

8.3

Commands

Lets discuss how commands work in detail. Here is the basic syntax:
@Cmd public <modifier> <returntype> <MethodName>(CommandInfo cmdInfo, [additional arguments]) { <body> }

This is not really that different from the task of dening any method. The main differences are: 1. Marking the method with the @Cmd annotation exposes it to the UI 2. The rst argument to the method is some context information about the command invocation (at the moment you dont really need to concern yourself with the CommandInfo type; I am discovering that this information is rarely needed and am beginning to question passing this argument). Making the method static has the effect of dening the command on the type instead of its instances. You can see the command action exposed as a context menu on the type in the classbar (or anywhere else, say after browsing types). If the method returns a String, that string is treated as a message that is displayed to the user in a sort of self-dismissing dialog box. If the method returns a type that is viewable (another entity), the framework makes sure to display a view of the returned instance after the command is invoked. If the method accepts arguments, then the framework will rst prompt the user for these arguments (via an input form) before proceeding to invoke the command. Take for example, this command, dened on User.java in the framework:
@Cmd(mnemonic=p) public String ChangePassword(CommandInfo cmdInfo, @Arg("New Password") Password password) { _password.setValue(password); save(); log(LoggedEvent.INFO, cmdInfo.getCommand(), "User changed password"); return "Password has been changed"; }

When an end-user invokes this command (by pressing the Change Password button on an instance of a user), he or she will rst be prompted to enter a password,

8.3. COMMANDS

117

using the caption New Password. The framework does it all. Once the password is entered, the framework proceeds to invoke the command (in the proper thread). In this case, the password editor takes care to properly validate the password before the method is ever invoked.

8.3.1

Types of Commands

So we see that with the @Cmd annotation, we can expose a method to the user interface. Also note the subtlety of adding the static modier to dene a command on a different object: the instances type, rather than the instance itself. So we have two types of commands: instance commands and type commands. In the JMatter framework, the Java class ComplexType represents or models a type, in the same way that the class java.lang.Class is an instances type. You will also nd @Cmd denitions in ComplexType. So the JMatter framework uses many of the concepts that it denes for application development internally, to build itself. Also this should make you realize that a type command on a given object is nothing more than an instance command on its type instance. Atomic types can have their own commands too. They can be invoked from the UI by right-clicking on the rendered value. For example, StringEO has the command Capitalize(). We encourage you to dene additional commands that might be useful to the plethora of atomic types that JMatter denes. 8.3.1.1 Type Commands

Aside from marking a method static to designate a command belong to the instances type, you also have the option of specifying a method signature with an extra parameter, like this:
@Cmd public static void SayHi(CommandInfo cmdInfo, ComplexType targetType) ...

The last parameter is optional. If specied, then JMatter will make sure and pass a reference to the target object (a ComplexType) upon which the command was invoked. Even though the method is static, it was invoked in the context of an instance, which happens to be a type. In some circumstances, the called method needs to know what context it was called in, and needs a reference to that object. 8.3.1.2 List Commands

Aside from type and instance commands, there is a third type of command: list commands. List commands can be dened in several ways.

118

CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

First, if an instance command is given the annotation attribute batchable as shown here:
@Cmd(batchable=true) public void Email(CommandInfo cmdInfo) ...

This is an indication that the command can be invoked in batch, so to speak; that is, given a list of instances (perhaps search results from a query), you will be able to invoke that command on all the items in the list. The logic basically iterates over all instances in the list and invokes the command on each instance. There exists a command Email on JMatters type Person, which launches your default email client and opens a compose window with the destination address pre-lled with the persons email address information. You can try this from the ContactMgr demo application. To invoke it in batch mode, just bring up a list of contacts and right-click on the list-views title to reveal its context menu. Invoking the Email command in batch will open multiple compose windows, one for each recipient on the list. The additional command: EmailWithSubject, dened like this:
@Cmd(batchable=true) public void EmailWithSubject(CommandInfo cmdInfo, @Arg("Subject") StringEO subject)

prompts you for a subject line and then launches your email clients compose command. Note that this command is also marked as batchable. JMatter is smart enough to ask you for the subject line once, irrespective of the number of times the command is invoked. What if we wanted the behavior of the command to be smarter? That is, we wish to write a separate implementation of Email, perhaps named EmailAll, that opened a single composition window, but that specied multiple addresses (the addresses of each of the persons on the list) in the To: eld. To do that, dene a list command, like this:
@ListCmd public static String EmailAll(CommandInfo cmdInfo, AbstractListEO list) ...

The command will be exposed on the list and the method will be invoked, passing in the list reference as an argument to the method. You can now iterate over the list items to grab all the email addresses, but implement the method such that a single email message is composed. Finally, List Commands also allow multiple parameters, heres an example:

8.4. METADATA

119

@ListCmd public static String EmailAllWithSubject(CommandInfo cmdInfo, AbstractListEO list, @Arg("Subject") StringEO subject)

Note that list commands must be denoted as static. Please refer to the Person class for the complete code listing. List commands are a powerful tool that can signicantly increase the usability of applications. Their use is highly encouraged. Without them, end users may be forced to perform the same operation repetitively to effect a business change in their model.

8.4
8.4.1

Metadata
Overriding Plural Name

JMatter applications are all about managing information. Information stored in objects and presented in the user interface as objects. Every model object of course has a distinct name (or label) and icon, and a distinct set of elds and commands. The user interface displays a classbar, which in a sense is a starting point for performing various operations, listing information of a given type, searching for information, creating a new instance, etc.. The classbar displays the various types in iconized form: with a caption and an icon. Each types caption is derived from its class name. Its actually the plural form of the class name. For a Boat, the plural form is simply Boats. For a Person object you might wish the caption to say People. To override the default behaviour for deriving the plural for a type, dene a static method named pluralName. Example:
public static String pluralName() { return "People"; }

8.4.2

Overriding Natural Name

The name of a type as it is displayed in the JMatter ui is derived from the class name. There may be circumstances where you might want to override the natural name for a type. This is done in a manner similar to the above, by dening a static method named naturalName().

120

CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

8.4.3

Color Coding

Types may optionally be color-coded. List views and instance views titles are painted using a gradient background color. By dening this eld, for example:
public static Color colorCode = new Color(0x4169aa);

The framework will use the specied color as the starting color for the gradient. Additionally, list entries are painted such that row background colors alternate from white to another color. The types color code, if specied, is used for that other color. Both these styling mechanisms make it easier to distinguish types in the user interface. Color coding is generally a very effective tool for improving a user interface.

8.4.4

Icons

You can assign an icon to each type. Rather than edit a conguration le, the name of the icon is derived from the type name. JMatter supports .png, .gif, and .jpg formats. Two icons sizes must be supplied: a 16x16 pixel icon (used in listings), and a larger 32x32 pixel icon. The les must be placed in the resources/images folder of your project. Your projects build le automaticaly copies these resources to the classpath at images/<imgresourcename>. For the User class, the les should be named User16.png and User32.png respectively (the le sufx may vary of course). List views of a uniform type are also decorated with an icon. You can distinguish icons used for lists of a given type from icons used for individual instances: drop in Users16.png and Users32.png into the images folder. Note how the le name uses the pluralized form of the type. JMatter also leverages and honors the types inheritance hierarchy. For example, if you dene a specic subclass of User.java, say UberUser.java, without providing a set of icons for the subtype, JMatter will fall back the super types icon. For types that are stateful, you can also distinguish between instances of different states by icon. For example, the JMatter framework provides a UserLocked32.png. If for some reason a user is locked, an administrator viewing a list of users can easily spot the locked user. The IssueManager demo application also leverages this feature (see chapter 7). 8.4.4.1 Per-Instance Icons

There are situations where one of the elds of a model object contains a picture representing the instance in question. Here are examples:

8.4. METADATA

121

1. An albums cover 2. A persons photo 3. A photo of a car part So far, all instances of a given type use the same icon. Why not use a different icon per instance in such situations? The methods iconLg() and iconSm() which are instance methods on model objects, govern what icon is to be used for an instance. Simply override the implementations in your classes. JMatter provides a utility class: PhotoIconAssistant, that takes the work out of properly scaling the photo to the right size for an icon, on your behalf. Heres an example of how this is done:
public class Speaker extends AbstractComplexEObject { ... public ImgEO getPhoto() { ... } private transient PhotoIconAssistant assistant = new PhotoIconAssistant(this, photo); public Icon iconLg() { return assistant.iconLg(); } public Icon iconSm() { return assistant.iconSm(); } ... }

8.4.5

Field Order

To control the order in which a types elds are laid out on a form, use the eldOrder static member. Example:
public static String[] fieldOrder = {"name", "contact"};

Whatever eld names you dont reference in eldOrder will still appear on the form, after the listed ones, in no guaranteed order. This piece of metadata underscores an important aspect of the framework which you must understand: the notion that elds and commands can be referenced by name, as a string. What are the rules that govern the derivation of a elds name? Field names are derived from their accessor method name. Here are a couple of simple examples:

122

CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

getName() -> "name" getFirstName() -> "firstName"

Fields also have natural names, presented as eld captions in the user interface. The natural name for the rstName eld is First Name.

8.4.6

Command Order

In a manner analogous to the way elds are ordered on a form, we can control the order in which a types commands are displayed with the commandOrder static eld. The ContactMgr demo applications PersonContact type has two static methods Report and NewPersonWizard. Their relative order can be specied as follows:

public static String[] commandOrder = {"Report", "NewPersonWizard"};

Whats interesting here is that these two commands are static methods: theyre type commands. The commandOrder eld controls both static commands and instance commands. Each list is mutually exclusive and so can be (and is) specied with a single commandOrder string array eld.

8.4.7

Flatten Into Parent

Types can have different types of member elds. Some are simple, atomic, elds such as a string, a number, a percentage perhaps. These elds are not entities. From a persistence perspective, they dont get their own tables. A type may also bear members which are not atomic, but nevertheless aggregates of their containing types. Say for example that I dene a Person type with the eld name of type is Name. The type Name in turn has two elds: rst, and last, both of which are atomic elds. Person.name on the other hand is not atomic. The hierarchical relationship is sometimes important and useful in many situations. By default JMatter maintains a one-to-one correspondence from model to view, and does not hide this relationship. The view widget used by JMatters Swingbased view mechanism can expand or collapse to show the name elds children. An instance is shown in expanded mode below.

8.4. METADATA

123

Figure 8.1: Hierarchical Display of Aggregates Sometimes its more practical to display all descendant elds as a single attened form, rather than require users to expand and collapse sub-nodes in order to perform data entry. Thats what the attenIntoParent metadata bit is for. In our example, to communicate to the framework that we wish to atten the name elds child elds (rst and last) into its parent form, we would do this:
public static String[] flattenIntoParent = {"name"};

8.4.8

Tab Views

Another feature related to controlling an aspect of how information is displayed to users is the tabViews metabit. You use it in a manner similar to many other pieces of metadata: by specifying a list of member elds:
public static String[] tabViews = {"contact"};

The above example may be used, say, in a Person object to specify that the persons contact information (an aggregate eld) should be displayed in a separate tab. In the Swing-based user interface, the keyboard shortcut Alt-<index> can be used to switch the focus to the tab at index <index>. That is, in a view with three tabs, the shortcuts Alt-1, Alt-2, and Alt-3 can be used to toggle tab focus.

8.4.9

Default Search Path

This piece of metadata is useful to dene one eld that is most commonly used to search for instances of a given type. It may be name for a Person object, or title for a Presentation object. Here is how to specify it:

124

CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

public static String defaultSearchPath = "name";

The value is specied as a string but may actually be a eld path, such as name.rst. This value in turn is used in the user interface to assist with quick searches for performing associations or defaulting the search eld when performing a search operation. Its quite useful. At the moment, this feature is supported only for textbased elds where the inequality defaults to TextStarts (i.e. that were looking for instances whose default search eld value starts with the value entered by the user).

8.4.10

Unique Fields

JMatter automatically takes care to dene a surrogate primary key for your model classes. Often there may exist additional elds, natural keys, that must remain unique. Optionally dening a static eld identities will ensure that JMatter constructs the database schema properly (marking the eld as unique in the database, which will also create an index on the table). In the user interface, such elds cannot be revised after an object has been created for the rst time. Example:
public static String[] identities = {"ssn"};

8.4.11

Read-only Fields

Fields can be marked as read only by providing an optional readOnly static eld (in the same manner eldOrder is specied). This is useful when working with derived (or calculated) elds, which we discuss next. Example:
public static String[] readOnly = {"created"};

8.4.12

Calculated Fields

We sometimes use elds whose values are derived from other information. The information does not need to be persisted (made part of the database schema) and the information can simply be derived when the object is restored from the database. Dene such elds in the usual way. JMatter provides a way to mark the eld as not persisted, and a way to hook into the objects life cycle in order to update the eld value, as illustrated in the following example.

8.5. PER-FIELD METADATA

125

Example:
private final USDollar _total = new USDollar(); @Fld(persist = false) public USDollar getTotal() { return _total; } public void onLoad() { super.onLoad(); calculate(); } private void calculate() { ChargeCalculator calc = new ChargeCalculator(_trip, _settings); _charges = calc.getCharges(); _total.setValue(calc.getTotal()); }

Since derived elds need to be recalculated as a function of their inputs, its also useful to attach change listeners on the input values. Heres an example:
_settings.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { _tracer.info("Settings changed, recalculating.."); calculate(); } });

In this case the variable _settings is a composite member of the enclosing class.

8.5
8.5.1

Per-Field Metadata
@Fld Annotation

We can augment a elds getter method with the @Fld annotation. Here is a list of the parameters this annotation accepts, along with a description (all of these parameters are optional).

126

CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

Parameter Name mnemonic

Type char

Description What keyboard mnemonic to attach to the eld in question. Useful for form entry, to directly set the focus on a specic eld A way to override the caption used to display a eld in a form The elds description. Used as the contents of a tooltip on the eld. A means to override the name of the database column corresponding to this eld. By default, the column name is automatically derived from the eld name. Controls the size of the elds underlying database column. By default, many string-type elds are set as varchar(255). This attribute provides a means to control the column size at a ner level. Controls the size of the corresponding text eld used for doing data entry on the eld. Applies only to TimeEO and DateEO type elds. Accepts a SimpleDateFormat string to control the format of times and dates for both parsing and rendering. e.g. @Fld(format=m:ss) might be useful on a TimeEO eld for displaying song durations. Whether the eld should be persisted at all (see the discussion on Calculated Fields) Use to hide certain elds from the user interface

label description colname

String String String

colsize

int

displaysize format

int String

persist hidden

boolean boolean

Although the framework provides a means for overriding the label for a eld, we generally discourage this practice. We believe there is great value in maintaining a correspondence between eld labels in the user interface and their corresponding eld names in our object models. If you wish to revise the date and time format throughout the application (i.e. not for a specic eld), you can specify the format in the model-metadata.properties le (see subsection 8.6.3).

8.5.2

The @IdxFld Annotation

For relational lists, one can optionally specify an additional annotation: @IdxFld. At the moment, you can specify two attributes: ordered=true Will maintain the list as an ordered list. From a persistence perspective, the hibernate mapping le will use an ordered list (an additional

8.6. PER-COMMAND METADATA

127

column in the database table specied the list item order). From a UI perspective, in edit mode, the list can be reordered via drag and drop. ownsChildren=true If specied, the to-many relationship is modeled in such a way that when an item is removed from the list, the child item will be deleted from the database (hibernate cascade=delete-orphan). Semantically the list items cannot be freely associated with an entity. In the user interface, the Browse and Find association commands that usually adorn the list view are not accessible.

8.6

Per-Command Metadata

Commands must be marked with the @Cmd in order to be exposed to the user interface. Theres nothing special about these methods and they can be invoked programmatically as well. When these commands are invoked from the user interface, JMatter makes sure to call the method off the event dispatch thread. If a command returns a ComplexEObject, its view is drawn and displayed back on the event dispatch thread. The framework also makes sure to display a waiting cursor while the operation is invoked.

8.6.1

@Cmd Metatada

Here is a summary of the optional parameters that the @Cmd annotation supports:

128

CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

Parameter Name mnemonic label description sensitive

Type char String String boolean

Description What keyboard mnemonic to use to invoke the command Use to override commands caption in the user interface Used as a tooltip to the commands corresponding view (usually a button) Specify whether this is a sensitive command (e.g. Delete) where it would be benecial for the ui to provide a mechanism to prevent against inadvertent invocation of the command. This is done in the Swing view mechanism by disabling the commands button. A small lock on the button can be clicked on to unlock (enable) the action. Applies only to type commands (commands marked static). Specify a keyboard shortcut (an accelerator). Example: "control Z" Whether the command can be invoked in list context (composed across a number of instances) Decorate the command view (button or menu item) with an icon. For example, the Edit command is dened with iconref="pencil"; make sure to place a copy of pencil32.png and pencil16.png in the image resources folder.

shortcut

String

batchable iconref

boolean String

Note: although the framework provides ways of overriding eld and command labels, we highly discourage this practice. Having a one-to-one correspondence between the actions label and its corresponding method name signicantly improves the maintainability of your application.

8.6.2

@Arg Metadata

In addition, method arguments can be optionally marked with the @Arg annotation. This annotation accepts a single value, which is used as the caption on the form drawn to accept input to the method, as this example illustrates:
@Cmd(mnemonic=p) public String ChangePassword(CommandInfo cmdInfo, @Arg("New Password") Password password);

8.7. PERSISTENCE LIFECYCLE AND APPEVENTS

129

8.6.3

The model-metadata.properties le

By default all child projects have a le that can be customized to provide model metadata: resources/model-metadata.properties. Here are the default contents of this le:
User.role.required=true User.role.default=from Role r where r.name=Default CompositeQuery.name.required=true # e.g. #Speaker.name.required=true # date and time format override (optional) #DateEO.format=dd.MM.yyyy #TimeEO.format=HH:mm:ss

Although this le is discussed in the next chapter from the perspetive of validation, not all aspects of this le pertain to validation. First, we see that we can use a sort of eld path notation to reference a eld, such as User.role, or perhaps Person.name.rst. We can mark elds as required by setting the eld property value, appending the .required sufx, to true. We can also specify a elds default value. Above we see that we can even specify the default value in terms of a hibernate (hql) query. We can also provide a hard-coded value, say Person.salutation.default=Mr. For choice-type elds, we can specify the code for the choice and if a database lookup is necessary, it will be performed (e.g. Address.state.default=TX) Finally, we just recently inroduced the ability to specify the default date and time format, which previously was hard-coded to US norms. The format is specied using Javas SimpleDateFormat rules.

8.7

Persistence Lifecycle and AppEvents

The base class AbstractComplexEObject implements the interface PersistorListener:


public interface PersistorListener { public void onLoad(); public void onBeforeCreate(); public void onCreate(); public void onBeforeSave(); public void onSave(); }

130

CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

The persistence mechanism implementation calls these methods at the appropriate times: when an object is loaded from the persistence store, onLoad() will automatically be called, for example. It is permissible to override these methods, but be sure to rst call the superclasss implementation. That is, do not mask the superclass implementations:
public class Car extends AbstractComplexEObject { public void onLoad() { super.onLoad(); System.out.println("Loaded "+this); } .. }

This is useful for some things. For example, onLoad() is useful for recalculating a derived eld. The framework itself uses onBeforeCreate() to set the value of the read-only eld createdOn:
1 2 3 4 5 } public void onBeforeCreate() { _createdOn.setValue(new Date()); fireAppEventNotification(BEFORECREATE, this);

This bring up another aspect of the framework that might be useful to know about: AppEvents. The JMatter framework contains an implementation of the Observer pattern (aka publish/subscribe) that is used internally for communicating various events between various parts of the application. For example, the framework denes LOGIN and LOGOUT events. When a user logs in, this event is published and all interested listeners are notied. The frameworks class AppSession is an AppEventNotier in that it noties listeners of login-related events. AbstractComplexEObjects do a similar thing. By virtue of being persistor listeners, they are notied of persistence lifecycle changes. These objects use the AppEvent mechanism to also notify any interested listeners of these events. That explains line 4 in the above code sample. To the extent that you have objects in your application that need to be informed of such events, these objects may congure themselves as listeners on whatever model objects theyre interested in. In fact, we saw an example in the IssueMgr sample application where we wanted to delay transitioning to another state until after the object was created.

Chapter 9

Validation
There are a number of facets to validation. Lets begin by describing one aspect of the GUI. In the user interface, when an object is displayed, it can be edited and saved (updated). The user interface code that lays out the form conveniently inserts a number of panels called validation panels. These panels are normally empty and thus not apparent in the user interface. For an object with three atomic elds, say a Speaker with a name (StringEO), a title (StringEO), and a biography (TextEO), four validation panels will be setup: one for each eld, and one for the instance. Each atomic type asserts its own validation requirements. Lets take a look at USZipCode for a moment:
private static String omit = "- "; private static String valid = "0123456789"; public int validate() { String value = SimpleParser.parseValue(omit, valid, _value); if (value == null || value.length() != 5 && value.length() != 9) return invalid(); return 0; } private int invalid() { fireValidationException("Invalid zip code: "+_value); return 1; }

131

132

CHAPTER 9. VALIDATION

Here we see that USZipCode implements the validate() method, which the framework will invoke at the proper time. The return value, an int, species the number of "errors" encountered. So a return value of 0 implies that validation passed. Theres a publish/subscribe pattern here, where the model object does not have a reference to its corresponding view (or editor) object. Yet, somehow the UI must display the validation error message. So the model object publishes the message *Invalid zip code...* when a validation error is encountered. The validation panel that corresponds to a eld of this type in the user interface is a listener, and receives the messages, and properly displays the error:

Figure 9.1: Zip Code Validation The way you should view this form is that each eld has its own validation panel embedded in the form, just above it. Most of the time these panels are dormant. When a validation message is published, it will appear in the appropriate place. Each panel listens to the value of its corresponding eld. The method validate() will be called on atomic objects when a user tabs out of the editor (when the eld loses focus) and again when the user attempts to save the object. So validation on atomic types such as such as USZipCode, SSN, and USPhone is implemented in this way.

133

Some validation logic is really more an artifact of how the atomic types editor chose to allow you to enter the information, and so is implemented directly on the editor. Lets take a look at PasswordEditors bind() method, which is called by the framework to bind the value entered in the editor back to the model object:
public int bind(AtomicEObject value) { Password eo = (Password) value; String pwd1 = new String(_pf1.getPassword()); String pwd2 = new String(_pf2.getPassword()); if (pwd1.length() < Password.MINLENGTH) { eo.fireValidationException("Password must be at least " + Password.MINLENGTH+" characters long"); return 1; } if (! pwd1.equals(pwd2) ) { eo.fireValidationException("Password and repeated password do not match."); return 1; } eo.parseValue(pwd1); return 0; }

This editor displays two password elds. The entered value must match each time. Also theres a check to ensure that the specied password meets certain criteria, such as a minimum length, or exceeding a certain minimum password strength, based on a specic algorithm. Again, we see here how the editor, through its reference to the model object, re a validation signal, causing the proper validation error message to display. In addition, baked into the framework is a simple mechanism for marking elds as required. The framework will automatically check that required elds left empty will veto the ability to save an object, and will also display a proper error message. The way to mark required elds in JMatter is to specify them in the properties le model-metadata.properties. Heres a sample le, taken from an application having to do with aircraft that I recently implemented:
Airport.airportID.required=true Airport.name.required=true Airport.lat.required=true Airport.lon.required=true

134

CHAPTER 9. VALIDATION

Airport.city.required=true Airport.stateCode.required=true Trip.aircraft.default=from Aircraft a where name=CitationJet TripSegment.from.required=true TripSegment.to.required=true

Notice that this metadata le is also used to specify default values for elds. Note how a default value is specied for an association by actually looking it up in the database. The value specied is valid hql (hibernate query language). Lets get back to discussing validation. Any type you dene in your object model can dene its own validation as well, again, simply by implementing validate(). Heres how it was implemented for the type "TripSegment" in an application I developed:
public int validate() { if (_from == null || _to == null) { String msg = "From and To fields cannot be empty"; fireValidationException(msg); return 1; } if (_from.equals(_to)) { fireValidationException("From and To fields cannot be the same"); return 1; } if (_trip != null && _trip.getAircraft() != null) { Aircraft aircraft = _trip.getAircraft(); if (aircraft.hasRangeFor(_numPassengers.intValue())) { int range = aircraft.rangeFor(_numPassengers.intValue()); if (range < distance()) { String msg = String.format("Segment distance exceeds aircraft " + "range (%d) for specified number of passengers", range); fireValidationException(msg); return 1; } } } return 0; }

135

So theres a simple business rule in this case that a trip segments distance cannot exceed the specied aircrafts range for the specied number of passengers. So here you have it, in a nutshell, an overview of validation in JMatter, how to implement it in your applications, and how things work under the hood.

136

CHAPTER 9. VALIDATION

Chapter 10

Authentication & Authorization


JMatter comes built-in with authentication and authorization services. When launching a JMatter application for the rst time, the framework will create two roles (administrative and default) and two corresponding users: admin (with admin privileges), and johndoe with default privileges, as shown in the gure 38.

Figure 10.1: Initial Users and Roles The framework provides two model objects: User.java and Role.java, that are con-

137

138

CHAPTER 10. AUTHENTICATION & AUTHORIZATION

structed according to JMatters own conventions for model objects. The icons used for these types follow the same convention: you will nd in the path jmatter/resources/images the corresponding icons used by the framework. In the case of User, you will nd three variants: an icon for a single user, a plural version, and a state-specic icon for locked users (UserLocked32.png). Users and Roles are modeled in a bidirectional one-to-many association. By default, when creating a new user, the user will be associated with the default role. Passwords are hashed using the MD5 algorigthm, and it is this hash which is stored in the database. Upon application launch, the application is in logged out state, and a login dialog is presented. Three invalid login attempts by default will cause the user account in question to lock, requiring an administrator to reset the users password. Password resetting is implemented as a JMatter Command (@Cmd) and so is accessible directly from the user interface (assuming you have the proper permission). Upon successful login, the users classbar is fetched from database (upon initial login, the classbar is dened from the template le class-list.json) and presented in the user interface. Again, assuming the proper permissions, one can create new users, new roles, assign users to a role, and go about performing whatever activities are necessary to manage authentication-related information.

10.1

Autologin

In some situations, one might be interested in developing a application that does not care for or require authentication. For such cases, JMatter can be congured to automatically log in as a specic user upon launch, removing the need for users to manually authenticate. To congure a JMatter application with autologin, edit the applications src/applicationContext.xml as follows:
<bean id="app-session" class="com.u2d.app.AppSession"> <property name="app" ref="application" /> <property name="viewMechanism" ref="view-mechanism" /> <property name="autologinas" value="admin" /> </bean>

The important line is the autologinas property, which directs JMatter to turn on autologin and to automatically log the user in as the user admin, in this particular case.

10.2. AUTHORIZATION

139

10.2

Authorization

Authorization governs who can perform what actions. Authorization in JMatter is specied by role. JMatter comes complete with an authorization implementation, all driven from the user interface. The starting point is an application where everything is permitted. Authorization is specied then by applying a series of restrictions from this initial state. When a user logs in, the set of restrictions corresponding to the users role are fetched from the database and applied to the system. Upon logout, the restrictions are lifted, and reapplied on subsequent login, again according to the new logged in users roles restrictions. Restrictions can be applied to both commands and elds. Commands can be disabled, in which case, they disappear from the user interface: from context menus, from the button panels on form views. Fields can be marked hidden or read-only, per role. To specify the authorization policy, JMatter denes the command Manage Restrictions, dened on all types, as shown in gure 39.

140

CHAPTER 10. AUTHENTICATION & AUTHORIZATION

Figure 10.2: Managing Restrictions Just like Form Views are dynamically rendered, based on the structure of model objects, so is this view. When a new role is created, a new column will appear in this view. When a new command or eld is added, a new row will be added to the corresponding table. Here we see that existing administrative commands are already marked restricted for the default role. For example, the ability to create a new role, to edit or delete roles, is prohibited. Furthermore the ability to dene restrictions on roles is likewise prohibited. Finally, the role types Open command is prohibited as well, restricting access to inspection of the types metadata from the user interface.

10.3

List Filtering

Another component of authorization is the ability to lter data. For example, in the Issue Manager demo application, we may require that users can view only

10.3. LIST FILTERING

141

issues assigned to them. The Hibernate O/R mapping system provides a way to lter data that JMatter now exploits. The convention is to optionally dene a static method on a given type to lter lists of the type in question. For example, we might dene this method on Issue:

public static String typeFilter() { return "assignedTo_id = :currentUser"; }

When specifying the lter, you have to be aware that hibernates implementation of lters appears to be sql-based and not hql-based. So the lter is used in the construction of a sql query. Therefore we reference the types assignedTo eld by its primary key colum name. JMatter will now produce the lter declarations directly into the generated hibernate mapping les. You should see something like this at the bottom of the generated Issue.hbm.xml
.. <filter name="authFilter" condition="assignedTo_id = :currentUser"/> </class> <filter-def name="authFilter"> <filter-param name="currentUser" type="long"/> </filter-def>

Second, after logging in, JMatter will automatically enable this lter for the users session (unless you log in as administrator), and bind the logged in users primary key to the lter parameter (:currentUser). As further use cases for data ltering surface, this implementation will be broadened to accommodate them.

142

CHAPTER 10. AUTHENTICATION & AUTHORIZATION

Chapter 11

Search
Search is an indispensable part of business applications today. Database systems provide the ability to lookup information via its SQL interface. But software applications will almost never provide end users direct access to a database via SQL, and there are many good reasons for this. Typically a fair amount of code is written by developers on top of SQL (or these days HQL or some other object-based query language) to expose search features in their applications. JMatter integrates search capabilities directly into its user interfaces, in a deep and comprehensive fashion. The good news is that the entire implementation is independent of the domain in question, removing the need for developers to implement their own search layer.

11.1

Filtering Listings

All list views in JMatter are decorated with a simple query panel. Through this query panel, users can dynamically view a custom-ltered set of items, that match a specic criterion: users with a specic last name, contacts in a specic city, talks on a given topic, sessions given on a specic date, etc.. Users have adhoc search capabilities on every type in their domain. This feature is quite sophisticated. JMatter provides a custom widget based on a tree model that comprises an acyclic tree of the sum of valid search paths for a type, from the entitys root to leaf elds, and can traverse even associations to other elds. Furthermore, for every atomic type, JMatter provides a set of matching inequalities and value editors.

143

144

CHAPTER 11. SEARCH

So for example we can ask questions such as return all contacts who live in a zip code that starts with a 7 or nd all talks given by speakers whose who live within such a matching zip code.

11.2

The Find Command

The Find command, which is inherent on any type, allows the composing of multiple simple criteria in a conjunction. Disjunction type composite queries are not yet supported.

11.3

Smart Lists

Smart lists denote the ability to save a query performed using the Find command to database. All JMatter applications include model objects provided by the framework itself. Examples include the entities User, and Role to manage authorization. With respect to Search, the Query model object is also part of your applications domain. This means that end-users can create, read, update, delete, and execute queries to their hearts content. They can even use the built-in search capabilities of JMatter to query queries. So for example, in the MyTunes sample application, we can create our own playlists based on various criteria and name them, in a manner analogous that users have become accustomed to with other popular players.

11.4

Search in Associations

Another important feature in JMatter is the ability to search directly within the context of an association eld, for the purpose of establishing a relation between two objects. Section 21.2 on page 226 provides a detailed example of its use.

11.5

Polymorphic queries

When modeling an application using object oriented principles, we avail ourselves to various modeling techniques such as modeling with abstract classes and interfaces. We can have an association from one entity to another which is by nature polymorphic. We saw two such examples when covering the Sympster demo application:

11.6. CODE HINTS FOR SEARCH

145

1. A symposiums venue was modeled using a simple abstract base class with three subclasses (Hotel, Campus, and ConferenceCenter) 2. Sessions were modeled with a relationship to an Event, an interface, implemented by both Talk and BOF. The nature of these relationships carries through to queries. We can request of our persistence repository for a listing of events, which will transparently fetch both Talks and BOFs. We can narrow a polymorphic listing by type. One possible query is asking for all events of a specic type. All queries are performed objectbased. This support is possible because Hibernate is object-based. JMatter takes full advantage of this.

11.6

Code Hints for Search

There is one specic class-level piece of metadata that developers typically specify to govern a default that is related to searching, as discussed in section 8.4.9: defaultSearchPath. Heres an example:
public static String defaultSearchPath = "name";

This piece of metadata is useful to dene one eld that is most commonly used to search for instances of a given type. It may be name for a Person object, or title for a Presentation object. The value is specied as a string but may actually be a eld path, such as name.rst. This value in turn is used in the user interface to assist with quick searches for performing associations or defaulting the search eld when performing a search operation. Its quite useful. At the moment, this feature is supported only for textbased elds where the inequality defaults to TextStarts (i.e. that were looking for instances whose default search eld value starts with the value entered by the user).

146

CHAPTER 11. SEARCH

Chapter 12

Wizards, CSV Export, and PDFs


Remember our zero-code contact manager? In this chapter were going to actually add code to that application. Many desktop applications today provide these software assistants, or wizards, to help newbie users through a task. For example, when we created a contact person in our contact manager, we did not resort to an assistant. We just right-clicked New on Person and typed away. This works just ne. But maybe we would also like to break the process of entering contact information into these steps: 1. Enter persons name 2. Enter persons physical address 3. Enter remaining contact information (phone numbers, email address) 4. Finish Having more than one way to do something can sometimes help. Each method can complement the other. Lets see what kind of support JMatter provides for adding assistants to our user interface.

12.1

Subclassing Person

When we wrote this application, we used pre-written classes. One of them was com.u2d.type.composite.Person. We want to enhance person with an additional behaviour: we want to add a command to launch our wizard. It should be a class command, not an instance command.

147

148

CHAPTER 12. WIZARDS, CSV EXPORT, AND PDFS

So we need to subclass Person. Lets create a package com.u2d.contactmgr. In it were going to create a new class: PersonContact like this:
package com.u2d.contactmgr; import com.u2d.type.composite.Person; import com.u2d.wizard.details.Wizard; import com.u2d.element.CommandInfo; public class PersonContact extends Person { @Cmd public static Wizard NewPersonWizard(CommandInfo cmdInfo) { return new Wizard(new NewPersonWizard()); } }

Pretty simple. Were basically exposing a command that will return a Wizard object. JMatter knows what to do with these objects, how to display them, allow the end user to navigate through them, etc.. All you need to do is provide the steps.

12.2

Writing the Wizard

JMatter models a wizard as a container for a series of steps. JMatter denes several types of steps. There are basic (or atomic) steps, conditional steps, and composite steps. We need to write a class that is essentially a composite step: one that denes the set of steps that makes up our wizard. Here is the rst part of the implementation for our NewPersonWizard class:
package com.u2d.contactmgr; import com.u2d.wizard.details.*; import com.u2d.type.composite.*; import com.u2d.model.ComplexType; import com.u2d.view.swing.FormView; import javax.swing.*; public class NewPersonWizard extends CompositeStep { private Name _name; private USAddress _address; private Contact _contact; public NewPersonWizard() { super("New Person Wizard");

12.2. WRITING THE WIZARD

149

createObjects(); setupSteps(); } private void createObjects() { _name = (Name) ComplexType.forClass(Name.class).instance(); _address = (USAddress) ComplexType.forClass(USAddress.class).instance(); _contact = (Contact) ComplexType.forClass(Contact.class).instance(); } private void setupSteps() { NameStep nameStep = new NameStep(); AddressStep addrStep = new AddressStep(); ContactStep contactStep = new ContactStep(); addStep(nameStep); addStep(addrStep); addStep(contactStep); addStep(new CommitWizardStep()); ready(); } }

Lets analyze this code. We dened a class that extends CompositeStep. Recall that our wizard is essentially four steps: specify a name, an address, contact info, and nish. So we dene variables that will hold each of these three pieces of information. Next, in the constructor, we set the title for our wizard with the call to the super types constructor. We proceed to instantiate our three objects and then to congure them. The convention for setting up the steps is pretty easy: 1. create each step 2. add the steps in the proper order 3. call the ready() method Now all thats left to do is dene three basic steps. Ive decided to do this using inner classes, as follows:
class NameStep extends BasicStep { public String title() { return "Name Information"; } public String description() { return "Enter Persons Name"; } public JComponent getView()

150

CHAPTER 12. WIZARDS, CSV EXPORT, AND PDFS

{ return new FormView(_name, false, false); } } class AddressStep extends BasicStep { public String title() { return "Address Information"; } public String description() { return "Enter Persons Physical Address"; } public JComponent getView() { return new FormView(_address, false, false); } } class ContactStep extends BasicStep { public String title() { return "Persons Contact Information"; } public String description() { return "Please specify persons contact information"; } public JComponent getView() { return new FormView(_contact, false, false); } }

We see here that the implementation is trivial. We provide a title, description, and a view for each of our steps. Nothing to it! It is worth noting that the FormView class is taken from JMatters own Swingbased view mechanism. By reusing this class, we automate the chore of having to write the panels that make up our wizards user interface. Not only do we automate the construction of each panel, but also the binding of the view to its model object, as well as model object validation. For example, entering a zip code with an invalid format in the AddressStep will automatically be agged, giving the user a chance to revise and x the data entry (see the screenshots that follow this section) before being able to proceed to the next step in the wizard. In our last step, the commit step, we sew everything together and save our new contact person:
class CommitWizardStep extends CommitStep { public void commit() { PersonContact pc = new PersonContact();

12.3. RUNNING THE APPLICATION

151

pc.getName().setValue(_name); pc.getContact().setValue(_contact); pc.getContact().getAddress().setValue(_address); pc.save(); } public JComponent getView() { return new JLabel(description()); } public String title() { return "Final Step"; } public String description() { return "Were almost done; Person record will be " + "committed after clicking Next"; } }

Besides providing the basic step information: title, description, and view, we also need to ll in the commit() method, which is quite straightforward: 1. we create a new PersonContact instance 2. we set the name, contact, and address values 3. nally, we persist our instance JMatter does the rest! Lets take our app for a little spin.

12.3

Running the Application

Lets run our app:


$ ant run

The next ve gures are screen shots for the various steps in our simple wizard. Note how the name, description, and view for each step are automatically placed in their respective places on the wizards window.

152

CHAPTER 12. WIZARDS, CSV EXPORT, AND PDFS

12.3. RUNNING THE APPLICATION

153

154

CHAPTER 12. WIZARDS, CSV EXPORT, AND PDFS

This coverage of wizards was meant to be an introduction to the topic. JMatters wizard framework is complete from the point of view that one can produce wizards of any degree of complexity by combining basic steps, composite steps, and conditional steps in various ways.

12.4

CSV Export

If we like, we can also export our contact list to a CSV le. This feature is builtin to all JMatter applications. Simply browse your contact listing and right-click Export to CSV. You will be prompted for a location to save the le. Below is a screenshot of a small CSV export opened in the spreadsheet application Gnumeric.

12.5. PDFS

155

Figure 12.1: CSV Export Viewed in Gnumeric Note that this feature could be improved. At the moment the CSV Export command simply exports the table model exposed by the listing. However, in this case, it would be nice if the address elds were attened as properties for each contact. Itd be even nicer if there a CSV export wizard walked you through the process, allowing you to select which elds to export, which to skip, and in what order to serialize them out to le. We hope to extend this CSV export feature in a future version of JMatter.

12.5
12.5.1

PDFs
JFreeReport Integration

JFreeReport is an open source Java API for reporting; its home page is http://www.
jfree.org/jfreereport/.

This API has been around for a number of years. It denes an xml vocabulary for laying out reports. Its somewhat difcult to describe in one or two sentences what JFreeReport is all about. Some of its characteristics are reminiscent of templating technologies where information from our applications can be merged with a the xml report specication to produce the nal report. The report specication denes various bands such as report headers and footers, page headers and footers, and the actual report items themselves.

156

CHAPTER 12. WIZARDS, CSV EXPORT, AND PDFS

JFreeReport also provides means for you to automatically display a print preview of your report from inside your Swing application. From that dialog, one also has the ability to produce the report in a number of formats, including PDF, print, and Microsoft Excel. The JMatter framework attempts to make the job of producing reports with JFreeReport easier. The JFreeReport libraries are already bundled with JMatter. Producing a PDF report from JMatter via JFreeReport is a relatively easy task. The task of writing the report specication using JFreeReports XML specication however remains unchanged. The authors of this framework have used JFreeReport to produce completed medical forms, merging information in a medical system with a template dening the layout of the form[s] to be completed. 12.5.1.1 The basics

JFreeReport provides two ways in which data can be passed in to its xml report specication: 1. the implementation of a TableModel interface, which provides the majority of the tabular data to be included in a report, and 2. a simple properties le with key-value pairs for passing any kind of information to include in the header or footer sections of the report JMatter denes the following interface:
public interface Reportable { public String reportName(); public Properties properties(); public TableModel tableModel(); }

The latter two methods provide the data to bind to the xml report specication. The rst method provides the path to the reports xml specication. JMatter basically follows the convention that these xml les be placed alongside source code. The xml les are then loaded into a Java application as a resource from the classpath. If in a command method, you return a Reportable instance, JMatter will take it from there and use JFreeReport to produce a corresponding PDF le and open it using a PDF reader application.

12.5. PDFS

157

12.5.1.2

A Simple Example

Lets build a very simple report for our ContactManager application. The point of this section is not to provide documentation for JFreeReport. Rather, its only to illustrate how the integration works. So heres a simple mechanism to expose the production of a report that will include all the contacts we have in our system:
@Cmd public static Reportable Report(CommandInfo cmdInfo) { return new Reportable() { public String reportName() { return "com/u2d/contactmgr/Basic.xml"; } public Properties properties() { return new Properties(); } public TableModel tableModel() { return ComplexType.forClass(PersonContact.class). list().tableModel(); } }; }

So basically what Im doing here is exposing a static command using the JMatter conventions. This command returns a Reportable implementation that in this case passes data only via a tablemodel. Im basically returning the default table model that JMatter exposes on lists of types. Here is a very basic sample JFreeReport XML specication:
<?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE report PUBLIC "-//JFreeReport//DTD report definition//EN//simple/version 0.8.5" "http://jfreereport.sourceforge.net/report-085.dtd"> <report name="Basic Persons Listing" orientation="portrait" pageformat="LETTER" topmargin="36" bottommargin="36" leftmargin="36" rightmargin="36">

158

CHAPTER 12. WIZARDS, CSV EXPORT, AND PDFS

<configuration> <property name="org.jfree.report.modules.gui.base.PreferredWidth">640</property> <property name="org.jfree.report.modules.gui.base.PreferredHeight">480</property> </configuration> <pageheader height="200" fontname="sansserif" fontsize="10" fsbold="true"> <label x="0" y="0" width="100%" height="12" fonsize="12" fsbold="true" alignment="center"><![CDATA[Person Contacts Listing]]></label> <line x1="170" y1="50" x2="334" y2="50" weight="0.75" /> </pageheader> <items height="18" fontname="sansserif" fontstyle="plain" fontsize="10" fsbold="false" vertical-alignment="middle"> <string-field x="10" y="0" width="250" height="12" alignment="left" fieldname="Person Contacts" /> <string-field x="270" y="0" width="100" height="12" alignment="left" fieldname="Name" /> <string-field x="380" y="0" width="250" height="12" alignment="left" fieldname="Contact" /> </items> </report>

The essential aspects of this specication are located in the items band, where we see that various string-based elds are specied. JFreeReport allows you to insert images, other data types, to control the font size, style, and placement of the information. JFreeReport also provides a number of built-in functions that can be invoked to calculate sums, for example. Developers can also write and plug in their own custom functions. The result of invoking this command from the JMatter user interface is the production of the report PDF, as shown below.

12.5. PDFS

159

Figure 12.2: PDF produced with JFreeReport

12.5.2

JasperReports

JasperReports is yet another, even more popular, open, reporting solution for Java. It is a well-supported project. One appealing feature of this project is its companion project iReports, a mature graphical report designer, which does away with the tedium of writing JasperReports analog to the the xml report specication we just saw in the last section. Another attractive feature of JasperReports is its support and integration with Hibernate. This makes JasperReports a perfect mate for JMatter. We recently extended the Sympster demo application with an example use of JasperReports for producing a symposium schedule. Simply run Sympster, create a symposium and a number of associated Sessions, and then invoke the Symposium command Report Schedule.

160

CHAPTER 12. WIZARDS, CSV EXPORT, AND PDFS

JMatter now bundled the JasperReport libraries with its distribution for your convenience. We also highly recommend you support the JasperReports project by buying a copy of their documentation [6] in print.

12.5.3

Launching PDFs and other Files

The solution that appears to work well for displaying PDFs is to launch the desktops default PDF viewer, rather than attempt to embed a PDF viewer component within ones application. The Java platform has such a desktop integration feature in Java SE v6. The state of affairs today is such that the MacOSX platform still lags other platforms and does not yet support this version of Java. Developers often cannot afford to ignore this platform, since the very raison dtre of the Java platform is platform independence. JMatter has a generic solution to this general problem of launching a given le, with the result being the launching of the desktops default-designated reader for the document in question, combined with the action of opening the le in question within that viewer. This solution will work with earlier versions of Java (e.g. Java 5), and can be used to open PDF les, and other documents (.doc, .txt, .xls, .csv, etc..) in a platform-independent manner. Heres example code that uses a simple strategy for launching a dynamically generated pdf le:
File reportFile = File.createTempFile("report", ".pdf"); reportFile.deleteOnExit(); // write to the file.. com.u2d.utils.Launcher.openFile(reportFile);

In the above example we use Javas API to create a temporary le in a platformindependent manner and specify that the le should be deleted after the end-user quits the application. Then we simply call the static method Launcher.openFile(le) which does the rest. This has been veried to work on windows, apple, and linux platforms reliably. The Launcher utility in addition provides the following useful two methods: 1. public static void openInBrowser(String url) 2. public static void openInEmailApp(EmailMessage msg) public static void openInEmailApp(String mailtoURL)

12.6. SUMMARY

161

12.6

Summary

In this chapter weve seen the ease with which we can integrate wizards (assistants) into an already powerful user interface. This wizard feature has already been used in other contexts to produce complex wizards, that break down complex new patient forms at medical clinics into a set of smaller steps. Most of us are too familiar with the amounts of information a patient or guarantor must enter when rst visiting a medical institution (in the United States, at least). The JMatter framework attempts to be as open as possible. Wizards are not the only way to inject custom user interface features into JMatter applications. JMatter was designed to allow you to write your own custom views for objects and plug them into your existing JMatter applications, which is the topic of our next chapter. Weve also seen the CSV Export feature, a nice though simple mechanism for exporting data out of your application. Of course, there already exist many tools to export and process your applications data. Its already easily accessible in that all the information resides in an open database system. Finally, we also see that JMatter provides an avenue for producing PDFs by integrating and leveraging the open source JFreeReport API. Ive personally also written directly against the underlying iText PDF library to produce and display PDFs directly as a consequence of a command invocation.

162

CHAPTER 12. WIZARDS, CSV EXPORT, AND PDFS

Chapter 13

Calendars and Maps


Many types exhibit elds such as time spans: sessions, appointments, meetings, visits and more. Likewise many pieces of information have location information: a latitude and longitude. Such information is more naturally interpreted visually. We saw an example of scheduling in the Sympster demo application. JMatter supports both a simple and a fancy model for integrating scheduling visually into its graphical user interface. For mapping, JMatter integrates Swingx-ws for viewing entities on a map, in a fashion similar to what weve become accustomed to with Google maps.

13.1

Calendars

Section 6.5 on page 74 discussed a way to expose a fully-functional calendar view into the Sympster sample application. This calendar view has some attractive features such as the ability to view multiple schedules (we saw different schedules for distinct locations at a conference). It took only abiding by a few simple conventions to do this integration. JMatter now calls this form of calendaring integration its fancy calendaring model. JMatter now exposes a second, simpler calendaring integration model that makes almost no requirements on your model and yet in some ways is even more powerful than the former. Lets say we need to model a meeting. All we need to do is dene a eld of type TimeSpan and extend the base type CalEvent. This base type is now only a marker base class. We are not required to provide any metadata, theres no need to implement or override any methods, and were free to name the model objects timespan eld however we see t. JMatter will detect the type in question and automatically identify the timespan eld in question. JMatter then exposes a command on the type named Browse

163

164

CHAPTER 13. CALENDARS AND MAPS

in Calendar, which brings up a calendar view with both custom week and day views. You can navigate this view in time. Whats special is that this custom calendar view is nothing but a list view. It lists instances of a given type. As you already know, the default list view that appears as a consequence of invoking the Browse command is always adorned with a query panel at the top. This means that the list can be dynamically ltered. This calendar view sports the same query panel. So, not only can we browse information in time, but this feature is further combined with search capabilities. So if were looking at a calendar thats too crowded with meetings or talks, and were looking for a meeting at a specic location, we can lter the listing. In gure 13.1 we see a calendar view with four talks. Note the query panel at the top.

Figure 13.1: Calendar view with four talks The next gure shows the same listing ltered by title (were looking for talks with the word Swing in their title, just as an example).

13.2. MAPS

165

Figure 13.2: Filtered Calendar View Separately, one enhancement to this calendaring view worth noting is that durations can now be edited directly from within this view by simply dragging the bottom edge of event views to the desired end time. So calendaring is even simpler than it used to be, the integration is dead simple, requiring only the extension of a marker base type, and the features are more compelling, with search being pre-integrated into calendaring views.

13.2

Maps

Analogous to having integrated custom views for types with a time component, JMatter has begun providing custom views for types with a location component. For this feature, JMatter integrates the work done by the Sun Swing team on the project named Swingx-ws (where ws stands for web services). This implementation is a little less mature compared to calendaring but has come along nicely. Figure 13.3 shows an example route for a ight itinerary that leverages JMatters mapping support.

166

CHAPTER 13. CALENDARS AND MAPS

Figure 13.3: A Flight Route In this particular implementation I embellished the default map view with an additional layer using curved paths to delineate the routes segments. The waypoints on the map represent actual model objects. We can right-click on one and edit it if we wish. The basic contract is that a type extend AbstractComplexMappableEObject and implement the single method specied in the contract with the interface MappableEO:
public GeoPoint geoPosition();

You guessed it: a GeoPoint is a JMatter type, which means that, among other things, it knows how to persist itself to database. A GeoPoint encapsulates a latitude and longitude. The specic ight support application from which the previous screenshot was taken has a model object named Airport which implements this contract. In return, each instance will bear the command View on Map, which will automatically bring up a map view and add the waypoint in question. From there, users can further interact with the map. Further, list views for Airports automatically bear the list command View on Map as shown in gure 13.4.

13.2. MAPS

167

Figure 13.4: List Command: View on Map This particular list happens to be the search results of a save query for Airports (and Heliports) in the vicinity of Austin, Texas. The next gure shows the resulting map view with the waypoints in question. A map view is again nothing but a list view.

168

CHAPTER 13. CALENDARS AND MAPS

Figure 13.5: List Command: View on Map The map is zoomable of course. This means that if we wish to, we can take a closer look at the Lakeway aireld, as shown in the next gure.

Figure 13.6: Zooming in on a Waypoint

13.2. MAPS

169

Future enhancements to mapping support will likely be in the area of enhancing the map view with a query panel. In addition, were considering tying panning a map with fetching all waypoints bounded by the geographical rectangle that the map represents, which will make feasible browsing large amounts of information on a map. I would like to thank Andres Almiray for suggesting and prototyping this integration into JMatter.

13.2.1

Maps: An atlernative to view embedding

As nice as it is to be able to embed map views directly in a JMatter application, sometimes a simpler solution may be the more elegant in a particular context. For example, Ive recently been working on a client application for persons who need to service a specic address. In that context, I decided to add the ability for the end user to plot the given address directly in google maps by launching a web browser:

public static final String googleMapsUrlPattern = "http://maps.google.com/maps?q=%s"; @Cmd public void ViewInGoogleMaps(CommandInfo cmdInfo) { String address = String.format("%s, %s %s %s", street, city, stateCode, zip); String url = String.format(googleMapsUrlPattern, EmailMessage.htmlEscape(address)); Launcher.openInBrowser(url); }

All were doing above is constructing the proper url to bring up an address using google maps, and nally launching the url in a browser. Its that easy.

170

CHAPTER 13. CALENDARS AND MAPS

Chapter 14

Customized Views and Editors


Its nice for a framework to support the automatic generation of views for various objects. Weve also seen how the base user interface can be augmented with calendaring features, wizards, and support for producing PDFs. However, its equally important for a framework to remain exible and to allow for the construction of custom views as well. JMatters primary view mechanism at the moment is its Swing-based view mechanism. Other view mechanisms might be constructed in the future, including possibly a web-based user interface. In this chapter Id like to demonstrate through examples various ways in which custom views can be integrated into the Swing view mechanism.

14.1

Complex, or Composite Views

The demo-apps subdirectory contains a project, CustomUI, designed specically to illustrate how this is done. It is similar to our contact manager: Theres a Contact class and an Address class. The idea is that wed like to be able to customize the way Addresses appear on the screen; specically, the way that the form view for addresses is laid out. The default form view is nice. Figure 14.1 displays the default view for the address property of the Contact class.

171

172

CHAPTER 14. CUSTOMIZED VIEWS AND EDITORS

Figure 14.1: Standard Form View the Contact.address Field Lets say that wed prefer to display addresses in such a way that the eld captions are placed above the eld editors (instead of appearing to their left), and that wed like to lay out the city, state, and zip elds all on the same line, instead of having them appear one below the other, as shown in Figure 14.2.

14.1. COMPLEX, OR COMPOSITE VIEWS

173

Figure 14.2: Desired view for Addresses It turns out that JMatters FormView is already parametrized such that, if you prefer, you can designate that labels appear above their editors instead of to their left. All you need to do is revise the value for the labelEditorLayoutHorizontal property in your applications spring conguration context le src/applicationContext.xml as shown below:

<bean id="view-mechanism" class="com.u2d.view.swing.SwingViewMechanism" factory-method="getInstance"> <property name="appSession" ref="app-session" /> <property name="labelEditorLayoutHorizontal" value="false" /> </bean>

Lets proceed by pretending that this feature was not available. We must do two things: 1. Override the method getMainView() on the Address class, to return a new view 2. Implement the custom view for addresses; this process is similar to the way we traditionally build views in Swing

174

CHAPTER 14. CUSTOMIZED VIEWS AND EDITORS

The rst step is straightforward:


public EView getMainView() { return new CustomAddressView(this); }

Now, for the implementation. We could implement the UI by extending from Swings JPanel, like this:
public class CustomAddressView extends JPanel implements ComplexEView, Editor { private Address _addr; JComponent line1View, line2View, cityView, stateView, zipView; public CustomAddressView(Address address) { _addr = address; buildUI(); } private void buildUI() { line1View = (JComponent) _addr.getLine1().getView(); line2View = (JComponent) _addr.getLine2().getView(); cityView = (JComponent) _addr.getCity().getView(); stateView = (JComponent) _addr.getStateCode().getView(); zipView = (JComponent) _addr.getZipCode().getView(); FormLayout layout = new FormLayout("pref, 10px, pref, 10px, pref", "pref, pref, 10px, pref, pref, 10px, pref, pref"); CellConstraints cc = new CellConstraints(); DefaultFormBuilder builder = new DefaultFormBuilder(layout, this); // add caption.. builder.add(new JLabel("Line 1:"), cc.xyw(1, 1, 5)); builder.add(line1View, cc.xyw(1, 2, 5)); builder.add(new JLabel("Line 2:"), cc.xyw(1, 4, 5)); builder.add(line2View, cc.xyw(1, 5, 5)); builder.add(new JLabel("City:"), cc.xy(1, 7)); builder.add(new JLabel("State:"), cc.xy(3, 7)); builder.add(new JLabel("Zip:"), cc.xy(5, 7));

14.1. COMPLEX, OR COMPOSITE VIEWS

175

builder.add(cityView, cc.xy(1,8)); builder.add(stateView, cc.xy(3, 8)); builder.add(zipView, cc.xy(5, 8)); } public EObject getEObject() { return _addr; } // as a composite view, this particular class may not // necessarily be interested in binding to the model // and listen to changes. to the extent that i use // the jmatter views for the subparts of the address, // they will be listening directly to the parts. public void detach() { } public void stateChanged(ChangeEvent e) { } public void propertyChange(PropertyChangeEvent evt) { } public boolean isMinimized() { return false; } public int transferValue() { int result = 0; result += ((Editor) line1View).transferValue(); result += ((Editor) line2View).transferValue(); result += ((Editor) cityView).transferValue(); result += ((Editor) stateView).transferValue(); result += ((Editor) zipView).transferValue(); return result; } public void setEditable(boolean editable) { ((Editor) line1View).setEditable(editable); ((Editor) line2View).setEditable(editable); ((Editor) cityView).setEditable(editable); ((Editor) stateView).setEditable(editable); ((Editor) zipView).setEditable(editable); } public boolean isEditable() { return ((Editor) line1View).isEditable(); } }

Lets review this code. Here I am using the excellent JGoodies Forms framework to layout a form by hand, so to speak. JGoodies DefaultFormBuilder makes this pretty easy. Similar code could also be produced with the help of a visual form designer, such as the Abeille Forms Designer. Note however, that there are additional responsibilities that this class must fulll:

176

CHAPTER 14. CUSTOMIZED VIEWS AND EDITORS

1. The class must implement the ComplexEView interface 2. If the class will also participate in the editing process, it must implement the Editor interface In this case, the ComplexEView interface is fairly simple. Some of the methods have no-op implementations (detach(), stateChanged(), propertyChange()). Every view can, at its discretion, attach itself as a listener to the object model and thus receive model change notications. In this case, were dealing with a composite view, and each of the sub-views already listens to changes to the parts, so we dont technically need to listen to model changes here. Views must also make sure to detach themselves from the model objects when theyre destroyed. Its very important that the detach() method properly do this. A careless implementation can easily introduce a memory leak into the application as views are created and their memory not reclaimed because they may still be attached to a model object whose lifetime is typically longer than its views. The Editor interface is also fairly straightforward. The setEditable() method is called when the model objects state toggles from Read to Edit (and back), thus giving the user interface a chance to update itself accordingly (if so desired). Notice also that transferValue() is called before an object is saved, allowing the view a chance to bind the newly entered data back to the model object (or possibly raise a validation exception, in which case the save operation is vetoed. The integer value returned by this method is an indication of the number of validation errors, which is also displayed by the framework in such circumstances.

14.2

A Custom View for Sympster Sessions

Heres a more compelling illustration of customizing a view for an object: the Sympster demo application was recently further customized with a custom view for its Session class. In this situation, I wanted to reuse JMatters default FormView which handles the editing process beautifully and saves me a lot of work. On the other hand, I wanted a more compelling view for sessions in read state, as shown in gure 14.3.

14.3. THE SELF DEMO APPLICATION

177

Figure 14.3: Customized View for Session JMatter provides a class named CustomReadView which automatically composes JMatters FormView in edit state with a custom view that you provide for the read state, as shown in the following code snippet from the class Session where the getMainView() method is overridden correspondingly:
public EView getMainView() { return new CustomReadView(new SessionView(this)); }

Please refer to the implementation of SessionView in the Sympster demo application for the details of its implementation. One note worthy of mentioning is that the implementation leverages JMatters css4swing library to style itself, which I discuss in chapter 17 on page 197.

14.3

The Self demo application

Yet another way to augment JMatter with hand-crafted views and widgets is illustrated through the bundled demo application named Self. The model for this application is trivial on purpose: it consists of a Space that contains Balls. The space has one additional property: the temperature within the space. In this particular scenario, it is quite unpallatable to view these objects through forms when it would be so much more compelling if their visual representations were represented directly in the UI. Any command you write that returns an object of type View or JComponent will be displayed by JMatter upon invocation. The Self demo application takes advantage of this feature:

178

CHAPTER 14. CUSTOMIZED VIEWS AND EDITORS

public class Space { ... @Cmd(mnemonic=s) public View Show(CommandInfo cmdInfo) { return new SpaceView(this); } ...

Running this application, we can create a space, and add a few balls into our space. We can further set the temperature. I created two balls: a lled red ball with radius 30, and a blue ball with radius 80, and my temperature was 30 degrees celsius. Proceeding with invoking the Show command, I can expose my custom view SpaceView directly in JMatter:

Figure 14.4: The Self Demo Application The screenshot doesnt really do it justince since the balls are moving withing the space at a certain speed. Try to change the temperature within the space to, say, 50 degrees. This will cause the balls to move faster. Technically, this custom view could also have been implemented by wrapping it in a CustomReadView as we did in the previous example.

14.4. CUSTOMIZING LAYOUT

179

14.4

Customizing Layout

JMatter provides a means through which a layout for a form can be dened by using the open-source Abeille Forms Designer. By placing placeholder components in the layout and giving each a name matching a model objects eld name, JMatter can be made to use the specied layout when displaying the form in question. Abeille allows us to serialize the form designs denition to a .jfrm le which we place alongside our source code (JMatters build le automatically copies these les to the classpath as part of the build process) in a le we name after the model object whose view we want to customize. The CustomUI demo application provides an example implementation.

14.5

Atomic Views

JMatter denes the notion of atomic types. Examples include representations for booleans, dates, text, zip codes, social security numbers, percentages, integers, oats, etc.. Theyre dened in the package com.u2d.type.atom. This section describes how to write a custom view and/or editor for a given type. Lets take BooleanEO as an example. Here is the implementation for the default renderer for booleans:

public class BooleanRenderer extends JLabel implements AtomicRenderer { public void render(AtomicEObject value) { BooleanEO eo = (BooleanEO) value; setText((eo.booleanValue()) ? "Yes" : "No"); } public void passivate() { } }

The interface AtomicRenderer has essentially a single method. You can ignore the passivate() method for now (were considering making a design revision where views are pooled, and then re-used for different atomic types, in which case this method could be used to clean up the view before its re-used). So basically one implements the render() method. This method is handed a model object that it must render. So in this case, the renderer is given an instance of a BooleanEO which it uses to paint the text Yes or No on a JLabel. To write a custom Editor for a type, you must implement two methods: render() and bind(). Heres the denition of the interface that one must implement:

180

CHAPTER 14. CUSTOMIZED VIEWS AND EDITORS

public interface AtomicEditor extends AtomicRenderer { public int bind(AtomicEObject value); }

And heres an example implementation, again for the BooleanEO type:


public class BooleanCheckboxEditor extends JCheckBox implements ItemListener, AtomicEditor, ActionNotifier { public BooleanCheckboxEditor() { addItemListener(this); } public void itemStateChanged(ItemEvent e) { setText( (isSelected()) ? "Yes" : "No" ); } public int bind(AtomicEObject value) { BooleanEO eo = (BooleanEO) value; eo.setValue(isSelected()); return 0; } public void render(AtomicEObject value) { BooleanEO eo = (BooleanEO) value; setSelected(eo.booleanValue()); itemStateChanged(null); // text synch with checkbox } public void passivate() { } }

The bind() method is responsible on setting the newly edited value back to the model object. Heres a second implementation for a BooleanEO editor that uses a pair of radio buttons instead:

public class BooleanRadioEditor extends JPanel implements AtomicEditor { private JRadioButton _yesBtn, _noBtn; public BooleanRadioEditor() { _yesBtn = new JRadioButton("Yes");

14.5. ATOMIC VIEWS

181

_yesBtn.setOpaque(false); _noBtn = new JRadioButton("No"); _noBtn.setOpaque(false); _yesBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { _yesBtn.setSelected(true); } }); _noBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { _noBtn.setSelected(true); } }); ButtonGroup group = new ButtonGroup(); group.add(_yesBtn); group.add(_noBtn); FormLayout layout = new FormLayout("pref, 3px, pref", "pref"); DefaultFormBuilder builder = new DefaultFormBuilder(layout, this); CellConstraints cc = new CellConstraints(); builder.add(_yesBtn, cc.xy(1, 1)); builder.add(_noBtn, cc.xy(3, 1)); } public void render(AtomicEObject value) { BooleanEO eo = (BooleanEO) value; JRadioButton btn = (eo.booleanValue()) ? _yesBtn : _noBtn; btn.setSelected(true); } public int bind(AtomicEObject value) { BooleanEO eo = (BooleanEO) value; eo.setValue(_yesBtn.isSelected()); return 0; } public void passivate() { } }

The JMatter codebase is rife with examples of atomic editors and renderers. Use them as the basis for creating your own implementations.

182

CHAPTER 14. CUSTOMIZED VIEWS AND EDITORS

14.5.1

Specifying the Default Editor and Renderer

Specifying the default renderer and editor for a given type is straightforward. JMatter denes the interface ViewMechanism. The Swing implementation of that interface is SwingViewMechanism. This interface denes a litany of methods that specify the components for the entire user interface. By revising the corresponding method for a given view mechanism, you control the user interface. For our above implementations of a boolean editor and renderer, and assuming the SwingViewMechanism, youd revise the implementations of getBooleanRenderer() and getBooleanEditor() respectively for the BooleanEO type:
public AtomicRenderer getBooleanRenderer() { return new BooleanRenderer(); } public AtomicEditor getBooleanEditor() { return new BooleanRadioEditor(); }

Of course, if youre going to be implementing a custom view for a more complex or composite object, then youre in complete control of the rendering and editing process. The frameworks view mechanism in general is extremely modular. Its easy to override one small aspect and plug it right into the existing view mechanism to fundamentally change one aspect of the user interface, whether its by providing your own implementation of a FormView (or embellishing the existing one), or by customizing the widgets that represent associations.

Chapter 15

Localization and Internationalization


I would like to thank Felix Torre for assisting in the development of support for localization (l10n) in JMatter, and Marco Meschieri for meticulously going through the codebase to extract captions and other text so that they could be localized. This chapter documents the current support for l10n in JMatter. The basic requirement is to be able to deploy a single application to a diverse population, in any of a combination of languages. For example, we may have both English-speaking and French-speaking users. Fundamentally, JMatter resorts to one aspect of the Java language that was designed for localization: the notion of resource bundles. JMatter uses propertyle based resource bundles. Multiple properties les are created. Each follows a certain convention to designate what language and locale it corresponds to, by combining a base name with a sufx. Look at the Sympster demo application for example. You will nd three les: locale-metadata.properties, locale-metadata_fr.properties, and locale-metadata_es.properties. So each sufx, _fr or _es, is a language designation: the former is the code for the French language, while the second designates Spanish. Resource bundles imply a specic hierarchy for retrieving values for specic keys in these property les: we check the computers specic language and country. Lets say were in Canada, where the language is fr and the country is CA. The system will look for the le locale-metadata_fr_CA.properties, falling back to the more generic _fr le, and nally, falling back to the most generic property le. There exist two sets of locale-metadata les. The rst set is located in jmatter/resources/app. In this le youll nd localization strings that apply to the framework in general. The second set of locale les are project-specic. So in your project, in the resources/ subdirectory, youll nd the second set of locale-metadata les

183

184

CHAPTER 15. LOCALIZATION AND INTERNATIONALIZATION

JMatter denes keys for retrieving all the labels and text rendered on the login dialog box. Here is how theyre specied in the _fr resource bundle:
# Login Dialog # =============================== logindlg.title=Entrez logindlg.lbl.username=Nom Dutilisateur: logindlg.lbl.pwd=Mot de passe: logindlg.msg.login=Entrez Sil vous plait.. logindlg.msg.failed_auth=Mauvais credentiaux; Essayez encore une fois.. logindlg.msg.user_locked=Votre compte est verouille; \ Contactez ladministrateur svp..

JMatter also denes a convention for specifying type labels, command labels, and eld labels that are shared by all applications:
# JMatter Global Localization Entries # =================================== Command.Save=Sauve Command.Cancel=Abandone Command.Copy=Copie Command.Paste=Colle Command.SaveAndClose=Sauve et Ferme Command.Open=Ouvre Command.Edit=Edite Command.Delete=Efface Command.Refresh=Rafraichi ComplexType.New=Fait Nouveau ComplexType.Browse=Liste ComplexType.Find=Trouve User=Utilisateur Users=Utilisateurs User.username=Nom dutilisateur User.password=Mot de passe User.locked=Verrouill User.photo=Photographe User.role=rle User.desktop=criture-bureau

Here we see that generic commands, shared by all types, are specied as Command.<commandname>. Generic type commands are specied using the key ComplexType.<commandname>. Other type commands and type elds are likewise specied using the key: <typename>.<eldname|commandname>. When dealing with aggregate elds, you can use a multiple dot notation, as in Speaker.contact.homePhone (see below).

185

You can specify a localization for a eld across multiple types shared in a base class by simply using the base class name in the eld path. For example (French):
AbstractComplexEObject.createdOn=Cre a la date

Here are some application-specic label designations for French, for the Sympster application:
# Application-Specific Localization Example Entries # ================================================= Speaker=Presenteur Speakers=Presenteurs Speaker.name=Nom Speaker.title=Titre Speaker.bio=Biographie Speaker.photo=Photo Speaker.AddTalk=Ajoute Une Presentation Speaker.contact.homePhone=Telephone Maison

Note also that plural designations can be provided. The key is simply the plural name for the type in English. Here in the USA I can test how my application might look to a French speaker by revising the locale on my system, or by forcing a locale through a system property, as illustrated by the run target in build.xml:
<target name="run" description="run app" depends="genhbm"> <java classname="${main.class}" classpathref="class.path" fork="true" maxmemory="192m"> <!-- to test localization, uncomment this.. <sysproperty key="user.language" value="fr" /> --> </java> </target>

Uncomment the <sysproperty> line and set its value accordingly. Weve included a couple of snapshots of the resulting localized application (gures 15.1 and 15.2).

186

CHAPTER 15. LOCALIZATION AND INTERNATIONALIZATION

Figure 15.1: Login dialog localized for French

Figure 15.2: Partially localized Sympster Application (French) We see a number of the commands now use French captions. The speaker is called a Presenteure, the eld name becomes Nom and title becomes titre. Not all the text appears in French simply because I didnt provide a full list of values for all commands and elds. The gures dont show how the context menus also

15.1. STATES

187

become localized. Open becomes Ouvre, etc..

15.1

States

When dealing with state machines, as we saw for example in the IssueMgr demo application, the state names can also be localized. For example, heres how the state names for issues are localized to French in IssurMgrs locale-metadata_fr.properties le:
IssueState.New=Nouveau IssueState.Assigned=Assign IssueState.Accepted=Accept IssueState.Fixed=Reparr IssueState.Closed=Ferm

15.2

Generic UI Localization

The user interface also has elements that need to be localized. For example Java Swing defaults to a resource bundle named uidefaults to pick up translations for tooltips such as a windows minimize button tooltip. JMatter will automatically load custom ui defaults specications from the le jmatter/resources/app/uidefaults_??.properties For example, the gure below shows some hebrew translations for ui defaults loaded by JMatter (the le name is uidefaults_iw.properties):

Figure 15.3: UI Defaults Localization (e.g. Hebrew)

15.3

Right-To-Left

JMatter will work with languages that have non-latin alphabets, and ones that are right-to-left such as Hebrew or Arabic. Check out the Sympster demo-app in

188

CHAPTER 15. LOCALIZATION AND INTERNATIONALIZATION

Hebrew for example. In the USA, you can simply override the locale by uncommenting this line in the Sympster build le:
<sysproperty key="user.language" value="he" />

Following are a couple of screenshots.

Figure 15.4: Hebrew Login Dialog

15.4. SUMMARY

189

Figure 15.5: Sympster Localized for Hebrew

15.4

Summary

Localization support in JMatter is by no means complete or exhaustive. For example, at the moment support for the proper date and currency formats for different locales needs work. We hope that future versions will esh out this support completely.

190

CHAPTER 15. LOCALIZATION AND INTERNATIONALIZATION

Chapter 16

Child Projects
This chapter provides a more detail information about the structure of JMatter project directories, and documents a JMatter applications build le.

16.1

Creating Child Projects

The framework has its own build le, used to compile the framework itself. This build le contains a target: new-project-ui that automates the creation of a JMatter project. We walked through using this target in chapter 4. Invoking this target brings up a simple user interface, shown in gure 4.1 on page 32. We specify: 1. The project name 2. The base directory 3. Whether we wish to produce a standalone or dependent project The project name is required. It is also used as the name of the directory that contains the project les. If the base directory is not specied, we default to creating the project as a sibling directory of the framework itself. The last option needs a slightly lengthier explanation. A standalone project has no external dependencies. Not only is the child project structure created, but all libraries necessary to run it are containing within the project, in the lib/ subdirectory. That is, a copy of the JMatter framework is in a sense frozen into the child project. Standalone projects are therefore not subject to changes to the framework that might take place after its creation (unless the JMatter jar le and other dependent jar les are manually replaced).

191

192

CHAPTER 16. CHILD PROJECTS

When creating a dependent project, its build le is told where the JMatter framework is located and so it can reference the JMatter frameworks .class les directly, as well as any .jar les that the framework itself leverages. Both modes are useful in different contexts. For developers with in-depth knowledge of the framework, that expect expect perhaps to make changes to the framework as they develop their application, its convenient not to have to repackage the framework jar le and copy it to the child project each time a change takes place. Dependent child projects would pick up these changes immediately. So therein lays the tradeoff. It isnt particularly difcult to change ones project from being dependent to being standalone or vice versa. However, at the time of this writing, there is no magic ant target that will do this work on our behalf.

16.2

Directory Structure and Files

The main directories that youll see after creating a new project are:
src, test, doc, resources

Each directorys name fairly clearly implies its role. The base directory for Java source code is src, while test is the base directory for tests. The doc subdirectory contains a basic README le. The doc/ directory is of course an ideal location for your projects own documentation. The resources folder is interesting; its composition is summarized in the table below.

16.2. DIRECTORY STRUCTURE AND FILES

193

Directory or File images/

styles.css

model-metadata.properties local-metadata_<locale>.properties

hibernate.properties

resources/jws

wings/ and echo2/

src/class-list.json

src/persistClasses.st

Description Where to place icons for model objects, the image for the splash screen, and other image resources that your application will use. Default stylesheet for JMatter; governs how the JMatter user interface is styled (see chapter 17). Where to specify required elds, and eld default values. Use for localization: provide translations for type names, command captions, eld captions, and more in order to produce a user interface that is properly translated for the given locale. Governs database conguration: database dialect, driver class name, connection url, username and password. Contains resources necessary to bundle the application as a java webstart distribution (see chapter 18) This requires some explanation. Were in the process of developing a web-based user interface for JMatter. At the time of this writing, this work is not yet nished. Resources necessary to construct the web application distribution resides in these directories. (Optional) This is where you can precongure your applications classbar: that is, specify here the list of model objects you wish to expose to your user interface. You typically will not need to edit this le. This template is resolved at build time to list the persisted entities in your application. The list is derived from the @Entity annotations in your class les. It is passed to Hibernate via a Spring conguration le.

All child projects come with an ant build le. This build le generates a number of directories for the purpose of maintaining artifacts. Lets discuss these:

194

CHAPTER 16. CHILD PROJECTS

db If you congure your application to use a lightweight or le-based database, such as H2 or hsqldb, the database les by default reside in this subdirectory build/classes Your application is compiled to this directory. All resources are also copied here, including images and hibernate mapping les (the latter being generated, not copied) jws-dist Used to assemble the Java WebStart distribution dist The Java WebStart distribution is packaged as a .war le and copied to this directory

16.3

Build File Targets

Lets now turn our attention to the child projects ant build le. Here is a listing and description of the relevant targets.
compile compile-tests genhbm jar jar-model jws-dist macappbundle reveng-db run run-test run-tests schema-export schema-update shellscript test-report compile code compile tests generate hbm.xml files jar it jar just the model create java webstart distribution create macosx app bundle Reverse engineer an existing database schema.. run app run a test class run tests export schema to db update db schema produce runnable shell script produce junit reports

Default target: run

There isnt that much to say beyond the default description of these targets. JMatter generates Hibernate hbm.xml les to the build/classes directory. The run target is useful while developing. You typically dont need to invoke many of these targets. Invoking schema-export for example will automatically compile the code and generate the mapping les rst. Also, if youre working with a dependent project, any changes to the framework codebase will automatically be recompiled rst. The jar-model target is useful in the context of the JMatter Application Browser (see chapter 19). For more detail about the reveng-db target, see 20.1 on page 219.

16.3. BUILD FILE TARGETS

195

Other targets worth pointing out include shellscript and macappbundle. The rst generates a run.sh (or run.bat on win platforms) to launch the application. On Linux, going from such a script to a desktop-launched application, complete with icon, is trivial. The latter is specically for macosx users and bundles the application as a .app le. Chapter 18 on page 209 walks you through deploying your project via Java WebStart.

196

CHAPTER 16. CHILD PROJECTS

Chapter 17

Styling the UI with CSS


Cascading Stylesheets (CSS) is a web technology. It is supported by modern web browsers to style user interfaces. CSS is simple and elegant. It is also powerful. It has an aspect-like design in that styles for parts of a user interface can be specied in a manner that is orthogonal from the rest of an application: it is a cross-cutting concern. JMatter comes with built-in support for a subset of the CSS that I believe to be applicable to Javas Swing technology. By default, JMatter will automatically load the le resources/styles.css on startup, and interpret and apply the rules contained within that stylesheet. Stylesheets consist of rules, and rules consist of selectors and declarations. Let us begin with a description of the CSS engine itself and specically what subset of CSS is supported, and how it is adapted to Swing. We will then turn our attention to the default stylesheet.

17.1
17.1.1

JMatters CSS Engine


Selectors

JMatters CSS implementation supports both simple and composite selectors. Simple selectors match a component by any of the following, or a combination thereof: 1. its type 2. a semantic style name (a css class name) 3. an id

197

198

CHAPTER 17. STYLING THE UI WITH CSS

In the web world, a component type is designated by its corresponding tag name, such as <h1> or <p>. In Swing its designated by its class name, for example: JLabel. Composite selectors allow the expression of a path. Theyre composed of two or more simple selectors, related through a combinator: 1. the Child combinator (denoted by the character >) 2. the Sibling combinator (denoted by the character +) 3. the Descendant combinator (denoted with a space)

17.1.2

Adapting Selectors for Swing

By default, you can reference any Swing component class that is a member of the package javax.swing without qualifying it. Some examples include: JPanel, JLabel, and JButton. Any component that is assignable from the referenced class name will be matched. That is, if you write a subclass of JLabel, and write a CSS rule like this:
JLabel { background-color: blue; }

The rule will apply to instances of the subclass as well (this is not true the other way around of course). A parsing ambiguity arises if one wished to reference a fully-qualied class name in a selector. Lets say we had a rule such as:
JLabel.special { background-color: blue; }

If the component type were referenced fully-qualied:


javax.swing.JLabel.special { background-color: blue; }

17.1. JMATTERS CSS ENGINE

199

It would be less clear (though not impossible to disambiguate) that we were referencing a component marked with a css class name. JMatters CSS implementation therefore does not allow fully-qualied class names in selectors. This CSS implementation adopts and leverages CSS3s namespaces (thanks to Tiago Silveira) module to resolve this issue. CSS3 namespaces were designed to resolve the issue of possibly clashing namespaces in different xml vocabularies. To reference a type in a different package, you must dene a namespace for it, like so:
@namespace l2f com.l2fprod.common.swing l2f|JOutlookBar { color: olive; }

The two main items to note here are: 1. A @namespace css rule is dened and aliased as l2f. 2. To reference a type selector in that namespace, concatenate the namespace id and type name with the vertical bar delimiter (|).

17.1.3

Assigning Components CSS class names

On the web, components are given semantic style names by annotating them with an html attribute, as in: class=title. JMatters CSS implementation provides an API method for assigning a css class name to a component:
ComponentStyle.addClass(componentRef, "title");

Since components can have more than a single semantic class name, one can invoke the above method repeatedly. Theres also a corresponding method for removing a class assignment:
ComponentStyle.removeClass(componentRef, "title");

One can likewise assign an id to a component with:


ComponentStyle.setIdent(componentRef, "btn103");

200

CHAPTER 17. STYLING THE UI WITH CSS

The above are all static methods. Application developers neednt concern themselves with this because the work associated with dening style names and annotating a user interface is a part of the task of writing that user interface. In the case of JMatter, the user interface is already written and is already annotated. To customize the style of a JMatter application, all you need to concern yourself with (besides knowing what semantic names to reference) is editing the stylesheet itself. You might however want to take a look at the Sympster demo application where a custom view for a type is written that leverages CSS.

17.1.4

Values

Of the myriad of ways in which measures can be specied in CSS, JMatter supports only a subset: 1. Font sizes must be specied in pts 2. Borders, margins, and padding must be specied in pxs 3. Colors can be specied either using the sixteen predened color names, the six-digit hex notation, or the shortened three-digit hex notation. The rgb() function is not supported at this time 4. Only the line styles dotted, dashed, and solid are supported at this time 5. Only the generic font family names serif, sans-serif, and monospace are supported at this time

17.1.5

Properties

A subset of the CSS dened properties is supported at this time. They are:
cursor color background-color background-image font-family font-size font-weight font-style font border-color, border-left-color, border-right-color, border-top-color, border-bottom-color border-style, border-left-style, border-right-style, border-top-style, border-bottom-style border-width, border-left-width, border-right-width, border-top-width, border-bottom-width

17.2. THE JMATTER STYLESHEET

201

border margin, margin-left, margin-right, margin-top, margin-bottom padding, padding-left, padding-right, padding-top, padding-bottom

JMatters CSS implementation also supports these CSS3 properties, but only on SwingX components that allow for the delegation of background painting:
opacity border-radius border-top-left-radius, border-top-right-radius, border-bottom-left-radius, border-bottom-right-radius

17.1.6

CSS Inheritance

It is important to mention that this engine supports CSS inheritance: that [inheritable] properties inherited from containing components are applied as well.

17.2

The JMatter Stylesheet

Lets study the le resources/styles.css one piece at a time. First comes an import declaration:
@namespace jm com.u2d.view.swing

This allows me to reference custom components from JMatters Swing view mechanism in selectors. Here are some examples:
JDesktopPane { background-color: #7684FF; } jm|FormPane { background-color: #fffaf0; }

The rst rule customizes the background color of the desktop pane. The selector matches a standard swing component. The second rule customizes the background color of form panes (using an off-beige color). Here are two more rules:

202

CHAPTER 17. STYLING THE UI WITH CSS

.command { font-style: italic; } .default-button { font-weight: bold; }

Views of commands in JMatter are annotated with the CSS class name command. I have chosen to emphasize that commands are active by italicizing their views (views of commands are either JMenuItems or JButtons). Furthermore, Swing (and forms) has the notion of a single command being designated as the default command on a form. Default buttons are given a little extra attention, such as interpreting pressing of the Enter key on the form as implying the invocation of the default command. Here you can specify how its view should be styled. Note how both rules .command and .default-button match for default commands so that their properties are combined. This CSS engine will make sure to apply the more specic rule in case of a conict. Here is a rule that styles the text in title views:
.list-title, .instance-title { color: #400; font-weight: bold; font-size: 16pt; }

We are applying the same set of declarations to both list titles and instance titles, so we grouped the selectors together. Here are two more semantic styles:
.required { color: blue; font-weight: bold; } .validation-msg { color: red; font-style: italic; }

17.2. THE JMATTER STYLESHEET

203

Here we specify how to style the captions for required elds and validation error messages. Feel free to customize these (and any other styles) as you see t. And nally, this rule styles the large semi-transparent message panel that appears for 2-3 seconds to acknowledge various actions, for example when one creates and persists a new instance to database:
.feedback-pane { color: white; background-color: black; font-size: 24pt; font-weight: bold; padding: 30px; border-radius: 24px; opacity: 0.7; }

Styling JMatter UIs is now much more accessible thanks to CSS. Since CSS is a technology you might already be familiar with, and since this implementation adheres strictly to the specication (i.e. it doesnt invent its own properties), you should be able to jump in right away without a learning curve.

17.2.1

The complete stylesheet

Below is a copy of the complete stylesheet, for reference.


@namespace jm com.u2d.view.swing @namespace types com.u2d.view.swing.atom JDesktopPane { background-color: #7684FF; } jm|FormPane { background-color: #fffaf0; padding: 5px; } .command { font-style: italic; } .list-title, .instance-title, .title {

204

CHAPTER 17. STYLING THE UI WITH CSS

color: #400; font-weight: bold; font-size: 16pt; } .list-title-panel, .instance-title-panel { } jm|FieldCaption { color: #2f4f4f; font-weight: normal; } .required { color: #483d8b; font-weight: bold; } .validation-msg { color: red; font-style: italic; } .default-button { font-weight: bold; } .feedback-pane { color: white; background-color: black; font-size: 24pt; font-weight: bold; padding: 30px; border-radius: 24px; opacity: 0.7; } #aboutPnl { margin: 5px; } types|URIRenderer { cursor: pointer; }

17.3. USING CSS4SWING IN STANDALONE SWING APPLICATIONS

205

17.3

Using CSS4Swing in Standalone Swing Applications

The CSS engine used by JMatter was developed by Eitan Suez, for the purpose of enhancing JMatter. However, the implementation is agnostic to the JMatter framework, and can be used with any old Swing application. That is, if youre working on a Swing-related project and wished you could style your application with CSS, well, now you can. First youll need to add these libraries to your classpath, which youll nd in jmatter/lib/runtime/swingvm: 1. css4swing.jar 2. antlr-runtime-3.0.1.jar 3. swingx.jar This chapter has already documented how to write stylesheets, and how to apply semantic style names or ids to various components. The only other requirement is to insert this statement before you start building your Swing user interface:
CSSEngine.initialize();

By default, the engine will look for the resource styles.css in your classpath. Alternatively, you can specify a different origin for your stylesheet with this method:
CSSEngine.initialize(InputStream is);

Here is a sample class that provides a little more context, and a more complete illustration:
package com.u2d.css4swing; import com.l2fprod.common.swing.JOutlookBar; import com.u2d.css4swing.style.ComponentStyle; import javax.swing.*; /** * Created by IntelliJ IDEA. * User: eitan * Date: Jan 30, 2007 * Time: 11:48:24 AM

206

CHAPTER 17. STYLING THE UI WITH CSS

*/ public class SampleTest extends JPanel { public SampleTest() { JLabel label = new JLabel("Eitan is testing.."); ComponentStyle.addClass(label, "required"); add(label); JLabel lbl2 = new JLabel("Ident-Designated"); ComponentStyle.setIdent(lbl2, "theone"); add(lbl2); FieldCaption caption = new FieldCaption("A label subclass.."); add(caption); JButton button = new JButton("Button 1 (required).."); ComponentStyle.addClass(button, "required"); add(button); JButton button2 = new JButton("Button 2 (not required).."); add(button2); _bar = new JOutlookBar(); ComponentStyle.addClass(_bar, "left-sidebar"); _bar.addTab("Hello", new JLabel("Hi")); _bar.addTab("Bye", new JLabel("Bye")); add(_bar); } JOutlookBar _bar; public static void main(String[] args) { CSSEngine.initialize(); SwingUtilities.invokeLater(new Runnable() { public void run() { JFrame f = new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); SampleTest st = new SampleTest(); f.setContentPane(st); f.setBounds(100,100,500,500); f.setVisible(true);

17.4. FUTURE PLANS

207

} }); } }

17.4

Future Plans

Additional enhancements for CSS support in JMatter are planned. Here is a tentative list: 1. Produce multiple alternative stylesheets that can be used as themes to skin JMatter applications 2. Support all border line styles dened by the CSS specication 3. Complete support for color value syntax, including the rgb() function and the CSS3 rgba() function for supporting transparency 4. Possibly adding support for CSS @import statements, as a simple include mechanism 5. Possibly adding support for applicable CSS pseudo classes and pseudo elements 6. Perhaps expose the ability to apply effects in a Swing application through CSS If you produce a stylesheet that you nd does a good job at styling the JMatter user interface, please consider contributing it back to the project as a JMatter theme.

208

CHAPTER 17. STYLING THE UI WITH CSS

Chapter 18

Deploying your Application


In this chapter well discuss how to setup your application for distribution with Suns Java Web Start technology.

18.1

JMatter Applications Architecture

We already know that JMatter applications rely on a database management system for storing information, performing queries, and more. The architecture of JMatter applications is simple and straightforward: JMatter applications are installed at end-user workstations, and communicate to the database that resides on the server. This architecture is known as a two-tier client-server architecture and is quite suitable for small multi-user applications (roughly up to 100 users). The dilemma is having to install and maintain JMatter applications on each client machine. This is where Java Web Start comes to the rescue.

18.2

Java Web Start

The basic idea behind Java Web Start is to distribute your application using the world wide web. End users simply visit a web page and click on a link that triggers the automatic download and installation of the application to the endusers computer. Java Web Start is bundled with every distribution of Java. It gets even better: each time the end user launches the application, Java Web Start veries whether any updates are available and will automatically download and install the updates prior to launching the application. So, not only is the distribution of your application automated but also its maintenance. You can read all about Java Web Start at http://java.sun.com/products/javawebstart/

209

210

CHAPTER 18. DEPLOYING YOUR APPLICATION

In our case, well be deploying applications within an intranet or extranet. Nevertheless, well be using web technologies to distribute and keep our client installations up to date.

18.3

Deploying ContactMgr

JMatter provides an ant target for bundling your application for distribution via Java Web Start. We rst need to decide what web server to use to deploy our application. Well need the machines host name or ip address, and the port number (which typically will be 80). Enter these two bits of information into the le project.properties located in resources/jws/dynamic Second we need to ensure that the database connection url we specify in hibernate.properties is not a relative url (such as jdbc:postgresql://localhost/contactmgr); that url must be valid for all the end-user computers. We also need to ensure that no rewalls forbid communications trafc between the end-user machines and the database. Remember, JMatter was designed for workgroup applications: that is, for multiple users on a Local Area Network or a Virtual Private Network. Ok, heres the magic ant target:
ant jws-dist

When the target is nished running, it will have produced a .war le in the dist folder. Create a directory with the same name as your project inside your web servers document root directory:
sudo mkdir /var/www/ContactMgr

Extract the war le to that directory. This should do the trick:


sudo unzip dist/ContactMgr.war -d /var/www/ContactMgr

We should now be ready to give our application a try. Sit at a client machine and visit the web page in question (perhaps http://local-server/ContactMgr). Youll see a page that looks like gure 18.1.

18.3. DEPLOYING CONTACTMGR

211

Figure 18.1: Java Web Start Launch Page Click on the link and Java Web Start will launch and begin downloading your application. Before permitting you to proceed, you will be prompted to accept the certicate used to sign the code (see gure 18.2).

Figure 18.2: Java Web Start Security Prompt This requires some explanation. Java Web Start will not run any code that is not signed with a code certicate. This is not 100% true. It is possible to customize the Java security policy on every client machine to allow locally deployed code to

212

CHAPTER 18. DEPLOYING YOUR APPLICATION

run. However this is not really a viable option as it completely defeats the original purpose of Java Web Start being a simple and easy way to deploy applications without having to perform modications on each client machine. So the code must be signed. By default JMatter will sign the codebase anonymously so as to allow the code to run. Java Web Start will prompt the end-user to allow the the application to launch. This is essentially the hand-off point. It is the place where you, the developer of the application, procure a valid code certicate and use it to sign the code base that youre deploying. Enough discussion, go ahead and reply Yes to the prompt and watch the application launch. You can proceed by logging in to the application and interacting with it as you always have up to now. Thats basically it. That is, anyone in your organization can now visit the intranet web page for our Contact Manager and with a single click of the mouse they will have downloaded, installed, and run our Contact Manager application.

18.4

Caveats

The process of accessing a database by nature is meant to be difcult as data security is of utmost importance. You need to make sure your database is congured to accept connections from the network, that the conguration does not leave any security holes (pass in an MD5 hash of the database users password for logging in, for example). If Java Web Start fails during the launch process the rst time you attempt to deploy your application, it is likely due to a connection timeout attempting to access the database. This would be a good time to take a moment and review your database documentation and your database settings.

18.5

Security Options

The PostgresQL database can be congured to communicate with clients over SSL, providing secure communications between clients and the database server. This option is an interesting one because it allows us to consider the possibility of deploying a JMatter application to a limited number of concurrent users over a wider geographic area. Also, its worth mentioning that H2 is a lightweight database that also supports SSL. In addition it supports encrypting the entire database.

18.6. MORE ABOUT JWS

213

18.6

More About JWS

Figure 18.3 depicts a MacOSX client application launched via Java Web Start. The database server in this instance is a PostgresQL cluster running on a nearby Linux machine.

Figure 18.3: Java Web Start - Launched Application on a MacOSX Client The rst time the application is launched, Java Web Start will be downloading and installing an entire application. So the rst launch will be fairly slow; it might take 30 seconds. Subsequent launches will not require the download (only a quick check for updates against the server) and consequently will take considerably less time. The hyperlink on the ContactMgr intranet page is only one way in which end users can launch their application. Java Web Start can be congured to place a shortcut for the application directly on the end users desktop, for example.

18.7

Summary

JMatter attempts to make the Java Web Start process as easy and painless as possible. Lets review what we just did:

214

CHAPTER 18. DEPLOYING YOUR APPLICATION

1. We invoked the ant jws-dist target, and 2. extracted the generated .war le to the web server 3. Visited the web page and clicked on a link, which triggered Java Web Start Anyone whos had to congure Java Web Start the normal way will certainly appreciate this.

Chapter 19

Deployment, Take II: The Application Browser


Deploying JMatter applications with Java WebStart works well enough. Its certainly what people term the fat client model, where the client application is quite sizable, in the order of 20 Megabytes, primarily due to the large number of dependent libraries required to support the application. The web model on the other hand is seen as a more lightweight approach, and termed the thin client model. In a manner directly analogous to the web, JMatter now supports a thin client model for deploying your applications, thereby deriving the same set of benets typically associated with web: Smaller downloads Dynamic application loading No installation required (just visit a URL) Here is how it works. JMatter comes equipped with an application named the Application Browser. You will nd it in the base directory of the JMatter distribution. This application consists of a single model object: the Application Bookmark. Roughly speaking, this application is to JMatter applications what the Firefox web browser is to web applications: its an application that allows you to load applications by specifying or entering a URL. The Application Browser can be packaged and deployed using the traditional Java WebStart mechanism, or perhaps through the more traditional mechanism of using an automated installer. By virtue of being implemented entirely in Java,

215

216

CHAPTER 19. DEPLOYMENT, TAKE II: THE APPLICATION BROWSER

this application is by denition cross-platform. Its worthwhile noting that the JMatter application browser is itself nothing but a standard JMatter application with a very simple model comprising a single entity: the Bookmark.

19.1

How it works, by example

Allow me to illustrate how this deployment mechanism works by example: lets deploy the Sympster application. Here are the steps we need to follow: 1. Package the application 2. Copy the packaged application to a web server so it can be http-loaded 3. Launch the application browser 4. Specify the url for the application and launch the application For the rst task, you will nd a new JMatter ant target named jar-model that will produce the packaged artifact. The output of this target is the le dist/Sympster.jar which consists strictly of the compiled object model and supporting classes (if any), the application resources and conguration les (images, class-list.json, hibernate mapping les, database connection setings, and spring conguration les). We can now upload the artifact to a web server, say for example, to the jmatter.org web site perhaps at the url: http://jmatter.org/demo-apps/Sympster.jar We now launch the application browser.

19.1. HOW IT WORKS, BY EXAMPLE

217

Figure 19.1: The JMatter Application Browser In Figure 19.1, we see that Ive dened an application bookmark for the Sympster demo application that Ive deployed to jmatter.org. I can now click on the Launch button to launch the application. The jar le is downloaded, and class-loaded into the client applications virtual machine. The application conguration is read and the application is loaded. Its splash screen appears, and we are nally presented with a login dialog. Upon logging in, we see the Sympster applications class bar show up on the left hand side and were ready to start using our application: perhaps dening new talks, creating a new session schedule for an upcoming symposium, etc.. When were nished with our Sympster application session, we can either quit the application, or unload it (from the menu: File -> Unload Application). The Application Browser re-appears, and we can choose to launch an entirely different application from a different URL. The application model remains two-tier, with the application talking directly to its back-end database. But it is worthwhile at this time to examine the benets of this method of deployment: We have turned a fat client into a thin client The size of our download has shrunk from 20MB to 80KB (its worth stressing that many web pages today are larger than 80KB)

218

CHAPTER 19. DEPLOYMENT, TAKE II: THE APPLICATION BROWSER

No installation of Sympster was necessary Developers are free to work on enhanced versions of the application, drop a new copy on the web server, and thereby upgrading the application, in a manner that is transparent to clients (end users)

19.2

Dealing with dependencies

The MyTunes demo application is a good example of an application that has dependencies on third party libraries that are not bundled with the Application Browser. How can we deploy MyTunes along with these necessary dependencies? The answer turns out to be very simple. All that is necessary is to properly cite the dependencies in the jar les manifest. Here is MyTunes ant target jar-model:
<target name="jar-model" description="jar just the model" depends="clean,genhbm"> <jar file="${model-jar.file}"> <manifest> <attribute name="Created-By" value="jMatter" /> <attribute name="Main-Class" value="${main.class}" /> <attribute name="Class-Path" value="JID3.jar jl1.0.jar" /> </manifest> <fileset dir="${build.classes.dir}" includes="**/*" /> </jar> </target>

The interesting part here is how weve added the two libraries JID3.jar and jl1.0.jar (responsible for playing mp3s) using the jar manifests Class-Path attribute. All we do next is make sure to put these libraries alongside MyTunes.jar on our web server. The rest is transparent: the associated jar les are fetched alongside the application. In this case our application is 300KB in size, counting the dependencies. Not bad for a music player.

19.3

Looking Ahead

Were thinking about further enhancing the application browser to allow multiple applications to be loaded in separate tabs, in a manner similar to the way that web browsers today feature tabbed-browsing. Were also beginning to contemplate developing a way to run JMatter applications using a three-tier model: by splitting the application logic between client and application server.

Chapter 20

Tooling
This chapter attempts to answer the question: are tools available specically for assisting developers in writing JMatter applications?

20.1

Reverse Engineering an Existing Schema

Jim Slack graciously contributed this code to the JMatter project. Here is a brief description of this tool from Jim: I became very interested in JMatter after reading your book and playing around with the demos, but was disappointed in the lack of a way to use a legacy database. Therefore, I just nished writing a Java program that creates JMatter Java source les from a database. It seems to work ne, although using it is a bit tricky because it involves a few manual steps: run the program, update the schema, then run an SQL script. So here are the instructions for how to use it. 1. Make a backup copy of your database 2. Create a new project as usual using the ant target new-project-ui 3. Navigate (cd) to your newly-created project and edit the le resources/hibernate.properties to point to the database schema in question 4. Invoke the ant target reveng-db which stands for Reverse Engineer Database. You have the option of specifying the name of the Java package that the generated source code will belong to with -Dreveng-pkgname=my.pkg.name (otherwise the code will default to org.jmatter.app)

219

220

CHAPTER 20. TOOLING

5. You can now invoke the schema-update target which will do two things: (a) it will invoke the genhbm target that will generate the hibernate mapping les from the generated source code; and (b) it will update the existing database schema to include version and createdOn columns and additional jmatter-specic tables 6. At the present time, theres one other simple matter to address. JMatter does not deal well with null initial values for the version and createdOn columns. Step [4] above creates the sql script aptly named reveng_update_script.sql that you can manually invoke to rectify this issue. Heres an example of how I do this with postgreSQL:
psql databasename $ \i reveng_update_script $ \q

Thats it. Youre now ready to either run your JMatter application and to layer behavior on to your existing application. Jim: Thank you very much!

20.2

IDEA Productivity Templates

I have developed a set of IntelliJ IDEA templates that constitutes a lightweight productivity solution for building JMatter apps. I can no longer write JMatter applications without them. This tool is included with the JMatter distribution in jmatter/tools/IDEA. Follow the instructions in the README le to install the templates into the IDE. The tool thus far consists of one basic le template and a number of live templates that can signicantly assist the development of JMatter applications within IDEA.

20.2.1

How it works

After creating a Java project, you can create basic JMatter model objects in a manner similar to the creation of new classes: 1. Select a package in the side bar 2. Right-click "New->ACO" (ACO stands for AbstractComplexEObject) 3. Specify the class name

20.3. ULTRAVIOLET AND UMLC

221

For example, for a class named Car, this basic template will be created:
package com.u2d.issuemgr; import com.u2d.model.AbstractComplexEObject; import com.u2d.model.Title; import com.u2d.type.atom.StringEO; import javax.persistence.Entity; @Entity public class Car extends AbstractComplexEObject { private final StringEO name = new StringEO(); public Car() {} public StringEO getName() { return name; } public Title title() { return name.title(); } }

In the IDEA project settings, enter the "Live Templates" section. You can inspect the various live templates dened for jmatter under the "jmatter" tree node. Some examples include:

Key fo flat bprop tv plu

Description expands to the metadata specification for fieldOrder expands to the flattenIntoParent metadata specification will write the bound property getter and setter methods for you expands to specify the tabViews metadata will write the pluralName() method to override the plural name for a type

20.3

Ultraviolet and UMLC

Ultraviolet is a UML class editor. A copy is packaged with and integrated into JMatter. One way to launch it is by invoking the ultraviolet target from the framework build le:

222

CHAPTER 20. TOOLING

$ cd jmatter $ ant ultraviolet

See the accompanying screenshot of Ultraviolet in action.

Figure 20.1: Ultraviolet With this editor, you can dene the set of classes in your model and their interrelationships. One can specify associations, their cardinality, whether theyre bidirectional. Much of JMatters metadata can be specied directly via each classs property sheet: class name, plural name, icon, color code, elds, commands, as well as eld and command metadata. One can also model inheritance. Ultraviolet will generate a .umlc le for your model: a complete description of your model in the umlc language. Finally, the tool will automatically translate the model into a JMatter application. Technically, the only aspects of development that you do outside of Ultraviolet is the implementation of the commands. This tool is inspiring and shows the power of domain-driven design and implementation. One can go from a simple idea to a model to a running application in minutes. Both Ultraviolet and umlc were developed entirely by Ryan Ramage. This tool is open source and has its own home page: http://code.google.com/p/umlc/ and http://code.google.com/p/umlc/.

Chapter 21

The Power User


This chapter details features of JMatter applications user interfaces, including many subtle features that aim to improve usability and users productivity.

21.1

Visual Command Interface

JMatter sports a feature inspired by blacktree softwares QuickSilver, and more recently, Gnome Do. Briey, these applications provide a visual command interface for desktops. For a desktop management application, most commands involve launching applications or bringing them up in the terminal or the le manager. The end user composes an instruction by rst specifying the target application and second the specic command to invoke on that application. Its primary use is for launching applications. Applications are specied by typing, and identied via a text matching algorithm. It turns out that these applications adhere to the noun-verb metaphor which is a strong part of JMatters general philosophy. Every operation in JMatter boils down to the invocation of a command on a target object (and optionally specifying command arguments). JMatters implementation of a visual command interface now provides an additional, alternative visual mechanism to invoke commands. I will illustrate how this interface works with an example. Lets take the Sympster demonstration application. Lets say we wish to create a new speaker. We typically do this by right-clicking on the Speaker icon in the class bar (the visual representation of its type) and selecting the command New from its context menu. Now, you can also: 1. Press Ctrl-I (Cmd-I on the mac) to invoke the visual command interface, 2. Type Spe, press the tab key, and type New

223

224

CHAPTER 21. THE POWER USER

3. Press the Enter key In step 2, we rst search for the type Speakers by name, and then we search for the command named New. We dont have to type the full name, just enough characters to match the item (the object) were looking for. Optionally, you can press the down-arrow key to see other matches and select the appropriate one. The escape key dismisses the visual command interface. In the above case, invoking the command causes the visual command interface to auto-dismiss. Figure 21.1 shows JMatters visual command interface in action.

Figure 21.1: JMatters visual command interface in action Many desktop users have become habituated to this type of command interface and prefer it. First, this is a testament that noun-verb types of user interfaces are a good match for the way we tend to go about doing things. Second, it provides a uniform way of invoking any command. Finally, you dont have to take your ngers off of the keyboard. This feature is built-in to JMatter. No work is necessary to enable it. You might however be interested in extending its capabilities further by extending its index, which we discuss next.

21.1. VISUAL COMMAND INTERFACE

225

21.1.1

Extending the Index

The visual command interface by default matches types. Match a target type, and then invoke a specic command on it, for example: Person Contacts -> Browse. It would be nice however if we could interact with instances of a given type in addition. For example, with the contact manager, itd be nice to match a contact by name directly from the visual command interface. Likewise, in MyTunes, itd be nice to direclty match a song by title. In Sympster, Speakers and Talks are also good candidates. The visual command interface provides a mechanism for you to add items to its index. The ContactMgr application has recently been enhanced to show you how. Heres how this is done.. First, we subclass com.u2d.app.Application and override the postInitialize() method:
public class Application extends com.u2d.app.Application { public void postInitialize() { super.postInitialize(); contributeToIndex(PersonContact.class); } }

The above call to contributeToIndex() instructs the visual interface to include contact instances in its index. Next we need to revise our spring conguration le to specify our subclass as the applications Application bean. We edit the le src/applicationContext.xml as follows:
<bean id="application" class="com.u2d.contactmgr.Application"> <property name="name" value="Contact Manager" /> <property name="version" value="1.0" /> <property name="description" value="A simple contact manager" /> <property name="helpContentsUrl" value="http://jmatter.org/documentation/html/index.html" /> <property name="pagesize" value="15" /> <property name="persistenceMechanism" ref="persistor" /> </bean>

Notice how the beans class above references our subclass. Thats it. Now when we launch the contact manager, assuming we have a contact named John Doe, we

226

CHAPTER 21. THE POWER USER

can invoke the visual command interface, start typing John and the instance will be matched. We can then invoke any of a number of commands, for example Open or Edit.

21.2

Associations Made Easy

NakedObjects originally introduced a terric way to establish associations between objects in a user interface. It automatically enabled this via drag and drop. For some reason, dnd in many ways is not used as much as it used to be. Having to take the hand off the keyboard is admittedly a "productivity mark deduction." So, in JMatter, I set out to enable associations in more than one way. For starters, dnd works out of the box. But one can also click a "pick" button that will display a listing of entries of the type for a given association, that the user simply picks from. Lets look at a concrete example: lets say were working with the Symposium manager demo application in JMatter. And lets further say that were dening a new talk to be given. Talks have a many-to-one association to the speaker (or presenter) giving the talk. My favorite way of establishing that association is with the in-place associator widget thats built-in to JMatter. Heres how it works. When editing the talk, click (or tab into) the association eld in question, which in this case is Speaker. Simply start typing and a matching list of entries automatically appears. This component dynamically fetches matching entries from the database as you type. The matched items listing also pages by default, so for a scenario with too many matching entires, only the rst page will be fetched. In my experience with this component, this is one of the fastest ways of making an association between two objects. Heres a snapshot of me trying to dene a new talk, *In Action*, as it were1 :
1 Please

pardon the sarcasm

21.3. PAGING

227

Figure 21.2: Associating a Speaker to a talk The only detail to tend to is to specify which eld of Speaker are we searching by. Thats what that little magnifying glass icon to the left of the text eld is for. Its a drop-down combobox that dynamically lists the various elds you might want to search by. The default eld that JMatter should use for searching in the context of in-place associations is controlled by the defaultSearchPath metadata, as shown by this example:
public static String defaultSearchPath = "name.first";

See section 8.4.9.

21.3

Paging

Weve all had to implement this feature as developers. Today, many frameworks such as Tapestry for example, will provide components out of the box that will automatically take care of paging a listing on your behalf. JMatter also provides paging out of the box. When I sat down and started to think about this feature, I saw a certain pattern. Ones rst, naive implementation of paging might consist of a simple forward and back navigation buttons:

228

CHAPTER 21. THE POWER USER

< >

Shortly afterwards comes the request for the ability to navigate to the rst and last page in a listing, and so the above evolves to:
<< < > >>

Then embellished, like so:


<< < [Page 3] > >>

Over time, paging has evolved to let you navigate to a number of pages in the vicinity of the current page:
1 2 .. 7 [Page 8] 9 .. 13 14

This is what most web-based applications do today. What I realized is that paging, taken to its eventual limit, is essentially embodied in the behaviour of a scrollbar. Most scrollbars provide continous scrolling. Whereas in the case of paging, the scrolling is discrete. The more pages there are, the less this discrete behaviour is apparent. Whats nice about todays scrollbars is that their size is inversely proportional to the length of the list. The larger the list, the smaller they are. Scrollbars have the advantage of giving you more of a visual perspective of where you are in the list. And you can simply drag the scrollbutton to any location along its dimension. JMatters Swing-based view mechanism denes a view implementation: a component named PageScrollBar which extends Swings JScrollBar, shown at the bottom of the following two-page listing:

21.4. EXPOS

229

Figure 21.3: Paging a Conferences Sessions As usual, developers of JMatter applications need not concern themselves with this at all. Its bundled into the framework and it just works. If however you feel the need to customize the way this scrollbar looks or behaves, its easy enough with a little Swing experience to make whatever enhancements or decorations one might have in mind.

21.4

Expos

JMatter GUIs are inherently Object Oriented UIs. I like to make the analogy to our operating systems desktops. There are a number of ways to make such UIs more effective. Sometimes I look to these desktop systems for ideas and features. One such feature is Apples Expos which has since also been copied by the Compiz Fusion project on Linux: the idea of scaling down and fanning out ones windows temporarily for the purpose of easily switching focus to a window that is otherwise hidden by other windows with a higher z-index. JMatter incorporates such a feature. Pressing the F12 key invokes the JExplose 2 feature which does precisely this. This option is also available form the desktop panes context menu.
2 Theres

no typo here. The author of this tool is French; explose in French means explode.

230

CHAPTER 21. THE POWER USER

21.5
21.5.1

Navigation
Window Placement

JMatter takes a certain strategy relating to the placement of new windows (internal frames) in its Graphical User Interface. I recall trying various window placement strategies and then realizing something I was doing as a user of my applications: after creating a new view, Id quickly reach for the windows title bar and place the window where I really wanted it. I dont think theres an algorithm for guessing the users intent. So I started thinking about what might the next best thing be. The strategy was to minimize the amount of work one has to do in moving the resulting window. What I do is place new windows such that their title bars are near the current mouse cursor location, thus minimizing the distance one would have to move their mouse to reach for it. Theres a somewhat hidden feature in JMatter which I very much like and that Id like to share. This feature takes things one step further: it automatically puts the newly created window in placement mode. Allow me to explain.. This feature requires pressing a metakey to communicate your intent to use it: when youre about to invoke a command that creates a new view (e.g. the Open command) , hold down the Control key (on the mac, use the Command key). The resulting window automatically "binds" to your mouse location. That is, it will follow your mouse. So, the way it works is you invoke the command with the Control key pressed and the new view is created, but it starts following your mouse around. Once youve found that ideal spot, a single left-click is all you need to do to pin it back down onto the desktop.

21.5.2

New View Placement Options

Another feature of desktop systems, one that has been around for some time, and is specically related to the le manager, is the idea of giving users options in terms of how to place newly-created views. When navigating a folder hierarchy, one can double-click on a folder, which typically opens a new window with the contents of that folder. Long ago, on ms-windows I recall always turning on the option "re-use existing window"; that is, replacing the existing view with the new one. This can really help with an otherwise rapid proliferation of windows on ones desktop. Separately, the mozilla project introduced us to another navigation option: tabbed browsing, which is a sort of "middle of the road" approach: dont create a new window, but dont replace the existing view either. Since then, weve seen other applications, such as shell terminals, copy this handy feature.

21.5. NAVIGATION

231

JMatter now supports both modes of navitgation. A Users default browsing preferences can be specied through the User model object, which has an aggregate property named Preferences. Its rst and only option at the moment captures how a user generally prefers to navigate in JMatter: should new views be created by default: 1. in a new window? 2. in a new tab? 3. in-place, replacing the existing view? Setting your preference is all it takes to change JMatters default navigation behavior. In many situations there may be exceptions to the default rule. Say, for example, that we wish to open a new view in a new tab even though the default setting is in-place navigation. To accommodate this, a new gesture has been introduced in JMatter: holding down the Shift key while invoking a command that produces a new view will cause a context menu to appear at the mouse location, for selecting how to create the new view. The choices again are the above three: in a new window, tab, or in-place. Figure 21.4 captures the invocation of the Open command while holding down the Shift key.

Figure 21.4: Invoking the Open command, holding down the Shift key Figure 21.5 shows the navigation option pop up. I selected the in new tab option.

232

CHAPTER 21. THE POWER USER

Figure 21.5: Open in new tab Option The next gure shows the result of the view created in a new tab.

Figure 21.6: Resulting View Finally, this last screenshot shows that, with tabs, you have the option of detaching the view onto its own window or closing the tab (Ctrl+w is the corresponding key binding).

21.6. COPY AND PASTE

233

Figure 21.7: Tab Detach Option I believe this to be an important feature, nally producing a desktop with a number of effective navigation instruments: 1. Fundamentally an OOUI 2. DnD support 3. An expos-like feature 4. Tabbed, In-Place, or New-window view placement Another complementary feature that is contemplated for JMatter is support for docking views. I have looked at exdock, which is a terric effort. But Im looking for something that is more transparent: effectively a layout manager designed for JDesktopPane that transparently provides docking support. Let me know what you recommend.

21.6

Copy and Paste

Every Swing application gets for free the ability to use the underlying platforms copy and paste capabilities when working with JTextFields and JTextAreas. In JMatter you might have noticed that instances also sport their own Copy/Paste commands. Youll nd this feature to be a little more powerful and interesting compared to the basic clipboard copy/paste feature.

234

CHAPTER 21. THE POWER USER

The main difference is that unlike the clipboard, where you get one temporary area to copy to, JMatter provides a temporary "buffer" area for every distinct type. So, for example in the Contact Manager demo application, I can go about and copy an Address here, a Contact object there, or an entire Person instance and all three copies exist in memory simultaneously, each in its own buffer. I can then, say, create a new Person instance and right-click "Paste" on the title view for the new instance. All of the information is copied over. This use case may not be very interesting or real. But there are other situations. Take for example how a Person has a Contact property modeled using composition (or aggregation). Each instance has its own copy. Yet its very possible for two persons to have the same contact information, or perhaps the same address, with the very real possibility that the two copies will change/diverge over time. The copy/paste commands on instances are automatically placed by JMatter in a number of context menus for a number of views. Youll nd these commands in the title views context menu, as shown below.

Figure 21.8: Copy on Instance Title View Youll also nd it on aggregate objects nodes as shown in gure 21.9.

21.6. COPY AND PASTE

235

Figure 21.9: Copy on Aggregate Node View Finally, youll nd it on the context menus for individual tab title views, as shown here:

Figure 21.10: Copy on Tab Title View This feature can come in handy and save repetitive data entry tasks, where one

236

CHAPTER 21. THE POWER USER

might otherwise be forced to invoke copy/paste individually on atomic elds.

21.7

The Restore Desktop Feature

One last feature, though not completely polished, is worth mentioning. JMatter saves and restores end users desktops between sessions. That is, the size and positions and other information about open windows is recorded and stored to the database when one logs out or quits the application. Conversely an attempt is made to restore these views on login. Whats nice about saving this information to database is that ones desktop conguration is independent of the workstation you log in to. Instead its tied to your user information in the database. This feature is at the moment fairly simple. Other than restoring the main window bounds and simple child windows (lists and instances), it does not yet properly restore other types of views at the moment.

Chapter 22

Summary
JMatter is a framework for building software applications that embrace the notion of domain-driven design: that the essence of a software application is the translation of domain knowledge into code; the modeling of the domain into a set of entities with interrelationships. Briey: many of of those things that Eric Evans discusses in his book Domain-Driven Design [5]. But this framework does more than embrace these ideas: it is a vehicle for implementing domain-driven applications today. The JMatter codebase constitutes a robust and generic implementation of all of the layers of a software application to support a given domain. This is an extremely agile proposition. In this short book alone, we managed to develop four fully-featured and distinct software applications. How such agility is achieved can be described succinctly as follows: By implementing all application services (search, forms, authorization, persistence, ui, etc..) generically, in a fashion decoupled from any one specic domain model, these implementations are free to be reused across domains. The consequences of this reuse are dramatic: large time savings an applications codebase shrinks dramatically and becomes manageable theres a clean separation between application development and infrastructure development consistent, high-quality applications

237

238

CHAPTER 22. SUMMARY

This model of development puts into question certain rules about software development that up until now wed assumed to be a given, namely: that the cost of making a change to a software system late in the life of a software project is much higher; or conversely that its cheaper to implement changes early on, when less software has been built upon requirements that may change. The above rule inherently assumes that much of an applications codebase is coupled to requirements, so that when the requirements change, a lot of code will have to be thrown away and rewritten: GUI forms will have to be revised to reect a new eld There will undoubtedly be ripple effects to the database schema Queries will have to be revised to take a new eld into account The authorization system will have to be updated because a new action was introduced And the list goes on. The entire application has to be retrotted to take the change into account. In JMatter the repercussions are kept to a bare minimum: the database schema derives from the domain model, as does the user interface, and the authorization system, and the search system, and so on.. All reect the domain model.

22.1

Looking Forward

What technologies to base a project on is always a difcult choice, and a moving target. For example, Java is used in many environments today, but we see a desire to move to languages such as Scala, Groovy, and Ruby. On the other hand, new languages may have less mature code libraries, and involve a certain risk. JMatter strikes a great balance in its choice of technologies. Its a reality today; its built upon a mature platform, a stable set of libraries, Hibernate being one example. Looking forward, we will likely be exploring new languages for the JVM such as Scala, Groovy, and JRuby. These languages will bring about tangible benets:

22.1. LOOKING FORWARD

239

Traits (also known as mixins) are a powerful and missing feature (from Java) that will provide more exibility in modeling. Internally, in terms of JMatters own implementation, it will help streamline the implementation even further. The functional programming traits of some of these languages promise to bring about improvements in performance via lazy loading, and in thread safety via immutability. Powerful metaobject programming facilities, and the very designs of these languages promise to provide the necessary tools to evolve how domains are specied into a full-edged domain-specic language. As one small, concrete example, the Scala language denes the notion of a value object via the built-in primitive val. Much redundancy in specifying a domain model can be done away with. You are likely to start seeing JMatter move in the direction of such languages in the coming years.

240

CHAPTER 22. SUMMARY

Appendix A

Keyboard Shortcuts
ShortCut Alt- Alt-1, Alt-2, etc.. Ctrl-w Ctrl-n Description Analogous to the alt-tab mechanism for switching between windows on your desktop In a window with multiple tabs, switch to the rst, second, [etc..] tab Closes the currently focused window When a view of a listing is in focus, a shortcut for the command New on the listings elements type. For example, if viewing a listing of Persons, instead of right-clicking New in the titlebar, just press Ctrl-n A shortcut that is active in listings, that places the focus on the search eld Invokes JExplose, a feature similar to Apples Expos, that will automatically scale and sort all of the windows on your desktop in order to facilitate the selection and management of multiple windows. This feature can also be invoked from the Desktops context menu (right-click on an empty spot on your desktop to bring up this menu).

Ctrl-f F12

241

242

APPENDIX A. KEYBOARD SHORTCUTS

Ctrl-command

Shift-Command

Shift-Click

Ctrl-Scrollwheel

Alt-/ Ctrl-/ Ctrl-I Ctrl-q

When invoking a command that generates a view window: if you nd yourself frequently repositioning the generated window, then this shortcut is for you. By holding down the Ctrl key while invoking the command (either clicking on the button or right-clicking on a context menu item), then the generated window will be bound to your mouse: it will follow your mouses movements. When you nd the ideal place to position the newlycreated window, just click with your mouse to pin it down into place. When invoking a command that generates a view, holding down the Shift key at the same time will prompt how youd like the new view generated: in a new window, a new tab, or in place (i.e. replacing current view). Click on a JMatter internal window while holding down the shift key to move or drag the window about. This is the same as dragging the titlebar to move the window, but gives you a much larger surface area to work with. This feature is the same as the well-known alt-click on linux desktops. In the context of a calendar window, can change the resolution of the calendar cells from one minute to one hour using this gesture (for either day view and week view). Focus on selected item in Class Bar Open currently selected views context menu. A keyboard equivalent for right-clicking. Invoke JMatters visual command interface (similar to quicksilver or gnome-do) Quit the application

Appendix B

Database Setup
The JMatter framework taps the power of database systems. JMatter employs the excellent Hibernate O/R Mapping framework which affords it database independence. That is, youre not constrained to using a specic database system. Options include PostgresQL, MySQL, Oracle, DB2, Sybase, Informix, SAP DB, and many more.
org/),

JMatter is tested primarily with PostgresQL and H2 (see http://www.h2database. and has been veried to work with Oracle and MySQL.

We recommend either H2: a full-featured, minimal administration, fast, Javaimplemented database, or PostgresQL: a mature, stable and open source database. The JMatter distribution pre-bundles JDBC drivers for PostgreSQL, MySQL, and H2 and hsqldb. If you choose to use a different database vendor, you will need to obtain the corresponding JDBC driver jar le and place it in the jmatter/lib/runtime/jdbc directory.

B.1

Conguring your own database for the ContactMgr Tutorial Application


Create a Database

B.1.1

Well use PostgresQL as an example. To create a database in PostgresQL, invoke a command similar to this one:
$ createdb -U postgres contactmgr

243

244

APPENDIX B. DATABASE SETUP

The -U ag is used to specify the name of the user who is creating the database. The username you should use depends on your specic installation (consult the PostgresQL documentation). You might also want to create a user specically for this application1 :
$ createuser -U postgres contactmgr

B.1.2

Specify the Database Connection Information

Make sure that youre in the ContactMgr folder before proceeding. Edit the le resources/hibernate.properties. Modify these three lines accordingly2 :
# hibernate.connection.url=jdbc:postgresql://localhost/contactmgr hibernate.connection.username=contactmgr hibernate.connection.password=

If youre using a database other than PostgresQL, youll also need to revise these two lines:
# hibernate.connection.driver_class=org.postgresql.Driver hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

Save the le.

B.1.3

Generate the Database Schema

From the ContactMgr base directory, invoke this command:


$ ant schema-export

B.1.4

Browsing the database schema with psql

$ psql contactmgr contactmgr=> \dt List of relations Schema |


1 Both 2 Lets

Name

| Type

Owner

createdb and createuser are programs that come with PostgresQL assume for now that the database will reside on the same machine as your application.

B.1. CONFIGURING YOUR OWN DATABASE

245

--------+---------------------+-------+-----------public | business public | commandrestriction public | complextype public | compositequery public | contactmethod public | fieldrestriction public | folder public | folder_items public | loggedevent public | person public | restriction public | role public | users public | usstate (15 rows) | table | contactmgr | table | contactmgr | table | contactmgr | table | contactmgr | table | contactmgr | table | contactmgr | table | contactmgr | table | contactmgr | table | contactmgr | table | contactmgr | table | contactmgr | table | contactmgr | table | contactmgr | table | contactmgr

public | queryspecifications | table | contactmgr

246

APPENDIX B. DATABASE SETUP

Appendix C

Working from the Subversion Repository


Credits: this appendix is an adaptation of a document written and volunteered by JMatter user pyramid

C.1

Checking out the code

The JMatter subversion repository is located at http://svn.jmatter.org/. Checking out the code from the HEAD of the repository:

svn checkout http://svn.jmatter.org/jmatter-complet/trunk jmatter-complet

To check out a specic release, look for the specic release tag name at:
http://svn.jmatter.org/jmatter-complet/tags/

Then issue the checkout command, as illustrated by this example:

svn checkout http://svn.jmatter.org/jmatter-complet/tags/Release-20060825 jm_20060825release

247

248

APPENDIX C. WORKING FROM THE SUBVERSION REPOSITORY

C.2

Directory Structure, Compiling, Running demo applications

The base directory is divided into two principal sections: the framework itself (located in directory jmatter) and the demo applications (located in demo-apps): ContactMgr, MyTunes, Sympster, MovieLib, and IssueMgr. To build the framework jar le dist/jmatter.jar, invoke:
cd jmatter ant

To run a demo application, say the ContactMgr demo application:


cd demo-apps/ContactMgr and schema-export ant run

Every demo application is built and run this way. These instructions are in accordance with the way any JMatter project is compiled and run. All the demo applications should be precongured to use a local, le-based H2 database. If per chance it is not, then simply edit the le resources/hibernate.properties. This le lists sample connection information for a variety of databases, including hsql, H2, postgresql, MySQL, and OracleXE. Uncomment the one you want and make sure the jdbc url and credentials are valid and youre ready to go. To automate the manual step of exporting your schema, add this hibernate property:
hibernate.hbm2ddl.auto=create

Appendix D

Online Articles on JMatter


Eitan Suez. Extreme Agility with jMatter http://www.clientjava.com/blog/2006/ 07/03/1151937901773.html. June 2006. Eitan Suez. Whats the matter with JMatter?
http://www.onjava.com/pub/a/ onjava/2007/08/16/whats-the-matter-with-jmatter.html.

August 2007.

Andres Almiray. Interview with Eitan Suez, creator of JMatter framework http://java.dzone.com/news/interview-eitan-suez-creator-jFebruary 2008.

249

250

APPENDIX D. ONLINE ARTICLES ON JMATTER

Appendix E

FAQ
This FAQ will be expanded in future versions of this documentation. 1. How do I customize my applications name in the main windows title bar? (a) Edit the le src/applicationContext.xml and look for a comment labeled TODO: Customize App Name Here. This is also the place where you customize the page size of listings in the user interface (the default is 15). 2. How do I add or remove a command to all my model objects regardless of type? (a) The base class for all JMatter model objects is AbstractComplexEObject. When JMatter introspects commands, it recurses up the types inheritance hierarchy. To add a command to all model objects, edit AbstractComplexEObject and add a new command like you would any model object (marked with the @Cmd annotation). Likewise, to remove an existing command, say for example the Export to XML command, simply comment out or remove the @Cmd annotation on the corresponding method.

251

252

APPENDIX E. FAQ

Appendix F

Contributing to this project


Here are few ways in which you can help this project succeed: 1. Use JMatter 2. Spread the word 3. Consider buying a print copy of this book from lulu.com (follow the link from the jmatter.org web site). A fraction of the price of the book goes back to the developers. 4. If youre in the business of developing commercial software solutions, buy a license of JMatter. Or get your company to purchase licenses. These licenses are priced ridiculously low (Ive estimated that the break-even point for JMatter is approximately one week into your rst project) and are royaltyfree. 5. Join the mailing list! Discuss features, suggest design improvements, become a part of our community 6. If youre a software developer, contribute bug xes, features, enhancements 7. Donate directly (see http://jmatter.org/pages/donate)

253

254

APPENDIX F. CONTRIBUTING TO THIS PROJECT

Appendix G

A Desktop within a Desktop?


One cannot help making the observation that the applications were developing are desktop-like in nature. We end up having a desktop running within a operating systems desktop. The features of our applications desktops are in many ways a replication of the features already built into our operating systems. The main difference being that instead of managing les and folders, were in a sense extending the desktop to allow for the management of business objects, in any combination we choose. When we wrote our contact manager, that combination happens to consist of persons and businesses, for example.

G.1

Dreaming of a Better Virtual World

The state of operating systems today looks all charming and wonderful. Take for example the new MacOS reborn in v10.0. Beautiful graphics, colors, lots of applications we can run. On the surface, it all looks and feels like a virtual garden of eden. I see a much colder, harsher landscape. I see a landscape of islands of processes that communicate with one another hardly ever. If they do, its via messages in a bottle. One of the few ways for such applications to talk to one another is via the clipboard. You copy (or drag) some text or maybe an image from one application and paste it (or drop it) onto another. Thats essentially the extent to which applications can communicate in an ad-hoc basis. Lets go a little further though. Lets think about the code required to implement an email application, a web browser, a word processor, our nance application, etc.. Each application must fend for itself: each one has to build its own search features, its own mechanism for persisting information, its own user interface, its own mechanism for calendaring, for validating information, etc..

255

256

APPENDIX G. A DESKTOP WITHIN A DESKTOP?

This is not entirely true; the operating system does provide certain services that any application can avail itself to: reading a le, writing a record to a database perhaps, opening a socket, creating a button, a text eld. Terric. Its a start. Again what we see is that the notion of orthogonal services that can be provided to all the applications that run in an operating system is missing. If the ideas embodied in JMatter were to be applied to an operating system, then we could create a virtual world where our software applications would suddenly and dramatically shrink in size. The reason would be simple: all youd have to do to build your application is dene your model objects. Half of them would already be dened in other applications and you wouldnt be writing them from scratch: youd be composing applications. Contributors to such an operating system might add new and interesting behaviors on existing objects. Maybe the ability for an email message object to receive an image object, maybe the ability to submit your nancial information electronically to your accountant. Youd be able to le email messages in folders that you place on your desktop. The notion of multiple separate applications would vanish. Theyd all run under a single application, managed by the operating system. When youre performing a search, youll be searching your entire virtual world in the same way, regardless of whether youre looking for a piece of text in a le or an email message, or maybe looking for a nancial transaction in a specic electronic account. We wouldnt need such large hard drives, and for many tasks, would not require such a fast microprocessor. Each application wouldnt request of the operating system a chunk of 50 megabytes to run in; your memory footprint would drop. When you perform a software update, youll be inheriting new orthogonal services: new capabilities that all of your objects would inherit, not just a single application. This is my vision for operating systems. It turns out these ideas are indeed very old ones. What Im describing, to a certain extent, is Smalltalk. Indeed the ideas behind JMatter were inspired by the NakedObjects framework, which in turn was inspired by Smalltalk.

G.2

Collapsing the desktops

So, my hope is that some day a single desktop will exist and the ideas in JMatter will be integrated into our operating systems. Until then, enjoy smashing your competition to bits with JMatter.

Bibliography
[1] Richard Pawson and Robert Matthews. Naked Objects. Wiley; 1st edition (November 2002). [2] Jef Raskin. The Humane Interface: New Directions for Designing Interactive Systems. Addison-Wesley Professional; 1st edition (March 29, 2000). [3] Simon Lewis. The Art and Science of Smalltalk. Prentice Hall; 1st edition (May 11, 1995). [4] Gamma, Helm, Johnson, Vlissides. Design Patterns. Addison-Wesley (1995). [5] Eric Evans. Domain Driven Design. Addison-Wesley (2004). [6] David R. Heffelnger. JasperReports for Java Developers. PackT Publishing (2006).

257

You might also like