+ All Categories

jmatter

Date post: 02-Dec-2014
Category:
Upload: marius-iulian-grigoras
View: 52 times
Download: 2 times
Share this document with a friend
Popular Tags:
267
Building Software Applications with JMATTER
Transcript
Page 1: jmatter

Building Software Applications

with

JMATTER

Page 2: jmatter
Page 3: jmatter

Building Software Applications

with

JMATTER

Eitan Suez

March 2009

Page 4: jmatter

© 2009 JMatterSoft LLC. All rights reserved.

On the Cover

The sport of windsurfing conveys qualities of speed and agility, qualities that I believe are also bornby the software framework JMatter in the field of software development. A sincere thanks goes to theStarBoard company, to the rider, and to the photographer, for the permission to use the photographon 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 andlayout.

Suez, EitanBuilding Software Applications with JMatter

Bibliography.ISBN: This publication is not yet registered with an ISBN Agency

Page 5: jmatter

Contents

I Introduction 1

1 Overview 3

1.1 How? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

1.2 Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

1.3 Seeing is believing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2 Software Installation 9

2.1 Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

2.2 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

3 A Short Tour 11

3.1 Launching ContactMgr . . . . . . . . . . . . . . . . . . . . . . . . . . 11

3.2 The Tour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

II Tutorial Applications 29

4 A Zero-Code Contact Manager 31

4.1 Creating a New Project . . . . . . . . . . . . . . . . . . . . . . . . . . 31

4.2 The Schema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

4.3 The Class Bar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

4.4 Running Your Contact Manager . . . . . . . . . . . . . . . . . . . . . 34

4.5 Custom Views Revisited . . . . . . . . . . . . . . . . . . . . . . . . . 35

4.6 Project Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

4.7 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

v

Page 6: jmatter

5 MyTunes in under 200 Lines 39

5.1 Creating the Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

5.2 Setup your Project in an IDE . . . . . . . . . . . . . . . . . . . . . . . 39

5.3 Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

5.4 The Album Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

5.5 The Genre Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

5.6 The Song Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

5.7 Running our Application . . . . . . . . . . . . . . . . . . . . . . . . . 46

5.8 Back To the Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

5.9 Validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

5.10 Behaviour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

5.11 Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

5.12 Importing Songs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

5.13 Not Completely Finished . . . . . . . . . . . . . . . . . . . . . . . . . 59

5.14 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

6 A Conference Manager 63

6.1 Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

6.2 Setting up the Project . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

6.3 The Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

6.4 Enhancements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

6.5 Calendaring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74

6.6 Inheritance-Based Polymorphism . . . . . . . . . . . . . . . . . . . . 80

6.7 Interface-Based Polymorphism . . . . . . . . . . . . . . . . . . . . . 82

6.8 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86

7 Issue Manager 89

7.1 Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89

7.2 Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90

7.3 Modeling Issues’ Lifecycle . . . . . . . . . . . . . . . . . . . . . . . . 93

7.4 Per-State Icons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97

vi

Page 7: jmatter

7.5 Additional Metadata . . . . . . . . . . . . . . . . . . . . . . . . . . . 98

7.6 A Few Loose Ends . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99

7.7 Issue Categories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101

7.8 The Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103

7.9 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104

III Framework Reference 105

8 Dichotomy of a Model Object 107

8.1 Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108

8.2 Fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109

8.3 Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116

8.4 Metadata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119

8.5 Per-Field Metadata . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125

8.6 Per-Command Metadata . . . . . . . . . . . . . . . . . . . . . . . . . 127

8.7 Persistence Lifecycle and AppEvents . . . . . . . . . . . . . . . . . . 129

9 Validation 131

10 Authentication & Authorization 137

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

Page 8: jmatter

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 JMatter’s CSS Engine . . . . . . . . . . . . . . . . . . . . . . . . . . . 197

17.2 The JMatter Stylesheet . . . . . . . . . . . . . . . . . . . . . . . . . . 201

17.3 Using CSS4Swing in Standalone Swing Applications . . . . . . . . 205

17.4 Future Plans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207

viii

Page 9: jmatter

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

Page 10: jmatter

B Database Setup 243

B.1 Configuring 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 249

E FAQ 251

F Contributing to this project 253

G A Desktop within a Desktop? 255

G.1 Dreaming of a Better Virtual World . . . . . . . . . . . . . . . . . . . 255

G.2 Collapsing the desktops . . . . . . . . . . . . . . . . . . . . . . . . . 256

x

Page 11: jmatter

Part I

Introduction

1

Page 12: jmatter
Page 13: jmatter

Chapter 1

Overview

Welcome! JMatter is a software application framework. It is designed specificallyfor building business software applications for work groups. Examples might in-clude accounting software, software for legal firms, medical software for smallpractices, software for auto mechanic shops, software for small software develop-ment shops, and more1.

The principal advantage of developing a business software application with JMat-ter is a dramatic reduction in development time. It is not an exaggeration tosay that the difference in development time compared to traditional methods isroughly a factor of 10! That is, one order of magnitude.

Take for example, the Issue Manager demo application described in chapter 7 onpage 89. Surprisingly, even though this application is presented as a “demo”, itnevertheless is a complete and working Issue Management software applicationthat can be used for day-to-day tracking and management of software issues. Theauthors of the JMatter framework used this application for some time for trackingbugs and enhancements to JMatter.

This Issue Manager software application was implemented by a single developerin roughly four hours. Contrast this to comparable systems such as Bugzillahttp://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 some-where in the neighborhood of one or more man-years to develop.

Equally important is the number of lines of code necessary to implement such asoftware application. Using JMatter, the entire Issue Manager application consistsof 300 lines of code at the moment, including white-space (blank lines), strewnacross three Java classes. Compare that to approximately 13,000 lines of pythoncode2 in trac spread among roughly 170 files (I don’t mean to pick on trac, which

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

3

Page 14: jmatter

4 CHAPTER 1. OVERVIEW

is a very nice issue management application; I just happen to have a copy installedon my computer).

This brings up another point: the JMatter framework is written in the Java pro-gramming language. This means that your software applications can run in aheterogeneous IT environment, on a variety of operation systems including theplethora of GNU/Linux OS’s, Solaris, MacOSX, and the various flavors of Win-dows3.

Software development professionals or teams that use the JMatter frameworktherefore enjoy a significant competitive advantage over other software devel-opment firms that employ more traditional methods of developing software.

At this point you should be asking yourself some very important questions: Canthis really be? How? Is it really possible to shave 90% or more of an application’s code?To deliver software in so much less time?

1.1 How?

Let’s take a moment to reflect on how software applications are constructed. Thereason for developers’ high productivity with JMatter is simple, but needs someelaboration.

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 overagain each time they work on a new application. With JMatter, things are dif-ferent. JMatter provides those common things so that developers don’t have tostart from scratch each time. You won’t find a single line of authentication codein a software application constructed using JMatter; that’s all tucked away in theframework.

If it were all about login dialogs, JMatter wouldn’t buy you very much. What setsJMatter apart is the fact that there are plenty more things that developers writefrom scratch for each new application; things that are common to them all. Hereare some of them:

A User Interface

A window, the ability to create new users, change their passwords, the abil-ity to create a new contact, edit the address for an existing contact, deletean old contact. The basic need to Create, view (Read), Update, and Deleteinformation is termed CRUD. It’s true that for each type of thing you’re cre-ating (a User, a Business, a Person, etc..), the forms will vary because each

3This includes both the client and server portions of the solution.

Page 15: jmatter

1.1. HOW? 5

thing contains a different set of fields. However, the mechanism is the same.Developing a user interface from scratch is a very tedious job. Estimatesstate that approximately 60% of the time spent developing an application isspent constructing its user interface;

Query Services

The basic need to filter information. For example, the ability to ask the ques-tion: Display all Persons who live in a certain city;

Validation

The ability to specify which fields are required, which are optional, whatconstitutes a valid phone number, date, etc.. when performing form entrytasks;

Persistence

The ability to save information, associations between objects, and more;

Calendaring

Many varying applications have the basic need to deal with time: schedul-ing 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, so-cial security numbers, images, passwords, percentages, currencies, names,addresses, notes, and more. Yet here again, you will discover software de-velopers spending time [re-]writing code to parse, validate, and format suchbasic information as a phone number;

Logging

Tracking activity in the system, the fact that someone logged in at a specifictime, 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 anapplication manages;

Wizards

A component of user interface construction, often used to break down com-plex tasks into a series of steps.

Page 16: jmatter

6 CHAPTER 1. OVERVIEW

Most of this work has nothing to do with the specific problem domain: they’regeneric services that all applications should have, but that [unfortunately] areconstructed from scratch each time4. I like to say that these services are orthogonalto 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 mostbasic of business applications. Before they have a chance to begin working on theproblem domain, they’re 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 tightlyand needlessly coupled to the problem domain

• a solution that compromises the end-user’s feature requirements to staywithin time and cost constraints

JMatter promises to empower developers to work on the task at hand withouthaving to build a foundation. At the time of this writing, JMatter provides mostof the listed orthogonal services. The implementation of a built-in, generic Au-thorization system has recently been completed.

The predominant architecture for software applications today is known as Model-View-Controller. You can think of JMatter as providing a complete and genericView-Controller implementation, leaving developers to work on the Model.

So to sum things up for now, the JMatter framework’s goal is to provide all ofthese orthogonal services, out of the box, so to speak without requiring any extraeffort on the part of the application developer.

1.2 Architecture

Before diving into JMatter, let’s briefly discuss what types of applications JMat-ter produces. What is their architecture? What language are these applicationswritten in? What operating systems can they be deployed onto, etc..

The JMatter framework and JMatter-based applications are written in the Javaprogramming language. The implication is primarily that these applications canrun 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 flavorsof Unix such as Solaris and BSD.

JMatter applications by design produce software applications where all data ispersisted to a back-end relational database. Databases provide powerful query

4or not! It’s rare to find a complete application that provides all of these services.

Page 17: jmatter

1.3. SEEING IS BELIEVING 7

capabilities that are the foundation for many business needs. The JMatter frame-work uses the Hibernate 5 framework to communicate to back-end databases.This affords the framework database independence. JMatter applications are com-patible with a number of back-end database systems. It has been tested with Post-gresQL, MySQL, and Oracle databases, as well as newer and more lightweightdatabase systems such as H2 and hsqldb. These back-end databases are availablefor a large number of operating systems.

On the client side, JMatter leverages the Java Swing Toolkit to produce rich clientapplications. These user interfaces are platform-independent.

The overall architecture has two tiers: the client application communicates overthe network to the back-end database. Multiple clients are installed on multipleworkstations, and multiple users can access the system concurrently.

This type of architecture is suitable for local area network deployment, or thewide area network, over a VPN 6 connection. A number of database systems to-day can be configured for communications over SSL, making it possible to deploysuch solutions over a wide area network without requiring a VPN solution.

To automate the task of installing clients on multiple workstations, and of keep-ing these installations up to date, JMatter leverages Java WebStart. Chapter 18 isdevoted to the specifics of deploying JMatter applications using this technology.

At the time of writing, JMatter already has early (alpha quality) implementa-tions of the infrastructure necessary to deploy the very same applications overthe world wide web, using a three-tier architecture. This will give users the abil-ity to deploy their applications either to the web or using Swing, or both (a mixedpopulation of users).

1.3 Seeing is believing

Here’s what lays ahead in the upcoming chapters: we’ll walk through installingJMatter on your system. Then we’ll begin by studying one of the JMatter demoapplications: the Contact Manager (Chapter 3). By the end of that chapter, you’llhave a good feel for JMatter applications, what they look like, how to interactwith them.

Part 2 of this manual focuses on teaching you how to write JMatter applicationsby example. We’ll start by building our own contact management software. Ineach succeeding chapter we’ll build a new application, each one building uponthe notions learned in the preceding chapters. All of the tutorial applicationsdocumented here are included in the JMatter framework distribution.

5see http://hibernate.org/6Virtual Private Network

Page 18: jmatter

8 CHAPTER 1. OVERVIEW

The third part of this manual aims to provide a complete reference of the JMatterframework. That’s where you’ll find detailed information on the various featuresof the framework, options, and conventions to adhere to.

Bold claims have been made in this introduction. Coming from the authors ofthe JMatter framework, these should be regarded with a healthy dose of skepti-cism. It is for you, the reader, to judge the cost-benefit proposition of the JMatterframework for delivering software applications. This document arms you withthe information necessary to make that judgment.

Page 19: jmatter

Chapter 2

Software Installation

In this chapter we’ll focus on the steps to install JMatter on your system. Let’sbegin with the prerequisites.

2.1 Prerequisites

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

JMatter is a Java-based framework and thus requires Java Standard Edition fromSun 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 antfrom 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 lookslike on my screen:

Apache Ant version 1.6.5 compiled on July 5 2006

9

Page 20: jmatter

10 CHAPTER 2. SOFTWARE INSTALLATION

2.2 Installation

Visit the JMatter web site at http://jmatter.org/ and click on the Download linkin the sidebar. You have the option of downloading the software either as a zipfile or as a tgz archive (a compressed tar file). Both files 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 Descriptiondemo-apps Where JMatter tutorial applications residejmatter The core of the JMatter frameworkmodules Various modules which the framework relies uponAppBrowser The JMatter Application Browser 1

If applicable, place a copy of the JDBC driver .jar file for your database in JMatter’slib/runtime/jdbc subdirectory (see Appendix B).

That’s it.

Page 21: jmatter

Chapter 3

A Short Tour

Let’s take a first look at a software application developed using JMatter. We’regoing to setup and launch, and then study the Contact Manager demo applicationthat is bundled with JMatter. You will find it in demo-apps/ContactMgr.

3.1 Launching ContactMgr

Follow these steps1:

$ cd demo-apps/ContactMgr

$ ant schema-export

From the tutorial application’s base directory, issuing the schema-export command(an ant target) for the first time will:

1. compile the framework,

2. compile the tutorial application’s code,

3. create an H2 database (in subdirectory db/ ),

4. generate the necessary o/r mapping files for the application, and

5. subsequently generates the actual database schema.

Next, let’s launch our application:

1The ’$’ symbol prefixing each command serves to indicate the command line and is not part of thecommand

11

Page 22: jmatter

12 CHAPTER 3. A SHORT TOUR

$ ant run

This command is simply a convenient way of launching the application duringdevelopment.

JMatter applications are designed to be multi-user applications, running in client-server mode. The framework supports the task of deploying applications usingSun’s Java WebStart technology. Please refer to chapter 18 for complete documen-tation pertaining to deploying applications.

If you prefer to configure your own MySQL or PostgresQL database, please referto appendix B.

3.2 The Tour

OK, we’ve just launched our first JMatter application. We should be greeted withthe login screen shown in figure 3.1.

Figure 3.1: Contact Manager Login Screen

Page 23: jmatter

3.2. THE TOUR 13

When an application is first created, a single user will exist in the system. The username and password values are admin. Later on, we’ll show you how to changethe admin password.

Go ahead and login. You are now presented to your application’s desktop (seefigure 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 mostapplication toolbars. Instead of containing various actions (such as copy, paste,and others typically found in a word processing application, for example), thistoolbar contains types of things: Persons, Businesses, Users, Folders, etc.. I’mgoing to call this toolbar the Class Bar from here on. Furthermore, I will oftenreference the term as a single, lower-cased word: classbar.

The JMatter user interface was designed to be simple and easy to understand. Themechanism for communicating various activities to the application mirrors theway we naturally tend to think about how to perform actions. We first identifythe object in question, and then specify the action to perform.

Page 24: jmatter

14 CHAPTER 3. A SHORT TOUR

In JMatter applications, when an object is displayed in a minimized form (whichis the case with the various objects we see in the classbar), the various actionsto invoke are accessible via a context menu, summoned by right-clicking on theobject in question.

This gesture should be a familiar one. For example, on the windows desktop,right-clicking on a file or folder will “bring up” its context menu. On the Ma-cOS with a two-button mouse, it’s the same gesture (simulated as a ctrl-click ona 1-button mouse). GNU/Linux-based desktops have the same metaphor. Themechanism of first selecting an object, and then selecting an action is known as anoun-verb user interface metaphor2.

So for example, to browse the list of users defined in the system, you can moveyour 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 shouldsee something similar to figure 3.3.

2It’s worthwhile noting that many applications’ user interfaces today don’t abide by this metaphor.Typical applications’ toolbars contain actions and it’s not entirely clear what objects they relate to.When working with menus, you’ll pick an action first and an object second (think about how weusually open files in software applications: we pick the open action first and select the file second).

Page 25: jmatter

3.2. THE TOUR 15

Figure 3.3: Users

I promised I’d show you how to change the admin user’s password. Let’s do thisnow:

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 pass-word (twice, to guard against typos)

The next time you log in to the application, you’ll have to enter the new password.JMatter stores an md5 hash of the password in the database and so passwords arenot vulnerable to prying eyes.

Close the window containing the listing of users for now. Let’s go ahead and adda person to our contact manager. You’ve probably already guessed how to do it:right-click on the Persons icon in the Class Bar. Sure enough there’s an action onits context menu called New. That’s the one.

Page 26: jmatter

16 CHAPTER 3. A SHORT TOUR

Your screen should now look like figure 3.4.

Figure 3.4: Creating a new Person

Go ahead and complete the form. Note that there are two tabs’ worth of infor-mation to enter: the person’s name and their contact information. Furthermore,the second tab contains a collapsible element: the address portion of the contactinformation can be expanded to reveal the address fields (street, city, state, zip,etc..). After you’ve finished entering the information, go ahead and click the Savebutton. Your view of the information you just entered will change to a read-onlymode. To edit the information further, click the Edit button. Don’t worry if youclosed the window. Your information has been saved and you can retrieve thisnew person’s information at any time. Note that other users logged in to thesystem 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. Ifyou have a system with 300 persons in them, JMatter will make sure to page thelisting 15 entries at a time3. Also, notice that if you modify the Preferred ContactMethod for a person from, say, Home Phone to Email, then when you’re viewingthat person in a minimized context (say browsing through a list of persons), the

3The page size can be customized.

Page 27: jmatter

3.2. THE TOUR 17

title for that person will automatically change. In the former case, it might say JoeBurns, (512) 333-444 and in the latter case it will change to Joe Burns, [email protected].

You can also create objects of type Business, for example, if you need to keep trackof contact information for various businesses that you interact with. The mecha-nism 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 possi-bility of accidental deletion of important information. JMatter does this by pro-tecting the Delete action with a lock. Just click on the lock first to unlock the actionand then click on the button to perform the deletion.

It’s important to note that JMatter applications’ user interfaces are very simple:they boil down to the implementation of a single concept: the noun-verb userinterface metaphor. That is, we’re in a world of objects and we manipulate themthrough actions5.

3.2.2 Folders

Notice the Folders icon in the classbar. Right-click the New with name action, andspecify a name for the new folder you’re creating. Let’s say that you want to keeptrack of important contacts, in which case you might want to name the folderImportant Contacts. After entering the folder name, click OK. The folder is createdand displayed on the screen.

From a listing of Persons, you can simply drag and drop an entry onto the folderto add that person. You can put pretty much anything you want in a folder. Theconcept is completely analogous to the notion of folders on Operating Systemdesktops. The difference of course is that you are not putting folders and filesinto a folder, but any type of object that is defined by the application, includingFolders, Persons, Businesses, Queries, and more.

Drag and Drop is only one mechanism to add items to a folder. I’ll be showingyou 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 isnot a problem of course since the application is backed by a database management

4CRUD: Create, Read, Update, Delete5Aside: 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 buildyour own such applications, very little else is needed other than defining an object model (classes andmethods).

Page 28: jmatter

18 CHAPTER 3. A SHORT TOUR

system, designed to hold thousands of records, gigabytes of information. Theprimary advantage of a database of course is its ability to mine information.

I’d like to look up all members of the Suez family in my contact manager. Here’sone way to do this using JMatter: right-click on Persons in the Class Bar and pickthe corresponding action, which this time will be Find.

When invoking Find on Persons, a window will appear containing a way for us tospecify a query. This one will be fairly easy:

1. From the pull-down menu on the left, select Person Name’s Last;

2. From the second pull-down menu, select the appropriate comparison oper-ation; in this case it does not really matter, let’s pick contains

3. In the text field on the right hand side, enter Suez (or whatever last nameyou’re 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.

Let’s take this example one step further: click on Save Query. At this point yourscreen should look something similar to figure 3.5.

Page 29: jmatter

3.2. THE TOUR 19

Figure 3.5: Performing and Saving a Query

Give your query a name (I called it The Suez’s) and click Save. We’ve just definedand executed a query, then named it and finally 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. That’s why there exists an entry in the Class Bar calledqueries. Go ahead and browse queries (right-click Browse on Queries in the ClassBar) and you’ll see your new query show up in the list (see figure 3.6).

Page 30: jmatter

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 awhile, after you’ve defined lots of queries, the ability to search for a query (byname) might come in handy.

Now that your query is defined and saved, you can execute it at any time. Youguessed it, just right-click the Execute action on any query listed and you’ll get thesearch results. If another matching entry is entered into the system after a queryis created, the search results will include the new entry as well, of course. JMattercalls this feature a Smart List.

Finally, since the query we just saved was a query on Persons, JMatter went aheadand established an association between the Persons type and this new query. Ittook the liberty to add a new action to the Persons context menu. That is, you cannow right-click The Suez’s on Persons.

3.2.3.1 Quick Recap

I know we haven’t yet reached the chapter about actually writing applications inJMatter. Still, it’s important to note even at this early stage that the query facilities

Page 31: jmatter

3.2. THE TOUR 21

baked into this application are provided by the framework. You will not find asingle line of code in the Contact Manager application to support these capabili-ties.

Something should be clicking at this point. Attempt to quantify how many lines ofcode exist in a “traditional” software application to support searches; especiallyfor a category of application such as an issue manager. Issue managers are allabout entering and updating and searching issues. Since entering and updatingand searching things is built-in in JMatter, then very little work actually remains:the need to define that there exists such as thing as an issue. That’s about it.

Also, notice how both developers and end users are empowered by this model ofbuilding applications:

1. end users do not have to go to a developer in order to define a new queryin 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 oflog entries and you’ll see a screen that looks like figure 3.7.

Page 32: jmatter

22 CHAPTER 3. A SHORT TOUR

Figure 3.7: Log Listing

What we discover is that the framework keeps track of specific events such aswhen a user logs in or out of the system or when a specific piece of information iscreated or updated6. The system creates a log entry: a message, possibly a longerdescription of the event that took place, who performed the specific action, andwhat object this action was performed on. Since log objects are proper JMatter ob-jects (like Person and Business) they inherit the same benefits: the ability to searchthrough logs, to view and even edit logs (though technically that last bit shouldbe forbidden, and can be made so7). You can also see in figure 3.7 that the listingis currently showing you the first of two pages of logs, with a page navigationarrow at the bottom.

6Tapping into this log system to log additional activities is trivial7See section 10.2 on authorization

Page 33: jmatter

3.2. THE TOUR 23

3.2.5 Multiple Views

Before we end our tour, there’s one last major aspect of the user interface that weneed to discuss: the notion of multiple views.

You might have noticed four little icons on the top right-hand-side of listings win-dows. Bring up a listing of persons (right-click Browse on Persons) and click on theicon with the yellow star in it. You should see something similar to figure 3.8.

Figure 3.8: Icon Alternate List View

The user interface for the Contact Manager application basically provides multi-ple 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, withthe Person’s fields (name, contact information) laid out in separate columns, or asa composite view: a listing on the left-hand-side combined with a form view ofthe currently selected item on the right hand side. This notion of multiple viewsshould feel familiar, as it’s akin to the way file managers on our desktops behave:we can view a listing of files and directories in detail view or iconized view and so

Page 34: jmatter

24 CHAPTER 3. A SHORT TOUR

on.

For single objects, say a single contact, you will likewise find alternate views. Youcan use a tree view for a contact where the tree is arranged in such a way that as-sociations between objects can be traversed. So for example, we can lookup a logentry about someone logging in to the system and view that entry in a compositetree view, as shown in figure 3.9. By expanding the tree nodes we can discoversome of the associations between log objects and other objects. In this case, theperson who logged in was the administrator. We also discover that users can beassigned to roles. The admin user belongs to the Administrators role, which inturn also keeps a list of all the users in the system that have the same role. Finallywe see that roles maintain lists of field and command restriction objects. It is byadding such restrictions to roles that we can begin to specify an authorization pol-icy for our system: who is allowed to view what fields, who is allowed to invokewhat 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

Page 35: jmatter

3.2. THE TOUR 25

learn the way information is modeled in a system, the various associations be-tween types of objects, and how to traverse them. In chapters 5 and 6 we’ll havea chance to explore such relationships.

3.2.5.1 Custom Views

Going back to the notion that we can have multiple different and complementaryviews for objects or lists of objects: certain types of objects have additional customviews, specific to that type. For example the Class Bar is nothing but a customview of a folder of folders. Although I won’t show you how to do this untilsection 4.5, you can look for a special folder named Class List whose contents arereflected in the Class Bar.

Figure 3.10 shows a composite tree view of the class bar. You can right-clickBrowse or New on any of the three views of the Persons type, for example. Fur-thermore, it is possible to customize the class bar by placing other types into thatfolder (for example the Role type, which would be useful for system administra-tors who sometimes need to define a new role, or add new users to an existingrole).

Page 36: jmatter

26 CHAPTER 3. A SHORT TOUR

Figure 3.10: Three Views of the Class List Folder: A tree, an icon list, and the classbar

This brings up an important point about the philosophy behind the design of theJMatter framework: to the greatest extent possible, the JMatter framework strivesto give the end user more control of the application, more independence from thedeveloper. How often have you been in a position where you really wanted tomake a simple change to the way an application is configured only to find outthat the change could not be performed from its user interface (i.e. it requiredprogramming)?

3.2.6 Tour Summary

Let’s review what we’ve accomplished so far.

We’ve seen how to launch the Contact Manager application, log in, and create anew user if we wish to. We learned how to browse and create contacts, and onceour contact list becomes very large, how to make practical use of the query feature

Page 37: jmatter

3.2. THE TOUR 27

to find the information we’re looking for. We also know how to switch betweenalternate views of the same information, and have a good grasp of what JMatterapplications are all about, from the end user’s perspective.

Finally, we have a general understanding of the noun-verb metaphor that JMatterapplication user interfaces model. That is, the notion that one first selects a targetobject on which to perform an action, and then looks for and invokes a specificaction on that object. This knowledge should enable us to quickly learn the userinterfaces of other applications written with JMatter, even ones we’re encounter-ing for the first time.

In the next chapter, we’ll start exploring how to write JMatter applications. We’llbuild our own contact manager. You may or may not be surprised by now if Iwere to tell you that the task will take us only a few minutes.

Page 38: jmatter

28 CHAPTER 3. A SHORT TOUR

Page 39: jmatter

Part II

Tutorial Applications

29

Page 40: jmatter
Page 41: jmatter

Chapter 4

A Zero-Code Contact Manager

Let’s write our own version of the contact manager. The point of this chapter is tolay the foundation for writing JMatter applications. You will learn how to createand setup a project, what information goes where, some of the configuration filesand their role in a JMatter application. As the title of this chapter indicates, wewill not have to write a single line of code to implement our first 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. Let’s call it CM (short forContactMgr), so as not to conflict with the existing demo version of the contactmanager application.

31

Page 42: jmatter

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 doesn’t reallymatter at this point. Let’s go with dependent1. Go ahead and click on the CreateProject button. This action will launch an ant target that takes our input and cre-ates a complete directory structure for us. If you didn’t specify a base directory,the new project is created by default in the jmatter directory’s parent directory.

Go ahead and quit the new-project-ui “applet.” Let’s navigate to our new project’sbase directory:

$ cd ../CM

$ ls

build.xml doc/ resources/ src/ test/

JMatter creates the directory structure for your project, along with its own antbuild file.

4.2 The Schema

We would normally proceed by modeling our application: identifying the enti-ties, and implementing them as Java classes. With JMatter however, things area little different. JMatter was designed to be a framework for building businessapplications. As such, JMatter predefines a number of common types of busi-ness objects, including persons, their contact information, addresses, and busi-nesses. In this chapter we’ll reuse the predefined implementations of Person andBusiness, whose fully-qualified class names are com.u2d.type.composite.Person andcom.u2d.type.composite.Business, respectively.

Before we generate our schema, we need a way to communicate to JMatter thevarious types of objects we would like to persist. We typically do this by adding

1The distinction between standalone and dependent projects is discussed in chapter 16 on page 191

Page 43: jmatter

4.3. THE CLASS BAR 33

an annotation (@Entity) directly on the model classes that we define. However inthis case, since we’re using pre-existing model classes, we do this by editing theunderlying template, src/persistClasses.st, directly:

..

<value>com.u2d.type.composite.Person</value>

<value>com.u2d.type.composite.Business</value>

..

We simply add the fully qualified names of the two classes Person and Business tothe listing. We’re now ready to generate the database schema:

$ ant schema-export

Behind the scenes, JMatter introspects the classes in question and for each it gen-erates a Hibernate database mapping file, and finally asks hibernate to generatethe DDL (data definition language) instructions and send them to the database.

We should now be able to inspect the contents of our database and verify that itcontains these tables. By default, JMatter uses the H2 database, which is lightweightand requires no work on your part 2. By default, JMatter created the databaseCMh2db in the db/ subdirectory of your project. To view its contents, you can usethe 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 betterdocumented by H2’s own documentation, of course.

4.3 The Class Bar

Similar to the task of specifying which types to persist to the database, we alsoneed to specify which types to expose to the user interface via the Class Bar. Thisstep is not really necessary, because we can edit (in this case, add types to) theclassbar directly from the user interface. Feel free to skip this section if you wish.

The way to predefine the default classbar items is to edit src/class-list.json:

2You may of course create your own, say, PostgresQL or MySQL database and configure yourapplication to work with it. Appendix B provides the necessary information.

Page 44: jmatter

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 file is nothing but a marshalled Folder object (in JSON format3). When theapplication starts up, the file will be unmarshalled back as a Folder object. JMatterwill detect that our database is empty (it contains no classbar) and will automati-cally persist the folder. Each user has his or her own class list. The xml file servesas a template. This is useful since many applications have multiple users, withdifferent roles. So different classbars can be defined for each role.

4.4 Running Your Contact Manager

Let’s do one more thing before we run our application: let’s give it a splash screen.Do this by dropping a file named splash.png (or splash.jpg or splash.gif ) into theresources/images folder. If you like, just copy the one from the demo application.

Ok, let’s run our app:

$ ant run

That’s it. We now have a working contact manager application. Go ahead andexercise it: create new person objects, etc.. (see figure 4.2).

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

Page 45: jmatter

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 di-rectly from the User Interface. We’re 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)

We’ve just asked our application to show us all the types defined in our system(Note that Contact Methods is among the list of defined types, though it doesn’thave 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 classbar

Page 46: jmatter

36 CHAPTER 4. A ZERO-CODE CONTACT MANAGER

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

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

4.6 Project Structure

Let’s take a closer look at the files in our project.

4.6.1 Files

JMatter defines certain conventions for where to place files. These conventions areprobably very similar to your existing project conventions. Here is a summary ofthese conventions:

1. Source code resides in the src/ directory

2. You will find certain resources, such as images, in the resources directory

3. The ant build file for your project uses the default name build.xml and residesin your project’s base directory

Page 47: jmatter

4.6. PROJECT STRUCTURE 37

4. Your source code is compiled to the target directory build/classes

5. JMatter generates Hibernate mapping files for persisting your domain ob-jects; these files by convention bear the suffix “.hbm.xml” and also are writ-ten to the build/classes directory

6. When deploying your application with Java Web Start (see chapter 18), thedistribution file is placed in the dist directory

7. The doc directory contains a simple README file, serving as a quick refer-ence 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 foryour project.

8. The test directory is created for you to place JUnit tests you write to ensurethat your code and business logic is correct and bug-free

4.6.2 Ant Targets

You don’t need to memorize the names of the ant targets that we invoke (e.g. antrun, ant schema-export); simply type:

ant -projecthelp

to view a list of all the defined targets: their name and description (Of course, ifyou’re running GNU/Linux and have bash smart completion turned on, simplypressing the tab key will display a list of valid ant targets).

4.6.3 A Peek at the Source Code

Open the file Person.java in a text editor or IDE4 (it is located in jmatter/src/com/u2d/type/composite).We’re not going to attempt to understand every line of code just yet.

What I want you to notice is that a Person defines two fields: name, and contact:

protected final Name _name = new Name();

protected final Contact _contact = new Contact();

The Java classes Name and Contact are also defined in the framework. The Nameclass is composed of the parts that make up a name: prefix, first, middle, last, andsuffix.

If you dig a little deeper, you will see that Contact.java defines these fields:

4IDE: Integrated Development Environment

Page 48: jmatter

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 Phonenumber, an Email address, a US Address and a Contact Method.

If you inspect the generated database schema for our application, you will notfind a database table to hold contact information or addresses.

The reason is that with JMatter, you have the choice of modeling a field either asan association or as an aggregation. In the context of the class Person, Contact andUSAddress are modeled as aggregates, and so are treated in a manner similar tovalue fields such as the work phone or email address. The fields that make upthe contact information and address are aggregated into the parent type’s table.Hibernate calls these Components. If you’re familiar with the concepts in the bookDomain-Driven Design [5], then you’re already familiar with both Aggregates andValue Objects.

We’ll learn more about ways of modeling relationships between objects in the nextchapter. Chapter 8 provides a more complete reference.

4.7 Summary

Here’s 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-uicommand;

2. We are aware of two configuration files src/persistClasses.st and src/class-list.jsonand know a little about how to configure 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 ourapplication: ant schema-export and ant run

5. We studied the structure of a JMatter child project

With the basics for setting up, configuring, and running projects under our belt,we’re now ready to do some real work. In the next chapter, we’re finally going toget a chance to write some code in the MyTunes music application.

Page 49: jmatter

Chapter 5

MyTunes in under 200 Lines

Tunes have become a popular topic. Let’s build a music player! Before we getstarted, bear in mind that we won’t have to build features such as Smart Lists forsongs; JMatter will give us those things for free. We’ll be able to concentrate onthe task at hand: modeling our application and implementing the behaviours ofour music player, such as importing songs into our song database, and playingsongs, of course. Let’s get started.

5.1 Creating the Project

We know how to create our project. I’ll name my project MyTunes and make it adependent project. A finished 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, let’s setup our project in our favorite IDE because we’refinally going to be writing code.

5.2 Setup your Project in an IDE

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

39

Page 50: jmatter

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 doesn’t really matter which you use, or whether you use oneat all, as long as you’re 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 we’ll 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 jarfiles in ../jmatter/lib/runtime to my project classpath so that the classes we referencecan be resolved. If you created a dependent project as I did, add the directory../jmatter/build/classes to your classpath as well. Since the specific instructions varyfrom IDE to IDE, and since this is such a basic operation, I won’t hold your handthrough this task. :-)

Before getting started with coding in the next section, you might want take a quickpeek at section 20.2 on page 220 to setup some JMatter-specific file templates andlive 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 themain entities in a music player system appear to be Songs, Albums, Artists, andGenres. Pretty straightforward. Let’s get started by modeling each of these:

Page 51: jmatter

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

Let’s 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(); }

}

Let’s analyze the above:

1. The @Entity Annotation: automates having to manually edit src/persistClasses.stas we had to do in the last chapter

2. Artist extends AbstractComplexEObjectIn Java all the classes we write extend Object. When building JMatter ap-plications, the base class for complex entities (ones that have more than asingle field) is AbstractComplexEObject. Just like Object gives us toString()for free, AbstractComplexEObject also gives us a few things for free.

3. Artist has two fields: name, and bioIt happens to be a personal style choice of the author to name instance vari-ables with the underscore prefix. This, of course, is not necessary.

4. Funky types: name is a StringEO, bio is a TextEOThat’s right. JMatter gives you a whole slew of atomic types to choose from,including types for phone numbers, social security numbers, time dura-tions, images, email addresses, colors, and much more. It’s quite easy toadapt a String as a StringEO and vice versa. There are two differences be-tween a StringEO and a TextEO:

Page 52: jmatter

42 CHAPTER 5. MYTUNES IN UNDER 200 LINES

(a) StringEO’s are saved to the database as varchar types (limit is typically255) whereas TextEO’s are saved as text types or some other similarlarge text object1; and

(b) StringEO editors in the GUI are text fields whereas TextEO editors aretext areas.Think of the EO part of the type name as being an acronym for En-hanced Object.

5. Name and Bio are marked final!Yep. That’s part of the ValueHolder contract, these are never null. To set avalue on an atomic or aggregate type, call the setValue() method. Conse-quently, atomic fields and aggregates in JMatter classes have only getters.

6. public static final String[] fieldOrder = {”name”, ”bio”}This is essentially metadata. You’re giving JMatter a hint as to the order thatyou’d like these fields displayed when viewed using a form view. Nameshould come first, bio second. Notice that the field names are those derivedfrom the accessor methods according to the JavaBeans convention, not theunderlying variable names.

7. public Title title() { return _name.title(); }Every JMatter class you define must specify a title. In this case, the titlefor an artist object will simply be the artist’s name. For the Person class inthe previous chapter it was a concatenation of the person’s name and thevalue of their preferred contact method (phone number or email address).The idea for the Title class was shamelessly taken from the NakedObjectsframework [1], though you’ll find in it a few additional features, such asthe appendParens() method which allows you to perform concatenation bywrapping the argument in parentheses.

That’s it. The code is not very lengthy, but this first-time explanation certainly is.

One last note: If you’re thinking right now that metadata such as the fieldOrderfield above might be better modeled using Java 5 annotations, I would agree withyou; I may do just that in the next version of JMatter. But this design decision hasno bearing on your productivity as a software developer.

5.4 The Album Class

In a fashion similar to the way we wrote Artist, let’s now write a simple imple-mentation for an Album:

1depending on the rdbms you use

Page 53: jmatter

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(); }

}

There’s really very little new here. It’s worth mentioning that we’re defining afield of type ImgEO for the album’s cover illustration. This basic type representsan image (gif, jpg, or png) that will be saved to database as some kind of binarylarge object (blob).

5.5 The Genre Class

Let’s take a look at Genre next. Genre is a little more interesting. I decided toconsider this type more like an enumeration. That is, that there should exist afairly small, finite list of genres. However, unlike enumerations, we don’t want tohard-code the list of genres in Java. We would like the end-user to be able to addentries to the list directly from the user interface. This is the template that JMatterdefines 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();

Page 54: jmatter

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 thatwe’ve extended a different class: AbstractChoiceEO. In the GUI, when we wantto specify a genre for a song, we’ll be picking the genre from a ComboBox (alsocalled a select or pull-down menu). For each Genre object we’ll specify both a codeand a caption. The line

public static String[] identities = {"code"};

is metadata telling JMatter that the code column in the table should be uniquefor all Genres (that is, you can’t have two genres with the same code, ’rock’ forexample).

5.6 The Song Class

Here’s a first 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"};

Page 55: jmatter

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. Let’s review this class:

1. The song class defines the fields: title, duration, album, genre, and artist. Asusual, we define the fieldOrder String array as a means of specifying theorder in which these fields are to be displayed.

2. The duration field is of a type we haven’t seen before: TimeEO. This type canbe used to specify a certain length of time.

3. @Fld(format="m:ss")We’re specifying through a field annotation parameter that in this appli-cation we’re going to want to format durations using minutes and seconds.The format string complies with the contract specified by java.text.SimpleDateFormat.

4. Accessors and MutatorsFinally we see that not all fields are owned by the Song class. The fields al-bum and artist are associations to other entities. The convention for definingand specifying the accessors and mutators for association fields is different.It complies with the JavaBeans convention for bound properties. Notice we:

(a) provide both a getter and a setter, and

(b) fire a PropertyChangeEvent after the assignment.

Page 56: jmatter

46 CHAPTER 5. MYTUNES IN UNDER 200 LINES

5. Here we have a better example of a title() method. First, don’t confuse thesong title with the song type’s title() method. They’re two different things.We want songs to display their titles and durations and so we concatenatethe two. I use the utility method appendBracket to display the song durationin square brackets.

5.7 Running our Application

We’ve been a little zealous here and defined 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 didn’t implementany behavior, we simply defined four types along with some pretty basic proper-ties on each, such as the Artist’s name, a Song’s title. If you like, feel free to keepthe Song class even more simple by just giving it a title for now.

5.7.1 Configuration

Technically there is no configuration left to do. However, it might be simpler forus to specify the contents of the classbar for our application in xml form. Again,this is optional. The file to edit is src/class-list.json. Here’s a sample that’ll donicely:

{

"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" }

]

}

Page 57: jmatter

5.7. RUNNING OUR APPLICATION 47

}

]

}

}

5.7.2 Finally Running the Application

Nothing new here. Let’s run our app:

ant schema-export

ant run

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

Figure 5.1: A first look at MyTunes

This is problematic: we haven’t specified any icons for our types. Let me tell you(and I speak from experience) that the choice and quality of your icons is as impor-tant to the success of your application than the quality of the code itself. I stronglybelieve that all aspects of our application must be of high quality, regardless of

Page 58: jmatter

48 CHAPTER 5. MYTUNES IN UNDER 200 LINES

whether it’s the code under the hood or perhaps cosmetic items that many devel-opers often perceive as being outside their jurisdiction, or outside their realm ofexpertise.

Here’s how to specify icons for each type: in the resources/images directory, place16x16 and 32x32 pixel versions of an icon for each type. The naming of theseimage files is important. It is via a file naming convention that JMatter knows toassociate an image with a type. This idea again was shamelessly taken from theNakedObjects framework. If you haven’t guessed it by now, NakedObjects [1]had a strong influence on my thinking.

Ok, images can be of type jpg, png, or gif, or anything that Java Standard Editionsupports. Here is a listing of my resources/images folder:

eitan@ubuntu:~/projects/ds/MyTunes$ ls -lF resources/images/

total 40

-rwxr-xr-x 1 eitan eitan 855 2005-11-28 21:38 Album16.png*-rwxr-xr-x 1 eitan eitan 1961 2005-11-28 21:39 Album32.png*-rwxr-xr-x 1 eitan eitan 1961 2005-11-29 07:56 App32.png*-rwxr-xr-x 1 eitan eitan 859 2005-11-28 21:39 Artist16.png*-rwxr-xr-x 1 eitan eitan 2170 2005-11-28 21:40 Artist32.png*-rwxr-xr-x 1 eitan eitan 925 2005-11-28 21:39 Genre16.png*-rwxr-xr-x 1 eitan eitan 2596 2005-11-28 21:39 Genre32.png*-rw-r--r-- 1 eitan eitan 753 2005-11-28 21:13 README

-rwxr-xr-x 1 eitan eitan 696 2005-11-28 21:38 Song16.png*-rwxr-xr-x 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.pngfor each class. But that’s not the whole story on icons. For a complete descriptionof the icon conventions, see section 8.4.4.

If, like me, producing icons is not your forte, then I highly recommend the in-cors professional icons collection http://www.iconexperience.com/. Ok, now thingsshould look a little bit nicer (see figure 5.2).

Page 59: jmatter

5.8. BACK TO THE CODE 49

Figure 5.2: MyTunes with Icons

That’s much better, don’t you agree?

We can play with the user interface some more and create genres, songs, and soon, but we’re not quite finished with our application.

5.8 Back To the Code

Our application’s foundation is laid; we have a basic object model. But we’remissing something: an album should define and maintain a list of songs. Wealready have the other side of that association in Song.album. Let’s add that one-to-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 you’re thinking that the above might be better modeled using Java 5 generics, Iwould agree with you; I may do just that in the next version of JMatter.

Page 60: jmatter

50 CHAPTER 5. MYTUNES IN UNDER 200 LINES

We defined a relational list of type song. The reason for the static Class songsTypeis to allow JMatter to introspect the list type statically. It’s not pretty but it will dofor now.

One last thing: we have a bidirectional one-to-many relationship between a songand an album. We need to add two more lines of metadata to tell JMatter aboutit. 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 whenwe add new fields to types. There are two ways to bring them back in sync. Theeasy 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 don’t have any precious data to save and restore yet sowe’ll go the easy route of either using schema-update or schema-export.

Page 61: jmatter

5.9. VALIDATION 51

5.9 Validation

You might have also noticed that you can now create albums or songs with noname or title. This is a little disconcerting. There are two ways to address thisissue. The first might be to specify that a song’s title or album’s name should beunique. We’ve seen this already with Genre: you can specify the field metadataidentities to enforce this. So in Album, you can add this:

public static String[] identities = {"name"};

Like fieldOrder, you can specify multiple identity fields if necessary. The fieldis flagged with the ’unique’ database constraint and in addition, JMatter treatsidentity fields as required.

In this case, it happens to be a coincidence that the fields we wanted to markas required also happened to be unique (i.e. you should definitely not go aboutmarking fields unique for the purpose of making the user interface treat them asrequired fields).

To mark fields as required, edit the file 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 fields’ captions are automatically styled in blue; (you can changethe styling of required fields by modifying the rule “.required” in the fileresources/styles.css2)

2. Validation checks will automatically be performed when attempting to cre-ate or save instances;

3. The user interface will automatically display validation error messages inthe proper locations on the form

Figure 5.3 shows the behavior of the JMatter user interface after the change.

2See chapter 17 for more about styling the user interface using CSS

Page 62: jmatter

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 pre-wired to support validation. This mechanism we just specified is the simple way,for required fields. There’s an additional method validate() that we can override inany of our types to specify more complex validation rules that have dependencieson multiple fields. For a more complete treatment of validation in JMatter, seechapter 9.

5.9.1 A word about the model-metadata.properties File

Although the mechanism of specifying model metadata in a text file may continueto exist in the future, it is the goal of the JMatter framework to move all of thatwork directly into the GUI. Whether a field is required, a field’s default value, itscaption and more will all be entered in the same way one enters the username fora new User. The intent is for Field types (and meta-types in general) to becomefull-fledged JMatter objects, with a GUI, editability, and so on.

One can definitely imagine a new role for a JMatter user: the configuration man-ager, who uses a JMatter application to configure a JMatter application beforereleasing it to its user population. In fact, I recall reading early versions of the

Page 63: jmatter

5.10. BEHAVIOUR 53

J2EE specification years ago where they outlined a number of roles in applicationdevelopment.

5.10 Behaviour

So far, we seem to have nice, working model for a music application: we cancreate songs, albums, associate them. We can define artists like the famous ShlomoArtzi for example.

This modeling is important, don’t get me wrong. After we’ve defined a thousandsongs, we’ll have powerful search features at our disposal to find that one specialsong. What’s missing is behaviour: the ability to play songs! Also, it would beawfully tedious to enter all that information by hand. Can’t we just import thatstuff from our iTunes library?

So, we’ve just defined some additional work for ourselves: we’d like to be able toplay songs and we’d like to be able to import songs listings.

A short glance at the Java sound API javadocs tells us that we can attempt to playan mp3 file 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 file is located. So we’llneed to add a new field to Song:

private final FileEO _path = new FileEO();

And add the new field to our fieldOrder 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 let’s add this construc-tor:

Page 64: jmatter

54 CHAPTER 5. MYTUNES IN UNDER 200 LINES

public Song(File path)

{_title.setValue(path.getName());_path.setValue(path);

}

Don’t forget the accessor method for _path:

public FileEO getPath() { return _path; }

Finally we need to expose a play command to our user interface. Since we’realready 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 files but not for MP3’s. A quick googleand 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 file tells us we justneed to add three jar files 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

Page 65: jmatter

5.11. ANALYSIS 55

Now we’re in business3. Let’s 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 thenstarted playing Amour Perdu, by Adamo (see figure 5.4).

Figure 5.4: Playing Amour Perdu

Time to slow down and explain some of what we just did..

5.11 Analysis

5.11.1 FileEO

JMatter provides editors for all kinds of basic types including Files. Our path wasof type FileEO. This implies to the user interface to use the designated editor for

3And you thought that the part in the movie The Matrix where a helicopter manual is summoned afew seconds prior to flying one was pure science fiction. :-)

Page 66: jmatter

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 com-mand in the user interface maps to a method implementation on my class, justas a type in the UI is implemented via a Java class. The convention to follow forcommands is to decorate the method with the @Cmd annotation. This annota-tion accepts a number of options, including the mnemonic character that the userinterface will use to make the command keyboard-accessible. There’s one addi-tional requirement, that these methods take a CommandInfo argument. We don’tactually need that information in this particular case but there exist situationswhen we do. Anyhow, it’s part of the current convention established by JMatter.

The caption that JMatter uses in menu items and buttons representing a commandmethod is derived from the method name. For an annotated method named Pro-duceHCFA_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 separatethread. JMatter does all this for us. Our user interface remains responsive theentire 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 Linuxanyway) to indicate that the song has not finished playing, we have full controlover the UI and can close our window, open new ones, perform queries, etc.. allwhile our Song plays in the background.

5.11.3 message()

There’s 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 viewmechanism to display a message. The Swing view mechanism displays the mes-sage in a large font in a semitransparent window that automatically dismissesitself after two second.

5.11.4 Return Type

Our command method returns an Object. Here is yet another simple conventionestablished 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

Page 67: jmatter

5.12. IMPORTING SONGS 57

get an exception attempting to play our song, we’re 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 boxthat one is forced to dismiss, JMatter displays a timed, semi-transparent, border-less dialog with the message which automatically disappears after a few secondsor when clicked on.

Let’s proceed and implement our second task: a mechanism for importing songsfrom our iTunes library.

5.12 Importing Songs

So here’s the issue: sitting in my ~/music/iTunes Music/ folder are a bunch of mp3files. I don’t want to add them to my system one by one. I’d like to basicallyright-click on Songs and request that MyTunes scan for songs on my disk, from aspecific base path. I decided to call my command Scan From Base Path and so willname 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");

}

};

Let’s study this bit of code:

Page 68: jmatter

58 CHAPTER 5. MYTUNES IN UNDER 200 LINES

1. Our method is defined as static to ensure that our command is added to theSong type, and not to song instances. The command will be accessible fromthe Class Bar (right-click on Song).

2. Next, we see that we use the same little trick of returning a string if the spec-ified path is not a directory. So the user will get an error message when theypick 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 typeFileEO. When this command is invoked, JMatter will see that this methodneeds a path and will prompt the user for it.

3. Look towards the bottom of the listing: we’re defining a plain old Java filefilter (POJFF) to let through only files with a .mp3 suffix. Then we invokea method listRecursive() on FileEO, passing in the file filter. Now we have alisting of all the mp3 files nested inside the user’s specified base directory.

4. Now all we need to do is create a Song object for each file and save all thesesongs. Not bad for ~ 10 lines of code, if I may say so.

Let’s try this out. No persistence-related changes have taken place so we can justre-run our app:

$ ant run

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

Page 69: jmatter

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 arenot correct of course. A better way to solve this problem would be to interpret theiTunes xml file, which contains all sorts of song metadata besides the basic songfile information.

5.13 Not Completely Finished

If we take a moment to think about our implementation, we’ll realize that ourwork is not exactly done. Although our songs actually play, our implementationis naive. Is the song actually streamed? Are resources disposed of properly?

A little more research into Java sound shows us that the API we’re using is reallyoutdated. There is a newer Java sound API in the javax.sound package. Further-more, even that API has been somewhat deprecated by the Java Media Frame-work, which is an add-on to the standard Java distribution. Finally, we discoverthat JMF itself has been in maintenance mode for a number of years now. Someadvocate using Apple’s QuickTime for Java API (QTJ). I personally have an issuewith using QTJ: it doesn’t run on my computer. That is, Apple does not writetheir APIs or software applications to run on GNU/Linux, even though they hadno qualms about pillaging open source code for their operating system kernel, orfor their Safari web browser, just to name a few situations. I suppose giving is aone-way street.

Page 70: jmatter

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 theJava Media Framework

2. Write a second, alternative import implementation that interprets iTunes’XML metafile

3. Revise our model to define the notion of a current playlist, add a commandto Song to add it to the playlist, and finally, move the play and pause com-mands from Song to the new PlayList. This revised model seems to make alittle more sense.

It turns out that if we discard the Java Sound API and the MP3 provider interfacewe downloaded, and instead use the JLayer library and its API, we get beauti-ful mp3 streaming for free in Java. The MyTunes demo application in the JMat-ter distribution was revised to use JLayer directly and mp3 files of all sizes playimmediately without consuming gobs of memory. I leave the study of the finalapplication to you as an exercise.

The point here is that JMatter frees you to work on the important things, like prop-erly importing or playing a song. You don’t have to worry about infrastructureservices such as persistence, queries, or a user interface.

In very little time, we created a basic music player with Smart Lists. Figure 5.6shows the quick search feature built into JMatter where you can just type in a songtitle in a listing’s searchbar to filter the list accordingly.

Page 71: jmatter

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 understate-ment. And yet, if we go through the due diligence of measuring how much codewe 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! That’sreadable. That’s workable. But not just 200 lines of code: a full-fledged musicplayer in under an hour? That’s a paradigm shift.

Let’s quickly review what we learned in this chapter:

1. We learned how to setup our project in an IDE.

Page 72: jmatter

62 CHAPTER 5. MYTUNES IN UNDER 200 LINES

2. We’ve learned the basic class template for our business objects in JMatter:our classes extend AbstractComplexEObject, they have aggregate propertiesthat adhere to the ValueHolder pattern, and they have associations to otherobjects that follow the JavaBeans accessor-mutator pattern.

3. We learned how to control the field order in the GUI with the fieldOrderstatic member; we can specify that a property is unique by including it inthe identities static member.

4. We learned how to associate icons with types by placing our icons in theresources/images folder, and following a specific naming convention.

5. We learned how to expose both instance and class (static) actions to the UI.We’ve also seen how to write actions that take arguments.

6. We’ve been exposed to some of the atomic types that JMatter provides outof the box, including: StringEO, TextEO, ImgEO, TimeEO, and FileEO.

7. We’ve also been exposed to a simple mechanism for specifying field meta-data, such as whether a field is required or not.

Although we have begun to dig deeper into this framework, there are many morefeatures that we have yet to discuss and uncover.

A small but useful additional feature that we’re going to use in the next chapteris the ability to customize icons on a per-instance basis. That is, we can use theartist’s photo as the basis for its icon in the MyTunes user interface; though we’llintroduce this feature in the context of a new application, the Conference ManagerSympster.

Some other, more serious features in JMatter include

1. Integration with JFreeReport for producing PDFs

2. Calendaring (we’ll see this in the next chapter)

3. Wizards

4. Polymorphic modeling support including interface-based modeling

Page 73: jmatter

Chapter 6

A Conference Manager

In this chapter we’re going to build a conference management application. Theidea 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 con-ventions of the JMatter framework

2. More metadata

3. How to use an object’s image field as its icon representation

4. How to add Calendaring support to your application

5. Polymorphic modeling

6.1 Analysis

Let’s begin by reviewing the nofluffjuststuff.com web site to get a feel for the busi-ness domain we’re 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 specific speaker

63

Page 74: jmatter

64 CHAPTER 6. A CONFERENCE MANAGER

4. We note that a speaker has a name and a biography, as well as a list ofpresentations

5. A presentation appears to have a title, an abstract, and an association backto the speaker

Let’s now take a look at upcoming or past symposia. Looking at the list of pastsymposia, I see that the Rocky Mountain Software Symposium took place duringthe weekend of November 11 2005. Click on a specific symposium and you’ll seea list of speakers, and a list of sessions. If you click on the link for the agenda,you’ll see another view of the sessions for this particular symposium. Note thatconferences will often have multiple sessions taking place at the same time, butat different presentation rooms.

So we can derive from this little stroll through the NFJS web site that some ofthe basic entities in a conference management system include a Speaker, a Talk (orPresentation), a Session, a Symposium, and probably a Room. We also have a fairlygood 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 specific location, at a specific time,with a specified 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 thetask of planning a new symposium, perhaps with scheduling sessions, printingagenda 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 inJMatter 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 proceedby writing our model classes.

Page 75: jmatter

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 oursystem: Symposium, Speaker, Talk, Session, and Room. Let’s create a Java packagewhere our classes will reside; proceed by creating a class for each of these types.

6.3.1 Type Icons and Config 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-qualified type name in src/class-list.json

6.3.2 The Symposium Class

Here’s 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"; }

}

We’re extending the base class AbstractComplexEObject. We defined a single fieldso far: the symposium’s name. We have a getter method for the name field, andour title() method. The new bit is the optional implementation of the static methodpluralName(). The default derivation of the plural name for Symposium is notintelligent enough in this case so we provide it. We’ve already seen how a type’splural name is used in JMatter’s user interface: each entry in the classbar displaysit; the titlebar for listings also displays the list item type’s plural name.

Page 76: jmatter

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. Speak-ers 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 toits speaker), I also specified the inverse field’s name. We also see the fieldOrdermetafield used to specify the display order of a speaker’s fields.

Notice that I could have chosen to use a Name type to represent the speaker’sname. In this instance I chose to keep the name simple as a single atomic field.

Page 77: jmatter

6.3. THE MODEL 67

6.3.4 The Talk Class

We’re still in the process of laying the foundation for our application. Here’s thecode for our first 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 to-one associations use the JavaBeans bound property conventions and fire an eventwhen they’re 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;

Page 78: jmatter

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);

Page 79: jmatter

6.3. THE MODEL 69

}

public Title title()

{

return time.title().append(":", talk).append(" in", location);

}

}

Again, very little new here. We have three fields: the talk, the location, and thetime span. TimeSpan is yet another basic type provided by the framework. It’s acombination of a date-time field and a duration. You can also think of a time spanas having both a start time and end time fields. Actually, this is how its defaultrenderer and editor depict it.

The title() method is also somewhat interesting as it attempts to concatenate thetime span along with the talk’s title and location title.

6.3.7 A First Look

I realize that I’ve been rushing through this a little. We could have easily writ-ten one class at a time and each time ran our application, thus building our ap-plication more incrementally. This in fact is a very good practice and a highlyrecommended one. Feel free not to follow me to the letter here.

Let’s take our first-draft for a spin:

$ ant schema-export

$ ant run

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

Page 80: jmatter

70 CHAPTER 6. A CONFERENCE MANAGER

Figure 6.1: First Look at our Conference Manager

Let’s 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 aspeaker and assign him or her a photo. Since a speaker has a list of talks, you cancreate 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 theinformation about the talk. The association will be made for you automatically.Alternatively, you can create a talk separately and then drag and drop the talkonto the speaker’s talks listing. Figure 6.2 is a snapshot of my screen after creatinga speaker and a talk.

Page 81: jmatter

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. No-tice that the date editor provides a date picker to facilitate entry. The time editorslikewise attempt to facilitate entry by providing small spinner arrows for incre-menting and decrementing the hour and minute fields. To associate a talk and aroom, again you have two choices:

1. Drop a talk onto the talk field of the session object (and similarly for thelocation field, drop a room object), or

2. Right-click Browse, Find, or New to browse and select an existing talk to as-sociate to this session, to query for and select a talk, or to create a new talkand then associate it to the session in question

Here is a snapshot of my screen after creating and setting a session:

Page 82: jmatter

72 CHAPTER 6. A CONFERENCE MANAGER

Figure 6.3: Creating and associating a Session

6.4 Enhancements

Let’s get back to our code and make a few additions, enhancements.

6.4.1 Type Color Coding

Here’s a useful piece of metadata to help distinguish between different types ofobjects in our system: color-coding. Here’s an example of how to specify thismetadata:

public static Color colorCode = new Color(0xffff00);

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

Page 83: jmatter

6.4. ENHANCEMENTS 73

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

6.4.2 Speaker’s Photo for Speaker Icon

We have a nice little icon representing a speaker. However, we have an even nicerone, and one that could help distinguish between speakers: their photo. Can’twe simply use the speaker’s photo as the basis for that instance’s icon? Certainly.Here’s 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 field in question.Then simply override the superclass’s iconLg() and iconSm() methods and delegatethe work to your assistant. Pretty simple.

6.4.3 A Second Look

Let’s check out our application with the changes in place.

$ ant run

I went ahead and created a few Speaker instances so we’d have something to lookat. Figure 6.4 shows two views of the speakers’ listing along with a maximizedview of Jason Hunter, a long-time NFJS speaker.

Page 84: jmatter

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 thecolor-coding in effect. These are small, nice, and valued enhancements to our userinterface.

6.5 Calendaring

One of the main tasks of managing conferences (or symposia, as they’re calledhere) is scheduling them, determining what sessions will be offered: where andwhen talks are to be given.

What will it take to build these features into our application? Let’s begin by study-ing the way JMatter models calendaring.

6.5.1 How JMatter Models Calendaring

The JMatter framework defines three main types of objects that work together toprovide calendaring features:

Page 85: jmatter

6.5. CALENDARING 75

1. Calendar EventsThese are basically items that one puts on a calendar. A meeting is a calen-dar event, for example. A visit between a physician and a patient is anotherexample. Here’s a third example: a session at a conference.

2. Resources, or SchedulablesAs its name implies, a Resource is something that can be occupied or con-sumed for a span of time. In our example, a room where a presentationis given is a resource. In the code, JMatter calls them schedulables. In aphysician’s clinic, the physician becomes the resource.

3. Grouping of Resources, or CalendarablesFinally, it’s important to get a view of how multiple resources are utilizedin time. We’d like to be able to see what sessions are going on at the sametime in six different rooms, so we can pick which presentation we wantto attend, for example. A nurse would like to see which physicians areavailable during a specific block of time, and so on.

So in our system, the Calendar Events are our Sessions, the resource is the Room,and finally our Calendarable is the Symposium. We can have many symposia andso 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 field: symposiacan take place in different venues. One could take place at a hotel in New YorkCity, another at a convention center in San Francisco, and a third could be takingplace at a university campus in Austin. Each venue would then have its own listof rooms where presentations are held.

For now we’re going to keep the venue constant. We’ll extend the model to sup-port multiple types of venues in section 6.6.

JMatter’s calendaring model can be found in the package com.u2d.calendar

6.5.2 Enhancing Sympster to Support Calendaring

Ok, let’s get to the code. Here is the simplest way to introduce calendaring toour application. Now that we’ve identified the relative roles of Session, Room,and Symposium and how they map to JMatter’s model for calendaring, we canproceed to enhance our code base. Let’s start with Session.

6.5.2.1 Enhancing Session

We need to:

1. make session a subclass of CalEvent;

Page 86: jmatter

76 CHAPTER 6. A CONFERENCE MANAGER

2. implement the contract for CalEvent.

The first 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();

}

We’re required to provide the name of the field in the class Session that corre-sponds to its timespan, so that JMatter knows how to display sessions in a calen-dar or a schedule widget. The name of this field happens to be time. Likewise,our calendar will display calendar events for different resources, so we also needto provide the name of the schedulable field on Session: location.

The third requirement, the calTitle() method could have been made optional but itis required by JMatter at the moment. It gives you a chance to specify a title for aSession 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, wespecify the talk’s title as the calendar-context title for Session.

That’s it for Session. Let’s 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

Page 87: jmatter

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 first 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 resourcesthat this calendar maintains. If each symposium had its own venue, the imple-mentation would simply have been:

return getVenue().getRooms();

In our case, we decided to keep our venue constant so we return the entire list ofrooms.

The second requirement is to provide the default calendar event type, which againis Session.

That’s it. We’re done.

Page 88: jmatter

78 CHAPTER 6. A CONFERENCE MANAGER

6.5.3 A Third Look

Let’s 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 Cal-endar. This command was inherited by CalendarEO. We see a calendar widget,similar to the one shown in figure 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, 30minutes, or 60 minutes per row

3. The ability to navigate to the next day or week by clicking on the navigationarrows (in day view, you’ll be navigating to the next or previous day, inweek view, you’ll be navigating to the next or previous week)

Page 89: jmatter

6.5. CALENDARING 79

4. A mini month calendar, for quickly navigating to a specific date in anothermonth or year

5. A date navigation text field, to quickly navigate to a specific date by simplyentering 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 specific time and location by double-clicking on a cell in day view

8. You can create a new session at a specific time and location, with a specifictalk by simply dropping a talk onto a cell in day view

9. You can alter the default session duration by right-clicking on the Sessionclass’s (in the class bar) Set Default Duration Hrs command.

10. You can alter the time or location of a session by simply dragging it ontoanother cell

11. You can open an existing session by double clicking on its representation’stitlebar in the calendar

12. You can invoke any commands on a session displayed in the calendar byright-clicking on its titlebar

I think you’ll agree that here again, JMatter provides tremendous leverage. Thedesigners of the JMatter framework are reusing this calendar across different ap-plications that span entirely different business domains. As the features of thiscalendar improve, all JMatter applications will inherit these improvements. Onemore time we ask you to compare the effort required to build such a featuretraditionally into an existing software application and what it took to integratescheduling into Sympster here.

6.5.4 Inheritance vs Interfaces

In order to gain the benefits of calendaring, we had to extend existing classes inour system. Luckily, our Session, Room, and Symposium did not already extendanother base class. Designing by inheritance has its problems in a world wheremultiple inheritance is not supported. But you don’t have to be locked in to it.

It turns out that JMatter does not require that you extend ScheduleEO or Calen-darEO to obtain these benefits. You can implement the Calendarable and Schedu-lable interfaces directly yourself and they really don’t require that much effort.Have a look at the source code for CalendarEO and ScheduleEO. They do very littleindeed. All they do is instantiate a Calendar and Schedule object respectively, andexpose an accessor method on it. That’s basically it.

Page 90: jmatter

80 CHAPTER 6. A CONFERENCE MANAGER

At the moment, the same cannot be said about a CalEvent. We are required tosubclass CalEvent. As we refine JMatter’s calendaring feature further, we expectthis requirement to be removed1.

6.6 Inheritance-Based Polymorphism

Let’s discuss how we would revise our application to accommodate symposiawith different venues:

1. Define a new field on Symposium called venueThe goal is for a venue to be a base type for multiple specializations, suchas a Hotel, a Conference Center, or a Campus (each of these three would beconcrete implementations of a Venue)

2. Define the base type VenueAt the very least, a venue should have a name and a list of rooms. So Venuewould 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 sub-folders (or edit the Class Bar directly from the GUI)

This particular situation lends itself nicely to implementing polymorphism viainheritance. Here’s 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 Conference-Center. Here is Hotel:

1One area worth researching JVM-compatible programming languages which support featuressuch as mixins or traits

Page 91: jmatter

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 defineCampus and ConferenceCenter. We can distinguish these three types by the icon wechoose to represent each type.

Finally, here are the changes I’ve 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 we’ve made:

ant schema-update

In this particular case, JMatter generates hibernate mapping files using the joinedsubclass 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 polymor-phic query and return a listing including hotels, campuses, and conferencecenters.

Page 92: jmatter

82 CHAPTER 6. A CONFERENCE MANAGER

2. Right-clicking New on Venues will prompt the user to select which concretetype they would like to instantiate. This is baked in to the user interface.When associating a venue to a symposium, right-clicking New, Browse, orFind on the symposium’s venue association field will do the right thing.

Figure 6.6: Sympster Extended with Venues

JMatter supports both inheritance-based polymorphism (as shown in this exam-ple) and interface-based polymorphism.

6.7 Interface-Based Polymorphism

We are taught that interface-based modeling is preferred over models that do notemploy interfaces. I concur. I’d like to demonstrate how to do interface-basedmodeling in JMatter.

As an illustration, let’s extend our Sympster application further. Right now, wecan define a symposium, speakers, their talks, and we can schedule sessions. Asession is defined as a talk given at a specific date and time, and with a specificduration, at a specific location.

Page 93: jmatter

6.7. INTERFACE-BASED POLYMORPHISM 83

I’d like to broaden the definition of a session to include events other than speak-ers’ presentations. What about BOF’s (Birds of a Feature session) for example?Or maybe a panel discussion including a number of participants. At NFJS sym-posia, we actually hold informal BOFs with 2-3 participants where we discuss aparticular topic.

Let’s walk through the code.

The first thing I do is define the interface ‘Event‘:

public interface Event extends ComplexEObject

{

public StringEO getTitle();

}

We’re basically going to require that each event provide a title. Talk already doesand BOFs will too. I still want to define this interface as it serves as a mechanismfor qualifying event types.

Next, let’s go ahead and define 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, let’s retrofit 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;

Page 94: jmatter

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 implementEvent.

Finally, remaining is broadening Session’s definition. Rather than define an asso-ciation to a Talk, we’ll revise that to be be an association to an Event. I won’t showyou all the edits. Here’s 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 that’s it. Now let’s take a look at how these changes manifest themselves inour application:

Figure 6.7: Polymorphic Queries: Listing Events

Page 95: jmatter

6.7. INTERFACE-BASED POLYMORPHISM 85

JMatter models the polymorphic association using Hibernate’s implicit polymor-phism 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.

Page 96: jmatter

86 CHAPTER 6. A CONFERENCE MANAGER

Figure 6.9: Events Calendar

We see two events on this calendar. The first is a talk on JMatter, and the secondis a BOF on Programming. :-)

6.8 Summary

I hope you enjoyed this chapter. We didn’t have to work too hard and yet wedeveloped a fully-functional conference manager.

In summary, new features of JMatter covered in this chapter include:

1. type color coding,

2. using an image field as the basis for an instance’s icon,

3. calendaring, and

4. polymorphism, using either inheritance or interface-based modeling

Let’s do our due diligence once again and get a feel for the amount of leveragewe derived from JMatter in this application:

Page 97: jmatter

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 you’re not convinced by now of the implications of this new mode ofdeveloping software, this might be a good time to pick up another book :-).

In the next chapter we’re finally going to take a look at the Issue Manager demoapplication, the one referenced in the introduction. We’ll be focusing on JMatter’ssupport for objects with lifecycles.

Page 98: jmatter

88 CHAPTER 6. A CONFERENCE MANAGER

Page 99: jmatter

Chapter 7

Issue Manager

In this chapter, we’re going to discuss JMatter’s support for business objects withlifecycles. We’re going to write an Issue Manager, a familiar application for soft-ware developers who use such systems to help manage the development of soft-ware. 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 isthat they have a life cycle. An Issue is created and assigned to a developer. Thedeveloper accepts the issue and begins working on a fix. After resolving the issue,the person who opened the issue verifies that the resolution is indeed satisfactory,and proceeds to close the issue. If the issue is not resolved to satisfaction, the issuecan be reopened.

It’s 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 notesto 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 theirstate. For example, one cannot attempt to accept an issue if it’s already been closed.We can identify the various states for an Issue, and define its lifecycle with the aidof state diagrams, transition tables, etc.. Software developers will typically modelsuch objects using the State Design Pattern1.

I have decided to model an Issue with five states:1The State Pattern is documented by the Gang of Four in their book, Design Patterns

89

Page 100: jmatter

90 CHAPTER 7. ISSUE MANAGER

1. New

2. Assigned

3. Accepted

4. Fixed

5. Closed

In a normal flow, an issue moves sequentially through these states. An issue iscreated (New state), then assigned to a developer (Assigned state), and accepted bythe developer (Accepted state). The person who opened the issue has the option ofrejecting the fix (in which case its state reverts to Accepted) or approving it, movingIssue 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 theContext object (in this case, Issue) when in that state. Also, many texts encouragethe design to use static inner classes for improving the performance of the sys-tem. That is, rather than create an instance of each inner class per Issue, a singleinstance of each inner class exists for all issues. The issue that is to be operatedupon is passed in as an argument to that inner class’s methods.

Although there’s no denying the improvement in memory requirements, I per-sonally find this design less than ideal, from an object-oriented point of view. Ifind it akin to removing the implicit this keyword in instances and passing a ref-erence to self with each method.

7.2 Getting Started

We’re about to start building our fourth application. Since we’ve done this to-gether three times already, I’m not going to walk you through the steps of creat-ing a new project and configuring it Please refer to previous chapters for specificinstructions. I named my application IssueMgr.

Ok, we need to model Issue. As a first pass, let’s not worry right away about thevarious states we identified in the previous section. Let’s instead start be definingthe various properties we want an issue to have. Here are the properties I’ve comeup with:

Page 101: jmatter

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 descrip-tion field is defined as a TextEO which causes it to be rendered using a text area,and saved as in the database as a large text type. I’ve decided for a first-pass tokeep severity and priority really simple, as numeric values. The next one: de-pendsOn is interesting and fairly self-explanatory. It will give us the knowledgethat Issue A will not be resolved before the issue it depends on (say Issue B) isresolved, for example.

The next field, notes, will allow us to tack on notes to an issue (as many notes aswe want in fact). A Note is yet another predefined type in JMatter. It has a subject,a time stamp, an author, and the note text itself. When creating a note, the authoris automatically assigned to the user who is currently logged in.

The next two fields, openedBy and assignedTo are self-explanatory. The last field isan interesting one. The idea is that I’d like to keep track of the history of an issue:when was it opened, assigned, accepted, fixed, etc.. Furthermore, when an issueis fixed, i want to require the developer to enter both a summary description ofthe fix and a lengthier one. I want to capture that information.

After thinking about this for a little while, I realized that JMatter’s built-in LoggedE-vent type would be a perfect candidate for recording this information. It’s alreadydesigned to hold precisely this type of information. It has a timestamp, a mes-sage, long message, it records the user who performed the action, it can evenrecord what action was performed, and finally, has an association back to the ob-ject upon which the operation was performed. In the context of the issue manager,we’ll be able to navigate from a log entry (with message Issue fixed at 4:30 pm) backto the issue it is associated to.

Ok, it looks like we have a fairly complete list of fields to start with. Of course, it’snot enough to just define these fields, the JMatter conventions must be followed:define accessor methods for aggregate types and both accessors and mutators forassociation types, following the JavaBeans bound property convention.

Page 102: jmatter

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 fieldOrder metadata and the required title() method. Sinceit is customary to refer to issues by some unique numeric ID, I’m exposing the

Page 103: jmatter

7.3. MODELING ISSUES’ LIFECYCLE 93

issue’s ID property in its title. This property is inherited from AbstractComplex-EObject.

We normally do not edit src/persistClasses.st by hand: the @Entity annotation takescare to add Issue to the list automatically. However here we’re using a predefinedentity Note and for it we do need to manually add an entry to our persistClasses.stfile, like so:

..

<value>com.u2d.type.composite.Note</value>

..

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

7.3 Modeling Issues’ Lifecycle

The time has come to model issues’ lifecycle.

There are a number of concerns here. The first is keeping track of the state ofour issue. And more specifically, to ensure that when an issue is persisted to thedatabase, that its state is remembered and properly restored at a later point intime.

A simple way to do this is to define yet another field to hold the name of the state.This field will be persisted to the database just like Issue’s other fields, and can bethe 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 identified five states and they’re not likely to change. JMatter provides amechanism for modeling enumerations by extending the JMatter type ChoiceEO.Here is the implementation of the contract to define the IssueState enumeration:

Page 104: jmatter

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 methodfor status:

public IssueState getStatus() { return _status; }

7.3.1 Defining the State Inner Classes

Below I’ve defined five inner classes, one for each of the states that Issue can bein.

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)

Page 105: jmatter

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 defining commands on these states is the same asthe mechanism used for defining commands in general. The difference is thatJMatter will ensure that these commands are accessible in a valid state. The @Argannotations’ values are a means of specifying the captions used to prompt the enduser for each of the method parameters.

Although we’ve defined 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);

}

Page 106: jmatter

96 CHAPTER 7. ISSUE MANAGER

In addition to instantiation, I’ve also added each state to a map, defined in Issue’ssuperclass. At the moment, this is a requirement of the framework. We haven’tyet specified the starting state, so let’s do that:

public State startState() { return _newState; }

We also need to provide a mechanism for the Issue’s state to be restored after anissue 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 issue’sstatus (which was fetched from the database) as a means to fetch the state objectfrom the state map.

I have not yet showed you the support code for the transitions. In each statewhere a command is defined a transition takes place. A logged event is createdand passed in to the method named transition(). Here’s how I create the loggedevent:

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 first does notrequire a long message, the second is an overloaded version that also sets thelong message. Notice how commands such as Fix, Close and RejectFix specifyarguments. Recall that JMatter “automagically” prompts the end user for thesearguments in the user interface and then feeds them to the commands when in-voking their methods. These values are then passed in to the makeLog() methods.

Finally, here is the implementation of the transition() method:

Page 107: jmatter

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 field, the state transitiontakes place, the status field is updated accordingly (kept in sync with the issue’sstate). The final statement ensures that the updated issue and its association tothe newly created logged event are saved to the database.

7.4 Per-State Icons

Up until now, you’ve been told that for each type of object you define, that JMatterwill look for an image file with a specific naming convention to use to representobjects of that type. This is true, but it’s not the whole story.

Let’s take an example. For the class Issue, we provide Issue32.png and Issue16.png.However, you’re also free to provide additional icons, one for each state: IssueAs-signed32.png, IssueAccepted32.png, etc.. So we see here an extension of the conven-tion. For objects with lifecycles, the icon can be made to further reflect the stateof the object you’re viewing. I have specified custom icons for each of Issue’s fivestates. Here’s (figure 7.1) a screenshot of the icons in my resources/images directory,along with their corresponding file names.

Page 108: jmatter

98 CHAPTER 7. ISSUE MANAGER

Figure 7.1: State-Specific Icon Support

7.5 Additional Metadata

We’ve defined a number of commands, such as Fix(CommandInfo cmdInfo, StringEOfix, TextEO description). We customized the captions for the two arguments fix, anddescription so the end user is clear about what information he or she will have toenter. We did this by annotating the method’s 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.

There’s a second, much more important issue that needs to be addressed though.In the case of our issue manager application, it’s not enough that the command

Page 109: jmatter

7.6. A FEW LOOSE ENDS 99

accept be only accessible in Assigned state. Only the developer who has been as-signed the particular issue should be allowed to accept the issue. The same ap-plies to the fix command. For rejectFix and close, the same idea applies: only theuser 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. Acommand’s owner is the only user who will be allowed to invoke it. JMatter willnot even display the command’s views (a button or a menu item) to any otheruser. Here’s 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 you’ll agree this is fairly terse, yet clear and legible code. The last line, forexample, interprets to “the owner for the command named Close (in Fixed state) isthe value of the issue’s openedBy field. In other words, whoever opened the issueis the one authorized to close it.

7.6 A Few Loose Ends

7.6.1 Default Assigned-To Developer

It sure would be nice if each time I created a new issue, a certain developer wouldbe the default user assigned to the issue. One way to do this is to specify thedefault in the file resources/model-metadata.properties, like this:

#

Issue.assignedTo.default=from User as user where user.username=’eitan’

We’ve already used this file to specify field metadata such as whether and whichfields are required. Here we’re specifying a default. We can either hard-code it, orspecify any valid hql (hibernate query language) that will return an instance of avalid type.

Page 110: jmatter

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 definition thecurrently logged in user. How do we programmatically specify that this shouldautomatically happen? Here is one way to do this:

public void onBeforeCreate()

{

super.onBeforeCreate();

setOpenedBy(currentUser());

}

This method overrides a superclass method, one that is notified prior to the cre-ation of an object. It turns out that persistent objects (such as Issue) are not the onlyones that can listen to various object persistence lifecycle events. JMatter providesa generic notification mechanism that any object can take advantage of. Each typeof event is defined by a string constant, such as DELETE, SAVE, BEFORECREATE,CREATE. You’ll see an example use of this mechanism shortly. It’s also worth not-ing that besides object persistence events, JMatter provides hooks for applicationevents 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 anissue transition to assigned state? The transition should take place when a user isassociated to the assignedTo property of Issue.

We need to be careful here. The setter method is called not only when an associ-ation is made but also when the object is restored from the persistence store (thedatabase). To distinguish between these two contexts, JMatter allows the defini-tion of an additional method, the associate method. It works like this: if both asetter and an associator are defined, JMatter will make sure to call the associatoronly when associating (calling only the setter when restoring the property fromdb).

Here’s the implementation:

public void associateAssignedTo(User user)

{

setAssignedTo(user);

if (_assignedTo != null && !_assignedTo.isEmpty())

{

if (isEditableState())

Page 111: jmatter

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 specific issue. Acall to the transition() method has the side effect of saving everything and puttingthe object in read state. We want to delay the call to transition if the associationis made while the issue is in an editable state (before it has been saved, while it’sbeing edited).

I’m resorting to using JMatter’s application event notification mechanism. If theassociation is made in read state, I simply transition. Otherwise, I delay transi-tioning until after the editing is complete.

7.7 Issue Categories

Our implementation of Issue is now complete. Let’s add one last feature. It mightbe helpful to define various categories of issues and classify issues according tothese categories.

The first thing we do is define 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(); }

}

Page 112: jmatter

102 CHAPTER 7. ISSUE MANAGER

Nothing fancy here. An issue category is defined to have a single field: a name.

Rather than define a to-many relationship to issue, I’m going to add a commandthat will fetch the category’s 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);

}

I’m not entirely satisfied with the implementation. I’d like to be able to use plainold hql or the hibernate API to define this query. The above uses JMatter’s ownAPI for defining queries, which basically says: fetch all issues where the categoryequals “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 fieldOrder metafield:

public static String[] fieldOrder = {"status", "title", "description",

"notes", "openedBy", "assignedTo", "history", "severity",

"priority", "category"};

That’s it for the coding. Make sure to update the schema and let’s run the appli-cation.

Page 113: jmatter

7.8. THE APPLICATION 103

7.8 The Application

Just because we finished coding does not mean that we’re done configuring ourapplication. For example, it might be useful to define a few standard queries suchas List Outstanding Issues and List Closed Issues that pre-filters the listing (usingJMatter’s Smart List mechanism).

Figure 7.2 below shows the issue manager in action. I’m listing all issues to illus-trate how the issue’s icon reflects its state (the ones with a lock are closed issues,the ones with the pencil are accepted, and supposedly, being worked on). I’malso showing two smart lists that I’ve created and that I often use to check outoutstanding issues.

Figure 7.2: The Issue Manager

I also often view issues in tabular view, which allows me to sort issues by priorityor severity (sorting is invoked by clicking on the table column header).

Page 114: jmatter

104 CHAPTER 7. ISSUE MANAGER

7.9 Summary

As in previous chapters, allow me to show you the stats for this application, interms 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 inJMatter is pretty strong. Its implementation is a natural extension of the conven-tions already established for simpler business objects. Nevertheless, I believe theimplementation can be streamlined further and place even less requirements onthe developer. For example the requirement to add the various states to a statemap could be done by the framework.

In summary, support for business objects lifecycle is a necessary component ofsupporting the development of business applications in general. Many businessobjects naturally embody lifecycles, including orders (new, confirmed, fulfilled,etc..), visits (scheduled, canceled, confirmed, ongoing, archived), etc..

We have now covered four distinct applications: a contact manager, the MyTunesapplication, the Sympster conference manager, and finally our issue manager in avery short time. JMatter also comes with a movie library application, that, amongother things, illustrates many-to-many relationships, as well as two other demon-stration applications that illustrate how to integrate custom views into your ap-plication (the topic of chapter 14 on page 171).

Let’s now turn our attention to part III on the facing page, which covers the JMat-ter framework in detail.

Page 115: jmatter

Part III

Framework Reference

105

Page 116: jmatter
Page 117: jmatter

Chapter 8

Dichotomy of a Model Object

Let’s 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 definition consists of data and behaviour,implemented as fields and commands (or methods), known as the type’smembers.

2. JMatter relies heavily on conventions for the purpose of inferring informa-tion about a type.

Here are some of the conventions:

1. Our class must extend the base type AbstractComplexEObject. This base classis a partial implementation of the ComplexEObject interface.

107

Page 118: jmatter

108 CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

2. We have a field, the person’s name, defined via a private variable but in-ferred 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(), whichin a sense defines instances’ labels, or captions in the application’s user in-terface. The Title class exists simply to facilitate the task of constructing atitle when we wish those titles to be constructed by concatenating variousfield values.

5. We use the @Entity annotation to mark the type as one that we want topersist to database.

6. We mark a method with the @Cmd annotation to indicate that we wish toexpose 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 impliedto be a message returned by the action that JMatter will display to the user.

2. Commands can accept arguments (I’ll have more to say about that later).

3. Type commands can be defined by marking the method as static.

4. JMatter infers the type names and captions, member names and captionsfrom our choice of class name, getter method name, and command methodname. This is done via run-time reflection in Java.

The total sum of conventions and features supported by JMatter is much lengthierthan 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 themodel completely, using object-oriented techniques: accounting for both data andbehaviour.

You can think of the complete application as having a model-view-controller de-sign. In the case of JMatter, the view and controller are generic, and already im-plemented. This frees you to focus on the model.

From a persistence perspective, all types inherit three fields or pseudo fields:

Page 119: jmatter

8.2. FIELDS 109

Field Descriptionid Serves as surrogate primary key. You do not need to define a

primary key for your types. The framework does this for you.version This field is used by the underlying hibernate persistence

framework to keep track of whether two objects are being editedat the same time, used for optimistic locking.

createdOn A read-only field that records the date and time that an object iscreated. When displaying a view of an object in form view, thevalue of this field is displayed at the bottom, in the view’s statusbar.

8.2 Fields

JMatter makes a distinction between atomic fields and complex fields, whereatomic fields have a single value, while complex fields are in a sense composed ofatomic and other fields.

There’s a second distinction that has to do with ownership of a field. Compos-ite, or aggregate fields are ones that are wholly owned by their parent object. Allatomic fields are aggregates. Associations on the other hand are fields that rep-resent relationships to other objects, or entities; these relationships can be set orsevered. Field ownership has implications on specific operations. For example, ifthe parent object is deleted, associations are only severed, but the associated ob-ject 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 fields.

It turns out that JMatter’s domain design happens to match the rules set forthby Eric Evans in his book Domain Driven Design [5]. If you’re familiar with thiswork, then the notions of entities, value objects, and aggregates and their interre-lationships should already by familiar to you.

We also need to discuss how to model fields with different cardinalities. There areof course to-one relationships, and * or to-many relationships.

8.2.1 Atomic Fields

JMatter defines and provides implementations for a variety of types of atomicfields. Developers are required to use the framework’s definitions. That is, astring-based field must be defined as a com.u2d.type.atomic.StringEO and not ajava.lang.String. Internally the frameworks’ atomic type implementations oftenwrap or encapsulate the more primitive type.

The framework’s atomic types are modeled as value objects. JMatter defines aninterface for Atomics, com.u2d.model.AtomicEObject.

Page 120: jmatter

110 CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

The framework requires that all aggregate type fields be implemented as finalfields. Consequently accessor methods for these fields comprise of only a gettermethod. The definitions 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 object’s name field? All valueobjects have a method:

public void setValue(EObject value);

to provide a means for setting the value. That is, the reference to the objectnever changes, only its contained value. StringEO has an additional conveniencemethod:

public void setValue(String value);

Other atomic types have similar conveniences. IntEO for example (which repre-sents an integer) has this convenience method:

public void setValue(int value);

These types also have a corresponding way of getting the represented value as asimple 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 ChangeNotifier’s, which means that they publish(or fire, in pub/sub speak) change events that you can listen to. This can be usefulfor building lotus123-style dependencies between objects (when A changes, up-date B). This is also useful internally to keep the user interface in sync with itsunderlying model.

Page 121: jmatter

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 defined in the package com.u2d.type.atom. Writing your own additionaltypes is quite straightforward. The existing implementations represent a wealthof examples that one can draw from.

8.2.2 Composite Fields

There isn’t much to say about composite (or aggregates) fields that I haven’t al-ready. Again, what makes a field an aggregate in the framework is the fact that itsmember is defined as a value object: define a final field, and only a getter method.Here’s 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 fields. For example, to copy one con-tact’s 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 predefines a number non-atomic, or higher-level types. They’rereside in the package com.u2d.type.composite. Here’s a list of type names:

Name, USAddress, ContactMethod, Contact, BusinessContact,

EmailMessage, Folder, Note, Person, Business, LoggedEvent

Page 122: jmatter

112 CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

8.2.2.2 Composite Indexed Field

JMatter provides a means for modeling a composite field with a to-many (*) car-dinality. A prototypical example is the relationship between an Order and its listof OrderItems.

JMatter provides the type com.u2d.list.CompositeList for the task. Here’s an exam-ple field definition 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; }

Here’s the constructor method signature:

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

The first argument is the child type (Order Items). The second is a reference tothe parent object (this). Finally, there’s a convention where CompositeList canautomatically give child objects a reference to its containing, parent object. This isdone by writing a setter method in the child type definition:

private Order _order;

public void setOrder(Order order) { _order = order; }

and passing the name of the field (order) as an argument to the CompositeListconstructor.

Notice that you also must (at the present time) provide metadata for the frame-work to introspect the list type statically. The framework looks for a public staticvariable name of type Class of the form <fieldname>Type.

In the user interface, JMatter provides an tabular component that provides meansfor adding child items, deleting them, editing them, etc..

8.2.3 Associations

8.2.3.1 To-One Associations

A to-one association definition is essentially the implementation of a JavaBeansbound property. Let’s look at an example, Song.artist:

Page 123: jmatter

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);

}

That’s about it.

8.2.3.2 To-Many Associations

For an indexed association, use the type com.u2d.list.RelationalList. Here’s an ex-ample, 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. define a final member variable, talks

2. provide metadata for the framework to statically introspect the type to de-termine 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. Takethe example of a speaker and his or her list of presentations. The presentationwould have an association to its speaker, and the speaker may have a to-manyassociation called presentations.

You can define both associations in the manner described in the two previoussubsections:

Page 124: jmatter

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 otherside of the relationship. The implementation at the moment is not too elegant butis nevertheless simple enough. In class Talk, add:

public static String speakerInverseFieldName = "talks";

And in Speaker:

public static String talksInverseFieldName = "speaker";

Basically, the field name is of the form: <fieldname>InverseFieldName. Speaker hasa field named talks, so the variable name is talksInverseFieldName. Its value is thename of the inverse field: the talk’s speaker’s field name is speaker. Both sidesmust define the bit of metadata.

8.2.4 Choice Types

The notion of a Choice in JMatter is somewhat analogous to what programmerscall enumerations. JMatter provides two flavors of choices. The first and morebasic flavor is the ChoiceEO and is implemented as an atomic object.

This flavor is suitable for enumerations (or small lists) that are static; i.e. they donot change. The framework itself implements a couple of types as ChoiceEO’s.

Page 125: jmatter

8.2. FIELDS 115

As part of my work on providing access control to information, I define a Field-RestrictionType (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 define the various states for an Is-sue. Basically the way to define such enumerations is by extending the base typeChoiceEO and implementing the method entries(). The editors for these types areSwing JComboBoxes (pick lists).

The second flavor is modeled as a ComplexEObject. The data is not hard-codedand the type is defined as an entity in the database. These lists are more versatilein that one can define new entries, new choices as a system evolves. We devel-oped an example implementation in the MyTunes tutorial chapter, to define songgenres.

The framework provides full create/edit/delete capabilities for these types. Theyare defined by extending the type AbstractChoiceEO. The framework itself definesfour such types of choices: US States, Sex, Marrital Status, Contact Method (in-stances of these four types are pre-populated from the xml files located in jmat-ter/resources/data).

Both flavors adhere to the Choice interface:

public interface Choice

{

public String code();

public String caption();

}

Page 126: jmatter

116 CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

8.3 Commands

Let’s 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 defining any method. The maindifferences are:

1. Marking the method with the @Cmd annotation exposes it to the UI

2. The first argument to the method is some context information about thecommand invocation (at the moment you don’t really need to concern your-self with the CommandInfo type; I am discovering that this information israrely needed and am beginning to question passing this argument).

Making the method static has the effect of defining the command on the typeinstead of its instances. You can see the command action exposed as a contextmenu 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 displayedto the user in a sort of self-dismissing dialog box.

If the method returns a type that is viewable (another entity), the frameworkmakes sure to display a view of the returned instance after the command is in-voked.

If the method accepts arguments, then the framework will first prompt the userfor these arguments (via an input form) before proceeding to invoke the com-mand. Take for example, this command, defined 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 buttonon an instance of a user), he or she will first be prompted to enter a password,

Page 127: jmatter

8.3. COMMANDS 117

using the caption New Password. The framework does it all. Once the password isentered, the framework proceeds to invoke the command (in the proper thread).In this case, the password editor takes care to properly validate the passwordbefore 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 userinterface. Also note the subtlety of adding the static modifier to define a commandon a different object: the instance’s type, rather than the instance itself.

So we have two types of commands: instance commands and type commands. Inthe JMatter framework, the Java class ComplexType represents or models a type,in the same way that the class java.lang.Class is an instance’s type. You will alsofind @Cmd definitions in ComplexType. So the JMatter framework uses many ofthe concepts that it defines for application development internally, to build itself.Also this should make you realize that a type command on a given object is noth-ing more than an instance command on its type instance.

Atomic types can have their own commands too. They can be invoked from theUI by right-clicking on the rendered value. For example, StringEO has the com-mand Capitalize(). We encourage you to define additional commands that mightbe useful to the plethora of atomic types that JMatter defines.

8.3.1.1 Type Commands

Aside from marking a method static to designate a command belong to the in-stance’s type, you also have the option of specifying a method signature with anextra parameter, like this:

@Cmd

public static void SayHi(CommandInfo cmdInfo, ComplexType targetType) ...

The last parameter is optional. If specified, then JMatter will make sure and passa reference to the target object (a ComplexType) upon which the command wasinvoked. Even though the method is static, it was invoked in the context of aninstance, which happens to be a type. In some circumstances, the called methodneeds 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: listcommands. List commands can be defined in several ways.

Page 128: jmatter

118 CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

First, if an instance command is given the annotation attribute batchable as shownhere:

@Cmd(batchable=true)

public void Email(CommandInfo cmdInfo) ...

This is an indication that the command can be invoked in batch, so to speak; thatis, given a list of instances (perhaps search results from a query), you will be ableto invoke that command on all the items in the list. The logic basically iteratesover all instances in the list and invokes the command on each instance.

There exists a command Email on JMatter’s type Person, which launches yourdefault email client and opens a compose window with the destination addresspre-filled with the person’s email address information. You can try this from theContactMgr demo application. To invoke it in batch mode, just bring up a list ofcontacts and right-click on the list-view’s title to reveal its context menu.

Invoking the Email command in batch will open multiple compose windows, onefor each recipient on the list.

The additional command: EmailWithSubject, defined 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 client’s composecommand. Note that this command is also marked as batchable. JMatter is smartenough to ask you for the subject line once, irrespective of the number of timesthe command is invoked.

What if we wanted the behavior of the command to be smarter? That is, wewish to write a separate implementation of Email, perhaps named EmailAll, thatopened a single composition window, but that specified multiple addresses (theaddresses of each of the persons on the list) in the To: field.

To do that, define 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, passingin the list reference as an argument to the method. You can now iterate over thelist items to grab all the email addresses, but implement the method such that asingle email message is composed.

Finally, List Commands also allow multiple parameters, here’s an example:

Page 129: jmatter

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 classfor the complete code listing.

List commands are a powerful tool that can significantly increase the usability ofapplications. Their use is highly encouraged. Without them, end users may beforced to perform the same operation repetitively to effect a business change intheir model.

8.4 Metadata

8.4.1 Overriding Plural Name

JMatter applications are all about managing information. Information stored inobjects and presented in the user interface as objects. Every model object of coursehas a distinct name (or label) and icon, and a distinct set of fields and commands.The user interface displays a classbar, which in a sense is a starting point for per-forming various operations, listing information of a given type, searching for in-formation, creating a new instance, etc..

The classbar displays the various types in iconized form: with a caption and anicon. Each type’s caption is derived from its class name. It’s actually the pluralform of the class name. For a Boat, the plural form is simply Boats. For a Personobject you might wish the caption to say People.

To override the default behaviour for deriving the plural for a type, define a staticmethod 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 classname. There may be circumstances where you might want to override the naturalname for a type. This is done in a manner similar to the above, by defining a staticmethod named naturalName().

Page 130: jmatter

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 arepainted using a gradient background color. By defining this field, for example:

public static Color colorCode = new Color(0x4169aa);

The framework will use the specified color as the starting color for the gradient.Additionally, list entries are painted such that row background colors alternatefrom white to another color. The type’s color code, if specified, is used for thatother color. Both these styling mechanisms make it easier to distinguish types inthe 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 configuration file, the nameof the icon is derived from the type name. JMatter supports .png, .gif, and .jpgformats. Two icons sizes must be supplied: a 16x16 pixel icon (used in listings),and a larger 32x32 pixel icon. The files must be placed in the resources/imagesfolder of your project. Your project’s build file automaticaly copies these resourcesto the classpath at images/<imgresourcename>.

For the User class, the files should be named User16.png and User32.png respec-tively (the file suffix may vary of course).

List views of a uniform type are also decorated with an icon. You can distinguishicons used for lists of a given type from icons used for individual instances: dropin Users16.png and Users32.png into the images folder. Note how the file name usesthe pluralized form of the type.

JMatter also leverages and honors the type’s inheritance hierarchy. For example,if you define a specific subclass of User.java, say UberUser.java, without providinga set of icons for the subtype, JMatter will fall back the super type’s icon.

For types that are stateful, you can also distinguish between instances of differentstates 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 caneasily spot the locked user. The IssueManager demo application also leveragesthis feature (see chapter 7).

8.4.4.1 Per-Instance Icons

There are situations where one of the fields of a model object contains a picturerepresenting the instance in question. Here are examples:

Page 131: jmatter

8.4. METADATA 121

1. An album’s cover

2. A person’s photo

3. A photo of a car part

So far, all instances of a given type use the same icon. Why not use a differenticon 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 implemen-tations in your classes. JMatter provides a utility class: PhotoIconAssistant, thattakes the work out of properly scaling the photo to the right size for an icon, onyour behalf. Here’s 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 type’s fields are laid out on a form, use the fiel-dOrder static member.

Example:

public static String[] fieldOrder = {"name", "contact"};

Whatever field names you don’t reference in fieldOrder will still appear on theform, after the listed ones, in no guaranteed order.

This piece of metadata underscores an important aspect of the framework whichyou must understand: the notion that fields and commands can be referenced byname, as a string. What are the rules that govern the derivation of a field’s name?

Field names are derived from their accessor method name. Here are a couple ofsimple examples:

Page 132: jmatter

122 CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

getName() -> "name"

getFirstName() -> "firstName"

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

8.4.6 Command Order

In a manner analogous to the way fields are ordered on a form, we can control theorder in which a type’s commands are displayed with the commandOrder staticfield.

The ContactMgr demo application’s PersonContact type has two static methodsReport and NewPersonWizard. Their relative order can be specified as follows:

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

What’s interesting here is that these two commands are static methods: they’retype commands. The commandOrder field controls both static commands and in-stance commands. Each list is mutually exclusive and so can be (and is) specifiedwith a single commandOrder string array field.

8.4.7 Flatten Into Parent

Types can have different types of member fields. Some are simple, atomic, fieldssuch as a string, a number, a percentage perhaps. These fields are not entities.From a persistence perspective, they don’t get their own tables. A type may alsobear members which are not atomic, but nevertheless aggregates of their contain-ing types. Say for example that I define a Person type with the field name of typeis Name. The type Name in turn has two fields: first, and last, both of which areatomic fields. Person.name on the other hand is not atomic. The hierarchical rela-tionship 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 JMatter’s Swing-based view mechanism can expand or collapse to show the name field’s children.An instance is shown in expanded mode below.

Page 133: jmatter

8.4. METADATA 123

Figure 8.1: Hierarchical Display of Aggregates

Sometimes it’s more practical to display all descendant fields as a single flattenedform, rather than require users to expand and collapse sub-nodes in order to per-form data entry. That’s what the flattenIntoParent metadata bit is for. In our ex-ample, to communicate to the framework that we wish to flatten the name field’schild fields (first 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 displayedto users is the tabViews metabit. You use it in a manner similar to many otherpieces of metadata: by specifying a list of member fields:

public static String[] tabViews = {"contact"};

The above example may be used, say, in a Person object to specify that the person’scontact information (an aggregate field) should be displayed in a separate tab.

In the Swing-based user interface, the keyboard shortcut Alt-<index> can be usedto 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 define one field that is most commonly used tosearch for instances of a given type. It may be name for a Person object, or title fora Presentation object. Here is how to specify it:

Page 134: jmatter

124 CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

public static String defaultSearchPath = "name";

The value is specified as a string but may actually be a field path, such as name.first.

This value in turn is used in the user interface to assist with quick searches forperforming associations or defaulting the search field when performing a searchoperation. It’s quite useful. At the moment, this feature is supported only for text-based fields where the inequality defaults to TextStarts (i.e. that we’re looking forinstances whose default search field value starts with the value entered by theuser).

8.4.10 Unique Fields

JMatter automatically takes care to define a surrogate primary key for your modelclasses. Often there may exist additional fields, natural keys, that must remainunique. Optionally defining a static field “identities” will ensure that JMatter con-structs the database schema properly (marking the field as unique in the database,which will also create an index on the table). In the user interface, such fields can-not be revised after an object has been created for the first 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” staticfield (in the same manner fieldOrder is specified). This is useful when workingwith derived (or calculated) fields, which we discuss next.

Example:

public static String[] readOnly = {"created"};

8.4.12 Calculated Fields

We sometimes use fields whose values are derived from other information. Theinformation 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 thedatabase.

Define such fields in the usual way. JMatter provides a way to mark the field as“not persisted”, and a way to hook into the object’s life cycle in order to updatethe field value, as illustrated in the following example.

Page 135: jmatter

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 fields need to be recalculated as a function of their inputs, it’s alsouseful to attach change listeners on the input values. Here’s 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 Per-Field Metadata

8.5.1 @Fld Annotation

We can augment a field’s getter method with the @Fld annotation. Here is a listof the parameters this annotation accepts, along with a description (all of theseparameters are optional).

Page 136: jmatter

126 CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

ParameterName

Type Description

mnemonic char What keyboard mnemonic to attach to the field inquestion. Useful for form entry, to directly set thefocus on a specific field

label String A way to override the caption used to display a fieldin a form

description String The field’s description. Used as the contents of atooltip on the field.

colname String A means to override the name of the databasecolumn corresponding to this field. By default, thecolumn name is automatically derived from the fieldname.

colsize int Controls the size of the field’s underlying databasecolumn. By default, many string-type fields are set asvarchar(255). This attribute provides a means tocontrol the column size at a finer level.

displaysize int Controls the size of the corresponding text field usedfor doing data entry on the field.

format String Applies only to TimeEO and DateEO type fields.Accepts a SimpleDateFormat string to control theformat of times and dates for both parsing andrendering. e.g. @Fld(format=’m:ss’) might be usefulon a TimeEO field for displaying song durations.

persist boolean Whether the field should be persisted at all (see thediscussion on Calculated Fields)

hidden boolean Use to hide certain fields from the user interface

Although the framework provides a means for overriding the label for a field, wegenerally discourage this practice. We believe there is great value in maintaining acorrespondence between field labels in the user interface and their correspondingfield names in our object models.

If you wish to revise the date and time format throughout the application (i.e. notfor a specific field), you can specify the format in the model-metadata.properties file(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 per-spective, the hibernate mapping file will use an ordered list (an additional

Page 137: jmatter

8.6. PER-COMMAND METADATA 127

column in the database table specified the list item order). From a UI per-spective, in edit mode, the list can be reordered via drag and drop.

ownsChildren=true If specified, the to-many relationship is modeled in sucha way that when an item is removed from the list, the child item will bedeleted from the database (hibernate cascade=delete-orphan). Semanticallythe list items cannot be freely associated with an entity. In the user interface,the “Browse” and “Find” association commands that usually adorn the listview are not accessible.

8.6 Per-Command Metadata

Commands must be marked with the @Cmd in order to be exposed to the userinterface. There’s nothing special about these methods and they can be invokedprogrammatically as well. When these commands are invoked from the user in-terface, 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 onthe event dispatch thread. The framework also makes sure to display a waitingcursor while the operation is invoked.

8.6.1 @Cmd Metatada

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

Page 138: jmatter

128 CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

ParameterName

Type Description

mnemonic char What keyboard mnemonic to use to invoke thecommand

label String Use to override command’s caption in the userinterface

description String Used as a tooltip to the command’s correspondingview (usually a button)

sensitive boolean Specify whether this is a sensitive command (e.g.Delete) where it would be beneficial for the ui toprovide a mechanism to prevent against inadvertentinvocation of the command. This is done in theSwing view mechanism by disabling the command’sbutton. A small lock on the button can be clicked onto unlock (enable) the action.

shortcut String Applies only to type commands (commands markedstatic). Specify a keyboard shortcut (an accelerator).Example: "control Z"

batchable boolean Whether the command can be invoked in list context(composed across a number of instances)

iconref String Decorate the command view (button or menu item)with an icon. For example, the Edit command isdefined with iconref="pencil"; make sure to place acopy of pencil32.png and pencil16.png in the imageresources folder.

Note: although the framework provides ways of overriding field and commandlabels, we highly discourage this practice. Having a one-to-one correspondencebetween the action’s label and its corresponding method name significantly im-proves the maintainability of your application.

8.6.2 @Arg Metadata

In addition, method arguments can be optionally marked with the @Arg annota-tion. This annotation accepts a single value, which is used as the caption on theform drawn to accept input to the method, as this example illustrates:

@Cmd(mnemonic=’p’)

public String ChangePassword(CommandInfo cmdInfo,

@Arg("New Password") Password password);

Page 139: jmatter

8.7. PERSISTENCE LIFECYCLE AND APPEVENTS 129

8.6.3 The model-metadata.properties file

By default all child projects have a file that can be customized to provide modelmetadata: resources/model-metadata.properties. Here are the default contents of thisfile:

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 file is discussed in the next chapter from the perspetive of valida-tion, not all aspects of this file pertain to validation.

First, we see that we can use a sort of field path notation to reference a field, suchas User.role, or perhaps Person.name.first.

We can mark fields as required by setting the field property value, appending the.required suffix, to true. We can also specify a field’s default value. Above we seethat we can even specify the default value in terms of a hibernate (hql) query. Wecan also provide a hard-coded value, say Person.salutation.default=Mr.

For choice-type fields, we can specify the code for the choice and if a databaselookup 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 timeformat, which previously was hard-coded to US norms. The format is specifiedusing Java’s 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();

}

Page 140: jmatter

130 CHAPTER 8. DICHOTOMY OF A MODEL OBJECT

The persistence mechanism implementation calls these methods at the appropri-ate times: when an object is loaded from the persistence store, onLoad() will auto-matically be called, for example.

It is permissible to override these methods, but be sure to first call the superclass’simplementation. 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 recalculatinga derived field. The framework itself uses onBeforeCreate() to set the value of theread-only field createdOn:

1 public void onBeforeCreate()

2 {

3 _createdOn.setValue(new Date());

4 fireAppEventNotification(BEFORECREATE, this);

5 }

This bring up another aspect of the framework that might be useful to knowabout: AppEvent’s.

The JMatter framework contains an implementation of the Observer pattern (akapublish/subscribe) that is used internally for communicating various events be-tween various parts of the application. For example, the framework defines LO-GIN and LOGOUT events. When a user logs in, this event is published and allinterested listeners are notified. The framework’s class AppSession is an AppEvent-Notifier in that it notifies listeners of login-related events.

AbstractComplexEObjects do a similar thing. By virtue of being persistor listeners,they are notified of persistence lifecycle changes. These objects use the AppEventmechanism to also notify any interested listeners of these events. That explainsline 4 in the above code sample.

To the extent that you have objects in your application that need to be informedof such events, these objects may configure themselves as listeners on whatevermodel objects they’re interested in.

In fact, we saw an example in the IssueMgr sample application where we wantedto delay transitioning to another state until after the object was created.

Page 141: jmatter

Chapter 9

Validation

There are a number of facets to validation.

Let’s begin by describing one aspect of the GUI. In the user interface, when anobject is displayed, it can be edited and saved (updated). The user interface codethat lays out the form conveniently inserts a number of panels called validationpanels. These panels are normally empty and thus not apparent in the user inter-face.

For an object with three atomic fields, say a Speaker with a name (StringEO), atitle (StringEO), and a biography (TextEO), four validation panels will be setup:one for each field, and one for the instance.

Each atomic type asserts its own validation requirements. Let’s take a look atUSZipCode 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

Page 142: jmatter

132 CHAPTER 9. VALIDATION

Here we see that USZipCode implements the validate() method, which the frame-work will invoke at the proper time. The return value, an int, specifies the numberof "errors" encountered. So a return value of 0 implies that validation passed.

There’s a publish/subscribe pattern here, where the model object does not have areference to its corresponding view (or editor) object. Yet, somehow the UI mustdisplay the validation error message. So the model object publishes the message*Invalid zip code...* when a validation error is encountered. The validation panelthat corresponds to a field of this type in the user interface is a listener, and re-ceives the messages, and properly displays the error:

Figure 9.1: Zip Code Validation

The way you should view this form is that each field has its own validation panelembedded 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 field.

The method validate() will be called on atomic objects when a user tabs out of theeditor (when the field loses focus) and again when the user attempts to save theobject.

So validation on atomic types such as such as USZipCode, SSN, and USPhone isimplemented in this way.

Page 143: jmatter

133

Some validation logic is really more an artifact of how the atomic type’s editorchose to allow you to enter the information, and so is implemented directly onthe editor. Let’s take a look at PasswordEditor’s bind() method, which is called bythe 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 fields. The entered value must match eachtime. Also there’s a check to ensure that the specified password meets certaincriteria, such as a minimum length, or exceeding a certain minimum passwordstrength, based on a specific algorithm. Again, we see here how the editor, throughits reference to the model object, fire a validation signal, causing the proper vali-dation error message to display.

In addition, baked into the framework is a simple mechanism for marking fieldsas required. The framework will automatically check that required fields leftempty will veto the ability to save an object, and will also display a proper er-ror message.

The way to mark required fields in JMatter is to specify them in the properties filemodel-metadata.properties. Here’s a sample file, taken from an application havingto do with aircraft that I recently implemented:

Airport.airportID.required=true

Airport.name.required=true

Airport.lat.required=true

Airport.lon.required=true

Page 144: jmatter

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 file is also used to specify default values for fields. Notehow a default value is specified for an association by actually looking it up in thedatabase. The value specified is valid hql (hibernate query language). Let’s getback to discussing validation.

Any type you define in your object model can define its own validation as well,again, simply by implementing validate(). Here’s how it was implemented for thetype "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;

}

Page 145: jmatter

135

So there’s a simple business rule in this case that a trip segment’s distance cannotexceed the specified aircraft’s range for the specified number of passengers.

So here you have it, in a nutshell, an overview of validation in JMatter, how toimplement it in your applications, and how things work under the hood.

Page 146: jmatter

136 CHAPTER 9. VALIDATION

Page 147: jmatter

Chapter 10

Authentication &Authorization

JMatter comes built-in with authentication and authorization services.

When launching a JMatter application for the first time, the framework will createtwo roles (administrative and default) and two corresponding users: admin (withadmin privileges), and ’johndoe’ with default privileges, as shown in the figure38.

Figure 10.1: Initial Users and Roles

The framework provides two model objects: User.java and Role.java, that are con-

137

Page 148: jmatter

138 CHAPTER 10. AUTHENTICATION & AUTHORIZATION

structed according to JMatter’s own conventions for model objects. The iconsused for these types follow the same convention: you will find in the path jmat-ter/resources/images the corresponding icons used by the framework. In the case ofUser, you will find three variants: an icon for a single user, a plural version, and astate-specific icon for locked users (UserLocked32.png).

Users and Roles are modeled in a bidirectional one-to-many association. By de-fault, 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 isstored in the database.

Upon application launch, the application is in logged out state, and a login dialogis presented. Three invalid login attempts by default will cause the user accountin question to lock, requiring an administrator to reset the user’s password. Pass-word resetting is implemented as a JMatter Command (@Cmd) and so is accessibledirectly from the user interface (assuming you have the proper permission).

Upon successful login, the user’s classbar is fetched from database (upon initiallogin, the classbar is defined from the template file class-list.json) and presented inthe 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 necessaryto manage authentication-related information.

10.1 Autologin

In some situations, one might be interested in developing a application that doesnot care for or require authentication. For such cases, JMatter can be configured toautomatically log in as a specific user upon launch, removing the need for usersto manually authenticate.

To configure a JMatter application with autologin, edit the application’s src/applicationContext.xmlas 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 onautologin and to automatically log the user in as the user admin, in this particularcase.

Page 149: jmatter

10.2. AUTHORIZATION 139

10.2 Authorization

Authorization governs who can perform what actions. Authorization in JMatter isspecified 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. Authorizationis specified then by applying a series of restrictions from this initial state. Whena user logs in, the set of restrictions corresponding to the user’s role are fetchedfrom the database and applied to the system. Upon logout, the restrictions arelifted, and reapplied on subsequent login, again according to the new logged inuser’s role’s restrictions.

Restrictions can be applied to both commands and fields. Commands can be dis-abled, 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 defines the command Manage Restric-tions, defined on all types, as shown in figure 39.

Page 150: jmatter

140 CHAPTER 10. AUTHENTICATION & AUTHORIZATION

Figure 10.2: Managing Restrictions

Just like Form Views are dynamically rendered, based on the structure of modelobjects, so is this view. When a new role is created, a new column will appear inthis view. When a new command or field is added, a new row will be added tothe corresponding table.

Here we see that existing administrative commands are already marked restrictedfor the ’default’ role. For example, the ability to create a new role, to edit ordelete roles, is prohibited. Furthermore the ability to define restrictions on roles islikewise prohibited. Finally, the role type’s Open command is prohibited as well,restricting access to inspection of the type’s metadata from the user interface.

10.3 List Filtering

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

Page 151: jmatter

10.3. LIST FILTERING 141

issues assigned to them.

The Hibernate O/R mapping system provides a way to filter data that JMatternow exploits.

The convention is to optionally define a static method on a given type to filter listsof the type in question. For example, we might define this method on Issue:

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

When specifying the filter, you have to be aware that hibernate’s implementationof filters appears to be sql-based and not hql-based. So the filter is used in theconstruction of a sql query. Therefore we reference the type’s assignedTo field byits primary key colum name.

JMatter will now produce the filter declarations directly into the generated hi-bernate mapping files. You should see something like this at the bottom of thegenerated 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 filter for the user’ssession (unless you log in as administrator), and bind the logged in user’s primarykey to the filter parameter (:currentUser).

As further use cases for data filtering surface, this implementation will be broad-ened to accommodate them.

Page 152: jmatter

142 CHAPTER 10. AUTHENTICATION & AUTHORIZATION

Page 153: jmatter

Chapter 11

Search

Search is an indispensable part of business applications today. Database systemsprovide the ability to lookup information via its SQL interface. But software ap-plications 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 thesedays HQL or some other object-based query language) to expose search featuresin their applications.

JMatter integrates search capabilities directly into its user interfaces, in a deepand comprehensive fashion. The good news is that the entire implementationis independent of the domain in question, removing the need for developers toimplement their own search layer.

11.1 Filtering Listings

All list views in JMatter are decorated with a simple query panel. Through thisquery panel, users can dynamically view a custom-filtered set of items, that matcha specific criterion: users with a specific last name, contacts in a specific city, talkson a given topic, sessions given on a specific date, etc..

Users have adhoc search capabilities on every type in their domain. This featureis quite sophisticated. JMatter provides a custom widget based on a tree modelthat comprises an acyclic tree of the sum of valid search paths for a type, from theentity’s root to leaf fields, and can traverse even associations to other fields.

Furthermore, for every atomic type, JMatter provides a set of matching inequali-ties and value editors.

143

Page 154: jmatter

144 CHAPTER 11. SEARCH

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

11.2 The Find Command

The Find command, which is inherent on any type, allows the composing of mul-tiple simple criteria in a conjunction. Disjunction type composite queries are notyet supported.

11.3 Smart Lists

Smart lists denote the ability to save a query performed using the Find com-mand to database. All JMatter applications include model objects provided bythe framework itself. Examples include the entities User, and Role to manage au-thorization. With respect to Search, the Query model object is also part of yourapplication’s domain. This means that end-users can create, read, update, delete,and execute queries to their heart’s content. They can even use the built-in searchcapabilities of JMatter to query queries.

So for example, in the MyTunes sample application, we can create our own playlistsbased on various criteria and name them, in a manner analogous that users havebecome accustomed to with other popular players.

11.4 Search in Associations

Another important feature in JMatter is the ability to search directly within thecontext of an association field, for the purpose of establishing a relation betweentwo 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 our-selves to various modeling techniques such as modeling with abstract classes andinterfaces. We can have an association from one entity to another which is by na-ture polymorphic. We saw two such examples when covering the Sympster demoapplication:

Page 155: jmatter

11.6. CODE HINTS FOR SEARCH 145

1. A symposium’s venue was modeled using a simple abstract base class withthree subclasses (Hotel, Campus, and ConferenceCenter)

2. Sessions were modeled with a relationship to an Event, an interface, imple-mented by both Talk and BOF.

The nature of these relationships carries through to queries. We can request ofour persistence repository for a listing of events, which will transparently fetchboth Talks and BOFs. We can narrow a polymorphic listing by type. One possiblequery is asking for all events of a specific type. All queries are performed object-based. This support is possible because Hibernate is object-based. JMatter takesfull advantage of this.

11.6 Code Hints for Search

There is one specific class-level piece of metadata that developers typically spec-ify to govern a default that is related to searching, as discussed in section 8.4.9:defaultSearchPath.

Here’s an example:

public static String defaultSearchPath = "name";

This piece of metadata is useful to define one field that is most commonly used tosearch for instances of a given type. It may be name for a Person object, or title fora Presentation object.

The value is specified as a string but may actually be a field path, such as name.first.

This value in turn is used in the user interface to assist with quick searches forperforming associations or defaulting the search field when performing a searchoperation. It’s quite useful. At the moment, this feature is supported only for text-based fields where the inequality defaults to TextStarts (i.e. that we’re looking forinstances whose default search field value starts with the value entered by theuser).

Page 156: jmatter

146 CHAPTER 11. SEARCH

Page 157: jmatter

Chapter 12

Wizards, CSV Export, andPDFs

Remember our zero-code contact manager? In this chapter we’re going to actuallyadd code to that application. Many desktop applications today provide thesesoftware assistants, or wizards, to help newbie users through a task.

For example, when we created a contact person in our contact manager, we didnot resort to an assistant. We just right-clicked New on Person and typed away.This works just fine. But maybe we would also like to break the process of enter-ing contact information into these steps:

1. Enter person’s name

2. Enter person’s 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 methodcan complement the other. Let’s see what kind of support JMatter provides foradding assistants to our user interface.

12.1 Subclassing Person

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

147

Page 158: jmatter

148 CHAPTER 12. WIZARDS, CSV EXPORT, AND PDFS

So we need to subclass Person. Let’s create a package com.u2d.contactmgr. In itwe’re 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. We’re basically exposing a command that will return a Wizard ob-ject. JMatter knows what to do with these objects, how to display them, allow theend 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 defines sev-eral types of steps. There are basic (or atomic) steps, conditional steps, and com-posite steps. We need to write a class that is essentially a composite step: one thatdefines the set of steps that makes up our wizard.

Here is the first 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");

Page 159: jmatter

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();

}

}

Let’s analyze this code. We defined a class that extends CompositeStep. Recallthat our wizard is essentially four steps: specify a name, an address, contact info,and finish. So we define variables that will hold each of these three pieces ofinformation.

Next, in the constructor, we set the title for our wizard with the call to the su-per type’s constructor. We proceed to instantiate our three objects and then toconfigure 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 that’s left to do is define three basic steps. I’ve decided to do this usinginner classes, as follows:

class NameStep extends BasicStep

{

public String title() { return "Name Information"; }

public String description() { return "Enter Person’s Name"; }

public JComponent getView()

Page 160: jmatter

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 Person’s Physical Address"; }

public JComponent getView()

{

return new FormView(_address, false, false);

}

}

class ContactStep extends BasicStep

{

public String title() { return "Person’s Contact Information"; }

public String description()

{

return "Please specify person’s contact information";

}

public JComponent getView()

{

return new FormView(_contact, false, false);

}

}

We see here that the implementation is trivial. We provide a title, description, anda view for each of our steps. Nothing to it!

It is worth noting that the FormView class is taken from JMatter’s own Swing-based view mechanism. By reusing this class, we automate the chore of havingto write the panels that make up our wizard’s user interface. Not only do weautomate the construction of each panel, but also the binding of the view to itsmodel object, as well as model object validation. For example, entering a zip codewith an invalid format in the AddressStep will automatically be flagged, giving theuser a chance to revise and fix the data entry (see the screenshots that follow thissection) 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 newcontact person:

class CommitWizardStep extends CommitStep

{

public void commit()

{

PersonContact pc = new PersonContact();

Page 161: jmatter

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 "We’re almost done; Person record will be " +

"committed after clicking ’Next’";

}

}

Besides providing the basic step information: title, description, and view, we alsoneed to fill 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. finally, we persist our instance

JMatter does the rest! Let’s take our app for a little spin.

12.3 Running the Application

Let’s run our app:

$ ant run

The next five figures are screen shots for the various steps in our simple wizard.Note how the name, description, and view for each step are automatically placedin their respective places on the wizard’s window.

Page 162: jmatter

152 CHAPTER 12. WIZARDS, CSV EXPORT, AND PDFS

Page 163: jmatter

12.3. RUNNING THE APPLICATION 153

Page 164: jmatter

154 CHAPTER 12. WIZARDS, CSV EXPORT, AND PDFS

This coverage of wizards was meant to be an introduction to the topic. JMatter’swizard framework is complete from the point of view that one can produce wiz-ards of any degree of complexity by combining basic steps, composite steps, andconditional steps in various ways.

12.4 CSV Export

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

Page 165: jmatter

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 com-mand simply exports the table model exposed by the listing. However, in thiscase, it would be nice if the address fields were flattened as properties for eachcontact. It’d be even nicer if there a CSV export wizard walked you through theprocess, allowing you to select which fields to export, which to skip, and in whatorder to serialize them out to file. We hope to extend this CSV export feature in afuture version of JMatter.

12.5 PDFs

12.5.1 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 defines an xml vocabularyfor laying out reports. It’s somewhat difficult to describe in one or two sentenceswhat JFreeReport is all about. Some of its characteristics are reminiscent of tem-plating technologies where information from our applications can be merged witha the xml report specification to produce the final report. The report specificationdefines various bands such as report headers and footers, page headers and foot-ers, and the actual report items themselves.

Page 166: jmatter

156 CHAPTER 12. WIZARDS, CSV EXPORT, AND PDFS

JFreeReport also provides means for you to automatically display a print previewof your report from inside your Swing application. From that dialog, one also hasthe ability to produce the report in a number of formats, including PDF, print, andMicrosoft Excel.

The JMatter framework attempts to make the job of producing reports with JFreeRe-port easier. The JFreeReport libraries are already bundled with JMatter. Produc-ing a PDF report from JMatter via JFreeReport is a relatively easy task. The taskof writing the report specification using JFreeReport’s XML specification howeverremains unchanged.

The authors of this framework have used JFreeReport to produce completed med-ical forms, merging information in a medical system with a template defining thelayout 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 reportspecification:

1. the implementation of a TableModel interface, which provides the majorityof the tabular data to be included in a report, and

2. a simple properties file with key-value pairs for passing any kind of infor-mation to include in the header or footer sections of the report

JMatter defines 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 specification.The first method provides the path to the report’s xml specification. JMatter basi-cally follows the convention that these xml files be placed alongside source code.The xml files are then loaded into a Java application as a resource from the class-path.

If in a command method, you return a Reportable instance, JMatter will take itfrom there and use JFreeReport to produce a corresponding PDF file and open itusing a PDF reader application.

Page 167: jmatter

12.5. PDFS 157

12.5.1.2 A Simple Example

Let’s build a very simple report for our ContactManager application. The pointof this section is not to provide documentation for JFreeReport. Rather, it’s onlyto illustrate how the integration works.

So here’s a simple mechanism to expose the production of a report that will in-clude 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 I’m doing here is exposing a static command using the JMatterconventions. This command returns a Reportable implementation that in this casepasses data only via a tablemodel. I’m basically returning the default table modelthat JMatter exposes on lists of types.

Here is a very basic sample JFreeReport XML specification:

<?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">

Page 168: jmatter

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 specification are located in the items band, wherewe see that various string-based fields are specified. JFreeReport allows you toinsert images, other data types, to control the font size, style, and placement ofthe information. JFreeReport also provides a number of built-in functions thatcan be invoked to calculate sums, for example. Developers can also write andplug in their own custom functions.

The result of invoking this command from the JMatter user interface is the pro-duction of the report PDF, as shown below.

Page 169: jmatter

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 forJava. It is a well-supported project. One appealing feature of this project is itscompanion project iReports, a mature graphical report designer, which does awaywith the tedium of writing JasperReport’s analog to the the xml report specifica-tion we just saw in the last section.

Another attractive feature of JasperReports is its support and integration withHibernate. This makes JasperReports a perfect mate for JMatter. We recentlyextended the Sympster demo application with an example use of JasperReportsfor producing a symposium schedule. Simply run Sympster, create a symposiumand a number of associated Sessions, and then invoke the Symposium commandReport Schedule.

Page 170: jmatter

160 CHAPTER 12. WIZARDS, CSV EXPORT, AND PDFS

JMatter now bundled the JasperReport libraries with its distribution for your con-venience. We also highly recommend you support the JasperReports project bybuying 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 desk-top’s default PDF viewer, rather than attempt to embed a PDF viewer componentwithin one’s application.

The Java platform has such a desktop integration feature in Java SE v6. The stateof affairs today is such that the MacOSX platform still lags other platforms anddoes not yet support this version of Java. Developers often cannot afford to ig-nore this platform, since the very raison d’être of the Java platform is platformindependence.

JMatter has a generic solution to this general problem of “launching” a given file,with the result being the launching of the desktop’s default-designated readerfor the document in question, combined with the action of opening the file inquestion within that viewer. This solution will work with earlier versions of Java(e.g. Java 5), and can be used to open PDF files, and other documents (.doc, .txt,.xls, .csv, etc..) in a platform-independent manner.

Here’s example code that uses a simple strategy for launching a dynamically gen-erated pdf file:

File reportFile = File.createTempFile("report", ".pdf");

reportFile.deleteOnExit();

// write to the file..

com.u2d.utils.Launcher.openFile(reportFile);

In the above example we use Java’s API to create a temporary file in a platform-independent manner and specify that the file should be deleted after the end-userquits the application. Then we simply call the static method Launcher.openFile(file)which does the rest. This has been verified to work on windows, apple, and linuxplatforms 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)

Page 171: jmatter

12.6. SUMMARY 161

12.6 Summary

In this chapter we’ve seen the ease with which we can integrate wizards (assis-tants) into an already powerful user interface.

This wizard feature has already been used in other contexts to produce complexwizards, that break down complex new patient forms at medical clinics into a setof smaller steps. Most of us are too familiar with the amounts of information apatient or guarantor must enter when first visiting a medical institution (in theUnited States, at least).

The JMatter framework attempts to be as open as possible. Wizards are not theonly way to inject custom user interface features into JMatter applications. JMat-ter was designed to allow you to write your own custom views for objects andplug them into your existing JMatter applications, which is the topic of our nextchapter.

We’ve also seen the CSV Export feature, a nice though simple mechanism forexporting data out of your application. Of course, there already exist many toolsto export and process your application’s data. It’s already easily accessible in thatall the information resides in an open database system.

Finally, we also see that JMatter provides an avenue for producing PDFs by in-tegrating and leveraging the open source JFreeReport API. I’ve personally alsowritten directly against the underlying iText PDF library to produce and displayPDFs directly as a consequence of a command invocation.

Page 172: jmatter

162 CHAPTER 12. WIZARDS, CSV EXPORT, AND PDFS

Page 173: jmatter

Chapter 13

Calendars and Maps

Many types exhibit fields 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. JMattersupports both a simple and a fancy model for integrating scheduling visuallyinto its graphical user interface.

For mapping, JMatter integrates Swingx-ws for viewing entities on a map, in afashion similar to what we’ve become accustomed to with Google maps.

13.1 Calendars

Section 6.5 on page 74 discussed a way to expose a fully-functional calendar viewinto the Sympster sample application. This calendar view has some attractivefeatures such as the ability to view multiple schedules (we saw different sched-ules for distinct locations at a conference). It took only abiding by a few simpleconventions to do this integration. JMatter now calls this form of calendaringintegration its fancy calendaring model.

JMatter now exposes a second, simpler calendaring integration model that makesalmost no requirements on your model and yet in some ways is even more pow-erful than the former. Let’s say we need to model a meeting. All we need to do isdefine a field of type TimeSpan and extend the base type CalEvent. This base typeis now only a marker base class. We are not required to provide any metadata,there’s no need to implement or override any methods, and we’re free to namethe model object’s timespan field however we see fit.

JMatter will detect the type in question and automatically identify the timespanfield in question. JMatter then exposes a command on the type named Browse

163

Page 174: jmatter

164 CHAPTER 13. CALENDARS AND MAPS

in Calendar, which brings up a calendar view with both custom week and dayviews. You can navigate this view in time. What’s special is that this customcalendar 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 in-voking the Browse command is always adorned with a query panel at the top.This means that the list can be dynamically filtered. This calendar view sports thesame query panel. So, not only can we browse information in time, but this fea-ture is further combined with search capabilities. So if we’re looking at a calendarthat’s too crowded with meetings or talks, and we’re looking for a meeting at aspecific location, we can filter the listing.

In figure 13.1 we see a calendar view with four talks. Note the query panel at thetop.

Figure 13.1: Calendar view with four talks

The next figure shows the same listing filtered by title (we’re looking for talkswith the word ’Swing’ in their title, just as an example).

Page 175: jmatter

13.2. MAPS 165

Figure 13.2: Filtered Calendar View

Separately, one enhancement to this calendaring view worth noting is that dura-tions can now be edited directly from within this view by simply dragging thebottom 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 morecompelling, 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 theproject named Swingx-ws (where ws stands for web services).

This implementation is a little less mature compared to calendaring but has comealong nicely.

Figure 13.3 shows an example route for a flight itinerary that leverages JMatter’smapping support.

Page 176: jmatter

166 CHAPTER 13. CALENDARS AND MAPS

Figure 13.3: A Flight Route

In this particular implementation I embellished the default map view with anadditional layer using curved paths to delineate the route’s segments. The way-points on the map represent actual model objects. We can right-click on one andedit it if we wish.

The basic contract is that a type extend AbstractComplexMappableEObject and im-plement the single method specified in the contract with the interface MappableEO:

public GeoPoint geoPosition();

You guessed it: a GeoPoint is a JMatter type, which means that, among otherthings, it knows how to persist itself to database. A GeoPoint encapsulates a lati-tude and longitude.

The specific flight support application from which the previous screenshot wastaken has a model object named Airport which implements this contract. In return,each instance will bear the command View on Map, which will automatically bringup a map view and add the waypoint in question. From there, users can furtherinteract with the map.

Further, list views for Airports automatically bear the list command View on Mapas shown in figure 13.4.

Page 177: jmatter

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 figure shows the result-ing map view with the waypoints in question. A map view is again nothing buta list view.

Page 178: jmatter

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 acloser look at the Lakeway airfield, as shown in the next figure.

Figure 13.6: Zooming in on a Waypoint

Page 179: jmatter

13.2. MAPS 169

Future enhancements to mapping support will likely be in the area of enhancingthe map view with a query panel. In addition, we’re considering tying panning amap with fetching all waypoints bounded by the geographical rectangle that themap represents, which will make feasible browsing large amounts of informationon a map.

I would like to thank Andres Almiray for suggesting and prototyping this inte-gration 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. Forexample, I’ve recently been working on a client application for persons who needto service a specific address. In that context, I decided to add the ability for theend user to plot the given address directly in google maps by launching a webbrowser:

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 we’re doing above is constructing the proper url to bring up an address usinggoogle maps, and finally launching the url in a browser. It’s that easy.

Page 180: jmatter

170 CHAPTER 13. CALENDARS AND MAPS

Page 181: jmatter

Chapter 14

Customized Views and Editors

It’s nice for a framework to support the automatic generation of views for variousobjects. We’ve also seen how the base user interface can be augmented with calen-daring features, wizards, and support for producing PDFs. However, it’s equallyimportant for a framework to remain flexible and to allow for the construction ofcustom views as well.

JMatter’s primary view mechanism at the moment is its Swing-based view mech-anism. Other view mechanisms might be constructed in the future, includingpossibly a web-based user interface.

In this chapter I’d like to demonstrate through examples various ways in whichcustom views can be integrated into the Swing view mechanism.

14.1 Complex, or Composite Views

The demo-apps subdirectory contains a project, CustomUI, designed specifically toillustrate how this is done. It is similar to our contact manager: There’s a Contactclass and an Address class. The idea is that we’d like to be able to customize theway Addresses appear on the screen; specifically, the way that the form view foraddresses is laid out. The default form view is nice. Figure 14.1 displays thedefault view for the address property of the Contact class.

171

Page 182: jmatter

172 CHAPTER 14. CUSTOMIZED VIEWS AND EDITORS

Figure 14.1: Standard Form View the Contact.address Field

Let’s say that we’d prefer to display addresses in such a way that the field captionsare placed above the field editors (instead of appearing to their left), and that we’dlike to lay out the city, state, and zip fields all on the same line, instead of havingthem appear one below the other, as shown in Figure 14.2.

Page 183: jmatter

14.1. COMPLEX, OR COMPOSITE VIEWS 173

Figure 14.2: Desired view for Addresses

It turns out that JMatter’s FormView is already parametrized such that, if you pre-fer, 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 propertyin your application’s spring configuration context file src/applicationContext.xml asshown 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>

Let’s proceed by pretending that this feature was not available. We must do twothings:

1. Override the method getMainView() on the Address class, to return a newview

2. Implement the custom view for addresses; this process is similar to the waywe traditionally build views in Swing

Page 184: jmatter

174 CHAPTER 14. CUSTOMIZED VIEWS AND EDITORS

The first step is straightforward:

public EView getMainView()

{

return new CustomAddressView(this);

}

Now, for the implementation. We could implement the UI by extending fromSwing’s 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));

Page 185: jmatter

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();

}

}

Let’s review this code. Here I am using the excellent JGoodies Forms frameworkto layout a form “by hand,” so to speak. JGoodies’ DefaultFormBuilder makesthis pretty easy. Similar code could also be produced with the help of a visualform designer, such as the Abeille Forms Designer. Note however, that there areadditional responsibilities that this class must fulfill:

Page 186: jmatter

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 theEditor interface

In this case, the ComplexEView interface is fairly simple. Some of the methodshave no-op implementations (detach(), stateChanged(), propertyChange()). Everyview can, at its discretion, attach itself as a listener to the object model and thusreceive model change notifications. In this case, we’re dealing with a compos-ite view, and each of the sub-views already listens to changes to the parts, so wedon’t technically need to listen to model changes here. Views must also make sureto “detach” themselves from the model objects when they’re destroyed. It’s veryimportant that the detach() method properly do this. A careless implementationcan easily introduce a memory leak into the application as views are created andtheir memory not reclaimed because they may still be attached to a model objectwhose lifetime is typically longer than its views’.

The Editor interface is also fairly straightforward. The setEditable() method iscalled when the model object’s state toggles from Read to Edit (and back), thusgiving the user interface a chance to update itself accordingly (if so desired). No-tice also that transferValue() is called before an object is saved, allowing the view achance to bind the newly entered data back to the model object (or possibly raisea validation exception, in which case the save operation is vetoed. The integervalue 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

Here’s a more compelling illustration of customizing a view for an object: theSympster demo application was recently further customized with a custom viewfor its Session class. In this situation, I wanted to reuse JMatter’s default FormViewwhich handles the editing process beautifully and saves me a lot of work. On theother hand, I wanted a more compelling view for sessions in read state, as shownin figure 14.3.

Page 187: jmatter

14.3. THE SELF DEMO APPLICATION 177

Figure 14.3: Customized View for Session

JMatter provides a class named CustomReadView which automatically composesJMatter’s FormView in edit state with a custom view that you provide for the readstate, as shown in the following code snippet from the class Session where thegetMainView() method is overridden correspondingly:

public EView getMainView()

{

return new CustomReadView(new SessionView(this));

}

Please refer to the implementation of SessionView in the Sympster demo applica-tion for the details of its implementation. One note worthy of mentioning is thatthe implementation leverages JMatter’s css4swing library to style itself, which Idiscuss 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 il-lustrated through the bundled demo application named Self. The model for thisapplication is trivial on purpose: it consists of a Space that contains Balls. Thespace has one additional property: the temperature within the space.

In this particular scenario, it is quite unpallatable to view these objects throughforms when it would be so much more compelling if their visual representationswere represented directly in the UI.

Any command you write that returns an object of type View or JComponent will bedisplayed by JMatter upon invocation. The Self demo application takes advan-tage of this feature:

Page 188: jmatter

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 ourspace. We can further set the temperature. I created two balls: a filled red ballwith radius 30, and a blue ball with radius 80, and my temperature was 30 degreescelsius. Proceeding with invoking the Show command, I can expose my customview SpaceView directly in JMatter:

Figure 14.4: The Self Demo Application

The screenshot doesn’t really do it justince since the balls are moving withing thespace 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 viewcould also have been implemented by wrapping it in a CustomReadView as wedid in the previous example.

Page 189: jmatter

14.4. CUSTOMIZING LAYOUT 179

14.4 Customizing Layout

JMatter provides a means through which a layout for a form can be defined byusing the open-source Abeille Forms Designer. By placing placeholder componentsin the layout and giving each a name matching a model object’s field name, JMat-ter can be made to use the specified layout when displaying the form in question.Abeille allows us to serialize the form design’s definition to a .jfrm file which weplace alongside our source code (JMatter’s build file automatically copies thesefiles to the classpath as part of the build process) in a file we name after the modelobject whose view we want to customize. The CustomUI demo application pro-vides an example implementation.

14.5 Atomic Views

JMatter defines the notion of atomic types. Examples include representations forbooleans, dates, text, zip codes, social security numbers, percentages, integers,floats, etc.. They’re defined in the package com.u2d.type.atom.

This section describes how to write a custom view and/or editor for a given type.Let’s take BooleanEO as an example. Here is the implementation for the defaultrenderer for boolean’s:

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 thepassivate() method for now (we’re considering making a design revision whereviews are pooled, and then re-used for different atomic types, in which case thismethod could be used to “clean up” the view before it’s re-used).

So basically one implements the render() method. This method is handed a modelobject that it must render. So in this case, the renderer is given an instance of aBooleanEO 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(). Here’s the definition of the interface that one must implement:

Page 190: jmatter

180 CHAPTER 14. CUSTOMIZED VIEWS AND EDITORS

public interface AtomicEditor extends AtomicRenderer

{

public int bind(AtomicEObject value);

}

And here’s 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 themodel object. Here’s a second implementation for a BooleanEO editor that uses apair of radio buttons instead:

public class BooleanRadioEditor extends JPanel implements AtomicEditor

{

private JRadioButton _yesBtn, _noBtn;

public BooleanRadioEditor()

{_yesBtn = new JRadioButton("Yes");

Page 191: jmatter

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. Usethem as the basis for creating your own implementations.

Page 192: jmatter

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 defines the interface ViewMechanism. The Swing implementation of thatinterface is SwingViewMechanism. This interface defines a litany of methods thatspecify the components for the entire user interface. By revising the correspond-ing method for a given view mechanism, you control the user interface.

For our above implementations of a boolean editor and renderer, and assum-ing the SwingViewMechanism, you’d revise the implementations of getBooleanRen-derer() and getBooleanEditor() respectively for the BooleanEO type:

public AtomicRenderer getBooleanRenderer() {

return new BooleanRenderer();

}

public AtomicEditor getBooleanEditor() {

return new BooleanRadioEditor();

}

Of course, if you’re going to be implementing a custom view for a more complexor composite object, then you’re in complete control of the rendering and editingprocess.

The framework’s view mechanism in general is extremely modular. It’s easy tooverride one small aspect and plug it right into the existing view mechanism tofundamentally change one aspect of the user interface, whether it’s by providingyour own implementation of a FormView (or embellishing the existing one), or bycustomizing the widgets that represent associations.

Page 193: jmatter

Chapter 15

Localization andInternationalization

I would like to thank Felix Torre for assisting in the development of support for lo-calization (l10n) in JMatter, and Marco Meschieri for meticulously going throughthe 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 diversepopulation, in any of a combination of languages. For example, we may haveboth English-speaking and French-speaking users.

Fundamentally, JMatter resorts to one aspect of the Java language that was de-signed for localization: the notion of resource bundles. JMatter uses property-file based resource bundles. Multiple properties files are created. Each followsa certain convention to designate what language and locale it corresponds to, bycombining a base name with a suffix.

Look at the Sympster demo application for example. You will find three files:locale-metadata.properties, locale-metadata_fr.properties, and locale-metadata_es.properties.So each suffix, _fr or _es, is a language designation: the former is the code for theFrench language, while the second designates Spanish. Resource bundles imply aspecific hierarchy for retrieving values for specific keys in these property files: wecheck the computer’s specific language and country. Let’s say we’re in Canada,where the language is fr and the country is CA. The system will look for the filelocale-metadata_fr_CA.properties, falling back to the more generic _fr file, and fi-nally, falling back to the most generic property file.

There exist two sets of locale-metadata files. The first set is located in jmatter/resources/app.In this file you’ll find localization strings that apply to the framework in general.The second set of locale files are project-specific. So in your project, in the re-sources/ subdirectory, you’ll find the second set of locale-metadata files

183

Page 194: jmatter

184 CHAPTER 15. LOCALIZATION AND INTERNATIONALIZATION

JMatter defines keys for retrieving all the labels and text rendered on the logindialog box. Here is how they’re specified in the _fr resource bundle:

# Login Dialog

# ===============================

logindlg.title=Entrez

logindlg.lbl.username=Nom D’utilisateur:

logindlg.lbl.pwd=Mot de passe:

logindlg.msg.login=Entrez S’il vous plait..

logindlg.msg.failed_auth=Mauvais credentiaux; Essayez encore une fois..

logindlg.msg.user_locked=Votre compte est verouille; \

Contactez l’administrateur svp..

JMatter also defines a convention for specifying type labels, command labels, andfield 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 d’utilisateur

User.password=Mot de passe

User.locked=Verrouillé

User.photo=Photographe

User.role=rôle

User.desktop=Écriture-bureau

Here we see that generic commands, shared by all types, are specified as Com-mand.<commandname>. Generic type commands are specified using the key Com-plexType.<commandname>. Other type commands and type fields are likewisespecified using the key: <typename>.<fieldname|commandname>. When dealingwith aggregate fields, you can use a multiple dot notation, as in Speaker.contact.homePhone(see below).

Page 195: jmatter

185

You can specify a localization for a field across multiple types shared in a baseclass by simply using the base class name in the field path. For example (French):

AbstractComplexEObject.createdOn=Crée a la date

Here are some application-specific label designations for French, for the Sympsterapplication:

# 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 pluralname for the type in English.

Here in the USA I can test how my application might look to a French speaker byrevising 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. We’ve includeda couple of snapshots of the resulting localized application (figures 15.1 and 15.2).

Page 196: jmatter

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 iscalled a Presenteure, the field name becomes Nom and title becomes titre. Not allthe text appears in French simply because I didn’t provide a full list of values forall commands and fields. The figures don’t show how the context menus also

Page 197: jmatter

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 demoapplication, the state names can also be localized. For example, here’s how thestate names for issues are localized to French in IssurMgr’s locale-metadata_fr.propertiesfile:

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 JavaSwing defaults to a resource bundle named “uidefaults” to pick up translationsfor tooltips such as a window’s “minimize” button tooltip. JMatter will automati-cally load custom ui defaults specifications from the file jmatter/resources/app/uidefaults_??.properties.For example, the figure below shows some hebrew translations for ui defaultsloaded by JMatter (the file 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 thatare right-to-left such as Hebrew or Arabic. Check out the Sympster demo-app in

Page 198: jmatter

188 CHAPTER 15. LOCALIZATION AND INTERNATIONALIZATION

Hebrew for example. In the USA, you can simply override the locale by uncom-menting this line in the Sympster build file:

<sysproperty key="user.language" value="he" />

Following are a couple of screenshots.

Figure 15.4: Hebrew Login Dialog

Page 199: jmatter

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 exam-ple, at the moment support for the proper date and currency formats for differentlocales needs work. We hope that future versions will flesh out this support com-pletely.

Page 200: jmatter

190 CHAPTER 15. LOCALIZATION AND INTERNATIONALIZATION

Page 201: jmatter

Chapter 16

Child Projects

This chapter provides a more detail information about the structure of JMatterproject directories, and documents a JMatter application’s build file.

16.1 Creating Child Projects

The framework has its own build file, used to compile the framework itself. Thisbuild file contains a target: new-project-ui that automates the creation of a JMatterproject. We walked through using this target in chapter 4. Invoking this targetbrings up a simple user interface, shown in figure 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 con-tains the project files. If the base directory is not specified, we default to creatingthe project as a sibling directory of the framework itself. The last option needs aslightly lengthier explanation.

A standalone project has no external dependencies. Not only is the child projectstructure created, but all libraries necessary to run it are containing within theproject, in the lib/ subdirectory. That is, a copy of the JMatter framework is in asense frozen into the child project. Standalone projects are therefore not subjectto changes to the framework that might take place after its creation (unless theJMatter jar file and other dependent jar files are manually replaced).

191

Page 202: jmatter

192 CHAPTER 16. CHILD PROJECTS

When creating a dependent project, its build file is told where the JMatter frame-work is located and so it can reference the JMatter framework’s .class files directly,as well as any .jar files that the framework itself leverages.

Both modes are useful in different contexts. For developers with in-depth knowl-edge of the framework, that expect expect perhaps to make changes to the frame-work as they develop their application, it’s convenient not to have to repackagethe framework jar file and copy it to the child project each time a change takesplace. Dependent child projects would pick up these changes immediately. Sotherein lays the tradeoff.

It isn’t particularly difficult to change one’s project from being dependent to beingstandalone or vice versa. However, at the time of this writing, there is no magicant target that will do this work on our behalf.

16.2 Directory Structure and Files

The main directories that you’ll see after creating a new project are:

src, test, doc, resources

Each directory’s name fairly clearly implies its role. The base directory for Javasource code is src, while test is the base directory for tests. The doc subdirectorycontains a basic README file. The doc/ directory is of course an ideal location foryour project’s own documentation.

The resources folder is interesting; its composition is summarized in the table be-low.

Page 203: jmatter

16.2. DIRECTORY STRUCTURE AND FILES 193

Directory or File Descriptionimages/ Where to place icons for model objects,

the image for the splash screen, andother image resources that yourapplication will use.

styles.css Default stylesheet for JMatter; governshow the JMatter user interface is styled(see chapter 17).

model-metadata.properties Where to specify required fields, andfield default values.

local-metadata_<locale>.properties Use for localization: provide translationsfor type names, command captions, fieldcaptions, and more in order to produce auser interface that is properly translatedfor the given locale.

hibernate.properties Governs database configuration:database dialect, driver class name,connection url, username and password.

resources/jws Contains resources necessary to bundlethe application as a java webstartdistribution (see chapter 18)

wings/ and echo2/ This requires some explanation. We’re inthe process of developing a web-baseduser interface for JMatter. At the time ofthis writing, this work is not yetfinished. Resources necessary toconstruct the web applicationdistribution resides in these directories.

src/class-list.json (Optional) This is where you canpreconfigure your application’s classbar:that is, specify here the list of modelobjects you wish to expose to your userinterface.

src/persistClasses.st You typically will not need to edit thisfile. This template is resolved at buildtime to list the persisted entities in yourapplication. The list is derived from the@Entity annotations in your class files. Itis passed to Hibernate via a Springconfiguration file.

All child projects come with an ant build file. This build file generates a numberof directories for the purpose of maintaining artifacts. Let’s discuss these:

Page 204: jmatter

194 CHAPTER 16. CHILD PROJECTS

db If you configure your application to use a lightweight or file-based database,such as H2 or hsqldb, the database files by default reside in this subdirectory

build/classes Your application is compiled to this directory. All resources are alsocopied here, including images and hibernate mapping files (the latter beinggenerated, not copied)

jws-dist Used to assemble the Java WebStart distribution

dist The Java WebStart distribution is packaged as a .war file and copied to thisdirectory

16.3 Build File Targets

Let’s now turn our attention to the child project’s ant build file. Here is a listingand description of the relevant targets.

compile compile code

compile-tests compile tests

genhbm generate hbm.xml files

jar jar it

jar-model jar just the model

jws-dist create java webstart distribution

macappbundle create macosx app bundle

reveng-db Reverse engineer an existing database schema..

run run app

run-test run a test class

run-tests run tests

schema-export export schema to db

schema-update update db schema

shellscript produce runnable shell script

test-report produce junit reports

Default target: run

There isn’t that much to say beyond the default description of these targets. JMat-ter generates Hibernate hbm.xml files to the build/classes directory. The run targetis useful while developing. You typically don’t need to invoke many of these tar-gets. Invoking schema-export for example will automatically compile the code andgenerate the mapping files first. Also, if you’re working with a dependent project,any changes to the framework codebase will automatically be recompiled first.

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.

Page 205: jmatter

16.3. BUILD FILE TARGETS 195

Other targets worth pointing out include shellscript and macappbundle. The firstgenerates a run.sh (or run.bat on win platforms) to launch the application. OnLinux, going from such a script to a desktop-launched application, complete withicon, is trivial. The latter is specifically for macosx users and bundles the applica-tion as a .app “file.”

Chapter 18 on page 209 walks you through deploying your project via Java Web-Start.

Page 206: jmatter

196 CHAPTER 16. CHILD PROJECTS

Page 207: jmatter

Chapter 17

Styling the UI with CSS

Cascading Stylesheets (CSS) is a web technology. It is supported by modern webbrowsers to style user interfaces. CSS is simple and elegant. It is also powerful. Ithas an aspect-like design in that styles for parts of a user interface can be specifiedin a manner that is orthogonal from the rest of an application: it is a cross-cuttingconcern.

JMatter comes with built-in support for a subset of the CSS that I believe to beapplicable to Java’s Swing technology. By default, JMatter will automatically loadthe file resources/styles.css on startup, and interpret and apply the rules containedwithin that stylesheet. Stylesheets consist of rules, and rules consist of selectorsand declarations.

Let us begin with a description of the CSS engine itself and specifically what sub-set of CSS is supported, and how it is adapted to Swing. We will then turn ourattention to the default stylesheet.

17.1 JMatter’s CSS Engine

17.1.1 Selectors

JMatter’s CSS implementation supports both simple and composite selectors. Sim-ple 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

Page 208: jmatter

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 it’s designated by its class name, for example:JLabel.

Composite selectors allow the expression of a path. They’re composed of two ormore 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 thepackage 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 otherway around of course).

A parsing ambiguity arises if one wished to reference a fully-qualified class namein a selector. Let’s say we had a rule such as:

JLabel.special

{

background-color: blue;

}

If the component type were referenced fully-qualified:

javax.swing.JLabel.special

{

background-color: blue;

}

Page 209: jmatter

17.1. JMATTER’S CSS ENGINE 199

It would be less clear (though not impossible to disambiguate) that we were refer-encing a component marked with a css class name. JMatter’s CSS implementationtherefore does not allow fully-qualified class names in selectors.

This CSS implementation adopts and leverages CSS3’s namespaces (thanks toTiago Silveira) module to resolve this issue. CSS3 namespaces were designed toresolve the issue of possibly clashing namespaces in different xml vocabularies.

To reference a type in a different package, you must define a namespace for it, likeso:

@namespace l2f com.l2fprod.common.swing

l2f|JOutlookBar

{

color: olive;

}

The two main items to note here are:

1. A @namespace css rule is defined and aliased as l2f.

2. To reference a type selector in that namespace, concatenate the namespaceid 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 withan html attribute, as in: class=”title”. JMatter’s CSS implementation provides anAPI 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 in-voke the above method repeatedly. There’s also a corresponding method for re-moving a class assignment:

ComponentStyle.removeClass(componentRef, "title");

One can likewise assign an id to a component with:

ComponentStyle.setIdent(componentRef, "btn103");

Page 210: jmatter

200 CHAPTER 17. STYLING THE UI WITH CSS

The above are all static methods.

Application developers needn’t concern themselves with this because the workassociated with defining style names and annotating a user interface is a part ofthe task of writing that user interface. In the case of JMatter, the user interface isalready written and is already annotated. To customize the style of a JMatter ap-plication, all you need to concern yourself with (besides knowing what semanticnames to reference) is editing the stylesheet itself.

You might however want to take a look at the Sympster demo application wherea custom view for a type is written that leverages CSS.

17.1.4 Values

Of the myriad of ways in which measures can be specified in CSS, JMatter sup-ports only a subset:

1. Font sizes must be specified in pt’s

2. Borders, margins, and padding must be specified in px’s

3. Colors can be specified either using the sixteen predefined color names, thesix-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 sup-ported at this time

17.1.5 Properties

A subset of the CSS defined 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

Page 211: jmatter

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

JMatter’s CSS implementation also supports these CSS3 properties, but only onSwingX 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 [inheri-table] properties inherited from containing components are applied as well.

17.2 The JMatter Stylesheet

Let’s study the file 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 JMatter’s Swing view mech-anism in selectors. Here are some examples:

JDesktopPane

{

background-color: #7684FF;

}

jm|FormPane

{

background-color: #fffaf0;

}

The first rule customizes the background color of the desktop pane. The selec-tor matches a standard swing component. The second rule customizes the back-ground color of form panes (using an off-beige color).

Here are two more rules:

Page 212: jmatter

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 JMenuItem’s or JButton’s).

Furthermore, Swing (and forms) has the notion of a single command being desig-nated as the default command on a form. Default buttons are given a little extraattention, such as interpreting pressing of the Enter key on the form as implyingthe invocation of the default command. Here you can specify how its view shouldbe styled.

Note how both rules .command and .default-button match for default commands sothat their properties are combined. This CSS engine will make sure to apply themore specific rule in case of a conflict.

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;

}

Page 213: jmatter

17.2. THE JMATTER STYLESHEET 203

Here we specify how to style the captions for required fields and validation errormessages. Feel free to customize these (and any other styles) as you see fit.

And finally, this rule styles the large semi-transparent message panel that appearsfor 2-3 seconds to acknowledge various actions, for example when one creates andpersists 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 atechnology you might already be familiar with, and since this implementationadheres strictly to the specification (i.e. it doesn’t invent its own properties), youshould 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

{

Page 214: jmatter

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;

}

Page 215: jmatter

17.3. USING CSS4SWING IN STANDALONE SWING APPLICATIONS 205

17.3 Using CSS4Swing in Standalone Swing Appli-cations

The CSS engine used by JMatter was developed by Eitan Suez, for the purposeof enhancing JMatter. However, the implementation is agnostic to the JMatterframework, and can be used with any old Swing application.

That is, if you’re working on a Swing-related project and wished you could styleyour application with CSS, well, now you can.

First you’ll need to add these libraries to your classpath, which you’ll find injmatter/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 applysemantic style names or id’s to various components.

The only other requirement is to insert this statement before you start buildingyour Swing user interface:

CSSEngine.initialize();

By default, the engine will look for the resource styles.css in your classpath. Alter-natively, 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 completeillustration:

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

Page 216: jmatter

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);

Page 217: jmatter

17.4. FUTURE PLANS 207

}

});

}

}

17.4 Future Plans

Additional enhancements for CSS support in JMatter are planned. Here is a ten-tative list:

1. Produce multiple alternative stylesheets that can be used as themes to skinJMatter applications

2. Support all border line styles defined by the CSS specification

3. Complete support for color value syntax, including the rgb() function andthe CSS3 rgba() function for supporting transparency

4. Possibly adding support for CSS @import statements, as a simple includemechanism

5. Possibly adding support for applicable CSS pseudo classes and pseudo ele-ments

6. Perhaps expose the ability to apply effects in a Swing application throughCSS

If you produce a stylesheet that you find does a good job at styling the JMat-ter user interface, please consider contributing it back to the project as a JMattertheme.

Page 218: jmatter

208 CHAPTER 17. STYLING THE UI WITH CSS

Page 219: jmatter

Chapter 18

Deploying your Application

In this chapter we’ll discuss how to setup your application for distribution withSun’s Java Web Start technology.

18.1 JMatter Applications Architecture

We already know that JMatter applications rely on a database management sys-tem for storing information, performing queries, and more. The architecture ofJMatter applications is simple and straightforward: JMatter applications are in-stalled at end-user workstations, and communicate to the database that resideson the server. This architecture is known as a two-tier client-server architectureand 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 clientmachine. 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 theworld wide web. End users simply visit a web page and click on a link thattriggers the automatic download and installation of the application to the end-user’s computer. Java Web Start is bundled with every distribution of Java.

It gets even better: each time the end user launches the application, Java WebStart verifies whether any updates are available and will automatically downloadand install the updates prior to launching the application. So, not only is thedistribution of your application automated but also its maintenance. You canread all about Java Web Start at http://java.sun.com/products/javawebstart/

209

Page 220: jmatter

210 CHAPTER 18. DEPLOYING YOUR APPLICATION

In our case, we’ll be deploying applications within an intranet or extranet. Nev-ertheless, we’ll be using web technologies to distribute and keep our client instal-lations up to date.

18.3 Deploying ContactMgr

JMatter provides an ant target for bundling your application for distribution viaJava Web Start.

We first need to decide what web server to use to deploy our application. We’llneed the machine’s host name or ip address, and the port number (which typicallywill be 80). Enter these two bits of information into the file project.properties locatedin resources/jws/dynamic

Second we need to ensure that the database connection url we specify in hiber-nate.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 ensurethat no firewalls forbid communications traffic between the end-user machinesand 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, here’s the magic ant target:

ant jws-dist

When the target is finished running, it will have produced a .war file in the distfolder.

Create a directory with the same name as your project inside your web server’sdocument root directory:

sudo mkdir /var/www/ContactMgr

Extract the war file 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 andvisit the web page in question (perhaps http://local-server/ContactMgr). You’llsee a page that looks like figure 18.1.

Page 221: jmatter

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 yourapplication. Before permitting you to proceed, you will be prompted to acceptthe certificate used to sign the code (see figure 18.2).

Figure 18.2: Java Web Start Security Prompt

This requires some explanation. Java Web Start will not run any code that is notsigned with a code certificate. This is not 100% true. It is possible to customizethe Java security policy on every client machine to allow locally deployed code to

Page 222: jmatter

212 CHAPTER 18. DEPLOYING YOUR APPLICATION

run. However this is not really a viable option as it completely defeats the originalpurpose of Java Web Start being a simple and easy way to deploy applicationswithout having to perform modifications on each client machine.

So the code must be signed. By default JMatter will sign the codebase anony-mously so as to allow the code to run. Java Web Start will prompt the end-user toallow the the application to launch. This is essentially the hand-off point. It is theplace where you, the developer of the application, procure a valid code certificateand use it to sign the code base that you’re deploying.

Enough discussion, go ahead and reply Yes to the prompt and watch the appli-cation launch. You can proceed by logging in to the application and interactingwith it as you always have up to now.

That’s basically it. That is, anyone in your organization can now visit the intranetweb page for our Contact Manager and with a single click of the mouse they willhave downloaded, installed, and run our Contact Manager application.

18.4 Caveats

The process of accessing a database by nature is meant to be difficult as data secu-rity is of utmost importance. You need to make sure your database is configuredto accept connections from the network, that the configuration does not leave anysecurity holes (pass in an MD5 hash of the database user’s password for loggingin, for example). If Java Web Start fails during the launch process the first timeyou attempt to deploy your application, it is likely due to a connection timeoutattempting to access the database. This would be a good time to take a momentand review your database documentation and your database settings.

18.5 Security Options

The PostgresQL database can be configured to communicate with clients overSSL, providing secure communications between clients and the database server.This option is an interesting one because it allows us to consider the possibilityof deploying a JMatter application to a limited number of concurrent users over awider geographic area.

Also, it’s worth mentioning that H2 is a lightweight database that also supportsSSL. In addition it supports encrypting the entire database.

Page 223: jmatter

18.6. MORE ABOUT JWS 213

18.6 More About JWS

Figure 18.3 depicts a MacOSX client application launched via Java Web Start. Thedatabase server in this instance is a PostgresQL cluster running on a nearby Linuxmachine.

Figure 18.3: Java Web Start - Launched Application on a MacOSX Client

The first time the application is launched, Java Web Start will be downloadingand installing an entire application. So the first launch will be fairly slow; it mighttake 30 seconds. Subsequent launches will not require the download (only a quickcheck for updates against the server) and consequently will take considerably lesstime.

The hyperlink on the ContactMgr intranet page is only one way in which endusers can launch their application. Java Web Start can be configured to place ashortcut for the application directly on the end user’s desktop, for example.

18.7 Summary

JMatter attempts to make the Java Web Start process as easy and painless as pos-sible. Let’s review what we just did:

Page 224: jmatter

214 CHAPTER 18. DEPLOYING YOUR APPLICATION

1. We invoked the ant jws-dist target, and

2. extracted the generated .war file to the web server

3. Visited the web page and clicked on a link, which triggered Java Web Start

Anyone who’s had to configure Java Web Start the normal way will certainly ap-preciate this.

Page 225: jmatter

Chapter 19

Deployment, Take II: TheApplication Browser

Deploying JMatter applications with Java WebStart works well enough. It’s cer-tainly what people term the fat client model, where the client application is quitesizable, in the order of 20 Megabytes, primarily due to the large number of de-pendent libraries required to support the application.

The web model on the other hand is seen as a more lightweight approach, andtermed the thin client model.

In a manner directly analogous to the web, JMatter now supports a thin clientmodel for deploying your applications, thereby deriving the same set of benefitstypically 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 theApplication Browser. You will find it in the base directory of the JMatter distribu-tion. This application consists of a single model object: the Application Bookmark.Roughly speaking, this application is to JMatter applications what the Firefox webbrowser is to web applications: it’s an application that allows you to load appli-cations by specifying or entering a URL.

The Application Browser can be packaged and deployed using the traditionalJava WebStart mechanism, or perhaps through the more traditional mechanismof using an automated installer. By virtue of being implemented entirely in Java,

215

Page 226: jmatter

216 CHAPTER 19. DEPLOYMENT, TAKE II: THE APPLICATION BROWSER

this application is by definition cross-platform. It’s worthwhile noting that theJMatter application browser is itself nothing but a standard JMatter applicationwith 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: let’sdeploy 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 first task, you will find a new JMatter ant target named jar-model that willproduce the packaged artifact. The output of this target is the file dist/Sympster.jarwhich consists strictly of the compiled object model and supporting classes (ifany), the application resources and configuration files (images, class-list.json, hi-bernate mapping files, database connection setings, and spring configuration files).

We can now upload the artifact to a web server, say for example, to the jmatter.orgweb site perhaps at the url: http://jmatter.org/demo-apps/Sympster.jar

We now launch the application browser.

Page 227: jmatter

19.1. HOW IT WORKS, BY EXAMPLE 217

Figure 19.1: The JMatter Application Browser

In Figure 19.1, we see that I’ve defined an application bookmark for the Sympsterdemo application that I’ve deployed to jmatter.org. I can now click on the Launchbutton to launch the application.

The jar file is downloaded, and class-loaded into the client application’s virtualmachine. The application configuration is read and the application is loaded. Itssplash screen appears, and we are finally presented with a login dialog. Uponlogging in, we see the Sympster application’s class bar show up on the left handside and we’re ready to start using our application: perhaps defining new talks,creating a new session schedule for an upcoming symposium, etc..

When we’re finished with our Sympster application session, we can either quitthe application, or unload it (from the menu: File -> Unload Application). TheApplication Browser re-appears, and we can choose to launch an entirely differentapplication from a different URL.

The application model remains two-tier, with the application talking directly toits back-end database. But it is worthwhile at this time to examine the benefits ofthis method of deployment:

• We have turned a fat client into a thin client

• The size of our download has shrunk from 20MB to 80KB (it’s worth stress-ing that many web pages today are larger than 80KB)

Page 228: jmatter

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, dropa new copy on the web server, and thereby upgrading the application, in amanner 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 de-pendencies on third party libraries that are not bundled with the ApplicationBrowser. How can we deploy MyTunes along with these necessary dependen-cies?

The answer turns out to be very simple. All that is necessary is to properly citethe dependencies in the jar file’s manifest. Here is MyTune’s 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 we’ve added the two libraries JID3.jar and jl1.0.jar(responsible for playing mp3’s) using the jar manifest’s Class-Path attribute. Allwe do next is make sure to put these libraries alongside MyTunes.jar on our webserver. The rest is transparent: the associated jar files are fetched alongside the ap-plication. In this case our application is 300KB in size, counting the dependencies.Not bad for a music player.

19.3 Looking Ahead

We’re thinking about further enhancing the application browser to allow multi-ple applications to be loaded in separate tabs, in a manner similar to the way thatweb browsers today feature tabbed-browsing. We’re also beginning to contem-plate developing a way to run JMatter applications using a three-tier model: bysplitting the application logic between client and application server.

Page 229: jmatter

Chapter 20

Tooling

This chapter attempts to answer the question: are tools available specifically forassisting 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 briefdescription of this tool from Jim:

I became very interested in JMatter after reading your book and play-ing around with the demos, but was disappointed in the lack of a wayto use a legacy database. Therefore, I just finished writing a Java pro-gram that creates JMatter Java source files from a database. It seemsto work fine, although using it is a bit tricky because it involves a fewmanual steps: run the program, update the schema, then run an SQLscript.

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 file resources/hibernate.propertiesto 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 thegenerated source code will belong to with -Dreveng-pkgname=my.pkg.name(otherwise the code will default to org.jmatter.app)

219

Page 230: jmatter

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 map-ping files from the generated source code; and

(b) it will update the existing database schema to include version and cre-atedOn columns and additional jmatter-specific tables

6. At the present time, there’s one other simple matter to address. JMatter doesnot 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 thatyou can manually invoke to rectify this issue. Here’s an example of how Ido this with postgreSQL:

psql databasename

$ \i reveng_update_script

$ \q

That’s it. You’re now ready to either run your JMatter application and to layerbehavior 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 lightweightproductivity solution for building JMatter apps. I can no longer write JMatterapplications without them.

This tool is included with the JMatter distribution in jmatter/tools/IDEA. Followthe instructions in the README file to install the templates into the IDE. The toolthus far consists of one basic file template and a number of live templates that cansignificantly 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 man-ner 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

Page 231: jmatter

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 inspectthe various live templates defined for jmatter under the "jmatter" tree node.

Some examples include:

Key Description

fo expands to the metadata specification for fieldOrder

flat expands to the flattenIntoParent metadata specification

bprop will write the bound property getter and setter methods

for you

tv expands to specify the tabViews metadata

plu 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 intoJMatter. One way to launch it is by invoking the ultraviolet target from the frame-work build file:

Page 232: jmatter

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 define the set of classes in your model and their interre-lationships. One can specify associations, their cardinality, whether they’re bidi-rectional. Much of JMatter’s metadata can be specified directly via each class’sproperty sheet: class name, plural name, icon, color code, fields, commands, aswell as field and command metadata. One can also model inheritance.

Ultraviolet will generate a .umlc file for your model: a complete description ofyour model in the umlc language. Finally, the tool will automatically translatethe model into a JMatter application. Technically, the only aspects of developmentthat you do outside of Ultraviolet is the implementation of the commands.

This tool is inspiring and shows the power of domain-driven design and imple-mentation. One can go from a simple idea to a model to a running application inminutes.

Both Ultraviolet and umlc were developed entirely by Ryan Ramage. This toolis open source and has its own home page: http://code.google.com/p/umlc/ andhttp://code.google.com/p/umlc/.

Page 233: jmatter

Chapter 21

The Power User

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

21.1 Visual Command Interface

JMatter sports a feature inspired by blacktree software’s QuickSilver, and more re-cently, Gnome Do. Briefly, these applications provide a visual command interfacefor desktops. For a desktop management application, most commands involvelaunching applications or bringing them up in the terminal or the file manager.The end user composes an instruction by first specifying the target applicationand second the specific command to invoke on that application. Its primary useis for launching applications. Applications are specified by typing, and identifiedvia a text matching algorithm.

It turns out that these applications adhere to the noun-verb metaphor which isa strong part of JMatter’s general philosophy. Every operation in JMatter boilsdown to the invocation of a command on a target object (and optionally specifyingcommand arguments). JMatter’s implementation of a visual command interfacenow provides an additional, alternative visual mechanism to invoke commands.

I will illustrate how this interface works with an example. Let’s take the Symp-ster demonstration application. Let’s say we wish to create a new speaker. Wetypically do this by right-clicking on the Speaker icon in the class bar (the visualrepresentation 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

Page 234: jmatter

224 CHAPTER 21. THE POWER USER

3. Press the Enter key

In step 2, we first search for the type Speakers by name, and then we search for thecommand named New. We don’t have to type the full name, just enough char-acters to match the item (the object) we’re looking for. Optionally, you can pressthe down-arrow key to see other matches and select the appropriate one. The es-cape key dismisses the visual command interface. In the above case, invoking thecommand causes the visual command interface to auto-dismiss.

Figure 21.1 shows JMatter’s visual command interface in action.

Figure 21.1: JMatter’s visual command interface in action

Many desktop users have become habituated to this type of command interfaceand prefer it. First, this is a testament that noun-verb types of user interfaces area good match for the way we tend to go about doing things. Second, it providesa uniform way of invoking any command. Finally, you don’t have to take yourfingers off of the keyboard.

This feature is built-in to JMatter. No work is necessary to enable it. You mighthowever be interested in extending its capabilities further by extending its index,which we discuss next.

Page 235: jmatter

21.1. VISUAL COMMAND INTERFACE 225

21.1.1 Extending the Index

The visual command interface by default matches types. Match a target type, andthen invoke a specific command on it, for example: Person Contacts -> Browse.

It would be nice however if we could interact with instances of a given type inaddition. For example, with the contact manager, it’d be nice to match a contactby name directly from the visual command interface. Likewise, in MyTunes, it’dbe nice to direclty match a song by title. In Sympster, Speakers and Talks are alsogood candidates.

The visual command interface provides a mechanism for you to add items to itsindex. The ContactMgr application has recently been enhanced to show you how.Here’s 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 con-tact instances in its index.

Next we need to revise our spring configuration file to specify our subclass asthe application’s Application bean. We edit the file src/applicationContext.xml asfollows:

<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 bean’s class above references our subclass. That’s it. Now whenwe launch the contact manager, assuming we have a contact named John Doe, we

Page 236: jmatter

226 CHAPTER 21. THE POWER USER

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

21.2 Associations Made Easy

NakedObjects originally introduced a terrific way to establish associations be-tween 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. Havingto 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 displaya listing of entries of the type for a given association, that the user simply picksfrom.

Let’s look at a concrete example: let’s say we’re working with the Symposiummanager demo application in JMatter. And let’s further say that we’re defininga new talk to be given. Talks have a many-to-one association to the speaker (orpresenter) giving the talk.

My favorite way of establishing that association is with the in-place associatorwidget that’s built-in to JMatter. Here’s how it works. When editing the talk,click (or tab into) the association field in question, which in this case is Speaker.Simply start typing and a matching list of entries automatically appears. Thiscomponent dynamically fetches matching entries from the database as you type.The matched items listing also pages by default, so for a scenario with too manymatching entires, only the first page will be fetched. In my experience with thiscomponent, this is one of the fastest ways of making an association between twoobjects.

Here’s a snapshot of me trying to define a new talk, *In Action*, as it were1:

1Please pardon the sarcasm

Page 237: jmatter

21.3. PAGING 227

Figure 21.2: Associating a Speaker to a talk

The only detail to tend to is to specify which field of Speaker are we searching by.That’s what that little magnifying glass icon to the left of the text field is for. It’sa drop-down combobox that dynamically lists the various fields you might wantto search by.

The default field that JMatter should use for searching in the context of in-placeassociations is controlled by the defaultSearchPath metadata, as shown by this ex-ample:

public static String defaultSearchPath = "name.first";

See section 8.4.9.

21.3 Paging

We’ve all had to implement this feature as developers. Today, many frameworkssuch as Tapestry for example, will provide components out of the box that willautomatically take care of paging a listing on your behalf.

JMatter also provides paging out of the box. When I sat down and started tothink about this feature, I saw a certain pattern. One’s first, naive implementationof paging might consist of a simple forward and back navigation buttons:

Page 238: jmatter

228 CHAPTER 21. THE POWER USER

< >

Shortly afterwards comes the request for the ability to navigate to the first andlast 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 thevicinity 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 embod-ied 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. What’s nice about today’s scrollbarsis that their size is inversely proportional to the length of the list. The larger thelist, the smaller they are. Scrollbars have the advantage of giving you more ofa visual perspective of where you are in the list. And you can simply drag thescrollbutton to any location along its dimension.

JMatter’s Swing-based view mechanism defines a view implementation: a com-ponent named PageScrollBar which extends Swing’s JScrollBar, shown at the bot-tom of the following two-page listing:

Page 239: jmatter

21.4. EXPOSÉ 229

Figure 21.3: Paging a Conference’s Sessions

As usual, developers of JMatter applications need not concern themselves withthis at all. It’s bundled into the framework and it just works. If however you feelthe need to customize the way this scrollbar looks or behaves, it’s easy enoughwith a little Swing experience to make whatever enhancements or decorationsone might have in mind.

21.4 Exposé

JMatter GUIs are inherently Object Oriented UIs. I like to make the analogy toour operating systems’ desktops. There are a number of ways to make such UIsmore effective. Sometimes I look to these desktop systems for ideas and features.

One such feature is Apple’s Exposé which has since also been copied by the CompizFusion project on Linux: the idea of scaling down and fanning out one’s windowstemporarily for the purpose of easily switching focus to a window that is other-wise hidden by other windows with a higher z-index. JMatter incorporates sucha feature. Pressing the F12 key invokes the JExplose 2 feature which does preciselythis. This option is also available form the desktop pane’s context menu.

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

Page 240: jmatter

230 CHAPTER 21. THE POWER USER

21.5 Navigation

21.5.1 Window Placement

JMatter takes a certain strategy relating to the placement of new windows (inter-nal frames) in its Graphical User Interface.

I recall trying various window placement strategies and then realizing somethingI was doing as a user of my applications: after creating a new view, I’d quicklyreach for the window’s title bar and place the window where I really wantedit. I don’t think there’s an algorithm for guessing the user’s intent. So I startedthinking about what might the next best thing be.

The strategy was to minimize the amount of work one has to do in moving theresulting window. What I do is place new windows such that their title bars arenear the current mouse cursor location, thus minimizing the distance one wouldhave to move their mouse to reach for it.

There’s a somewhat hidden feature in JMatter which I very much like and that I’dlike to share. This feature takes things one step further: it automatically puts thenewly created window in placement mode. Allow me to explain..

This feature requires pressing a metakey to communicate your intent to use it:when you’re about to invoke a command that creates a new view (e.g. the Opencommand) , hold down the Control key (on the mac, use the Command key).

The resulting window automatically "binds" to your mouse location. That is, itwill follow your mouse. So, the way it works is you invoke the command withthe Control key pressed and the new view is created, but it starts following yourmouse around. Once you’ve found that ideal spot, a single left-click is all youneed 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, andis specifically related to the file manager, is the idea of giving users options interms 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 thecontents of that folder. Long ago, on ms-windows I recall always turning on theoption "re-use existing window"; that is, replacing the existing view with the newone. This can really help with an otherwise rapid proliferation of windows onone’s desktop.

Separately, the mozilla project introduced us to another navigation option: tabbedbrowsing, which is a sort of "middle of the road" approach: don’t create a newwindow, but don’t replace the existing view either. Since then, we’ve seen otherapplications, such as shell terminals, copy this handy feature.

Page 241: jmatter

21.5. NAVIGATION 231

JMatter now supports both modes of navitgation. A User’s default browsing pref-erences can be specified through the User model object, which has an aggregateproperty named Preferences. Its first and only option at the moment captures howa user generally prefers to navigate in JMatter: should new views be created bydefault:

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 JMatter’s default navigation be-havior.

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 isin-place navigation. To accommodate this, a new gesture has been introduced inJMatter: holding down the Shift key while invoking a command that produces anew view will cause a context menu to appear at the mouse location, for selectinghow to create the new view. The choices again are the above three: in a newwindow, tab, or in-place.

Figure 21.4 captures the invocation of the Open command while holding downthe 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.

Page 242: jmatter

232 CHAPTER 21. THE POWER USER

Figure 21.5: “Open in new tab” Option

The next figure 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 detach-ing the view onto its own window or closing the tab (Ctrl+w is the correspondingkey binding).

Page 243: jmatter

21.6. COPY AND PASTE 233

Figure 21.7: Tab Detach Option

I believe this to be an important feature, finally producing a desktop with a num-ber 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 fordocking views. I have looked at flexdock, which is a terrific effort. But I’m lookingfor something that is more transparent: effectively a layout manager designed forJDesktopPane that transparently provides docking support. Let me know whatyou recommend.

21.6 Copy and Paste

Every Swing application gets for free the ability to use the underlying platform’scopy and paste capabilities when working with JTextFields and JTextAreas.

In JMatter you might have noticed that instances also sport their own Copy/Pastecommands. You’ll find this feature to be a little more powerful and interestingcompared to the basic clipboard copy/paste feature.

Page 244: jmatter

234 CHAPTER 21. THE POWER USER

The main difference is that unlike the clipboard, where you get one temporaryarea 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 andcopy an Address here, a Contact object there, or an entire Person instance and allthree 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 thenew instance. All of the information is copied over. This use case may not be veryinteresting or real.

But there are other situations. Take for example how a Person has a Contact prop-erty modeled using composition (or aggregation). Each instance has its own copy.Yet it’s very possible for two persons to have the same contact information, orperhaps the same address, with the very real possibility that the two copies willchange/diverge over time.

The copy/paste commands on instances are automatically placed by JMatter in anumber of context menus for a number of views. You’ll find these commands inthe title view’s context menu, as shown below.

Figure 21.8: Copy on Instance Title View

You’ll also find it on aggregate objects’ nodes as shown in figure 21.9.

Page 245: jmatter

21.6. COPY AND PASTE 235

Figure 21.9: Copy on Aggregate Node View

Finally, you’ll find it on the context menus for individual tab title views, as shownhere:

Figure 21.10: Copy on Tab Title View

This feature can come in handy and save repetitive data entry tasks, where one

Page 246: jmatter

236 CHAPTER 21. THE POWER USER

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

21.7 The Restore Desktop Feature

One last feature, though not completely polished, is worth mentioning. JMattersaves and restores end users’ desktops between sessions.

That is, the size and positions and other information about open windows isrecorded and stored to the database when one logs out or quits the application.Conversely an attempt is made to restore these views on login. What’s nice aboutsaving this information to database is that one’s desktop configuration is indepen-dent of the workstation you log in to. Instead it’s tied to your user information inthe database.

This feature is at the moment fairly simple. Other than restoring the main windowbounds and simple child windows (lists and instances), it does not yet properlyrestore other types of views at the moment.

Page 247: jmatter

Chapter 22

Summary

JMatter is a framework for building software applications that embrace the no-tion of domain-driven design: that the essence of a software application is thetranslation of domain knowledge into code; the modeling of the domain into aset of entities with interrelationships. Briefly: many of of those things that EricEvans discusses in his book Domain-Driven Design [5]. But this framework doesmore than embrace these ideas: it is a vehicle for implementing domain-drivenapplications today. The JMatter codebase constitutes a robust and generic imple-mentation 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 todevelop 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, authoriza-tion, persistence, ui, etc..) generically, in a fashion decoupled fromany one specific domain model, these implementations are free to bereused across domains.

The consequences of this reuse are dramatic:

• large time savings

• an application’s codebase shrinks dramatically and becomes manageable

• there’s a clean separation between application development and infrastruc-ture development

• consistent, high-quality applications

237

Page 248: jmatter

238 CHAPTER 22. SUMMARY

This model of development puts into question certain rules about software devel-opment that up until now we’d assumed to be a given, namely:

that the cost of making a change to a software system late in the lifeof a software project is much higher; or conversely that it’s cheaper toimplement changes early on, when less software has been built uponrequirements that may change.

The above rule inherently assumes that much of an application’s codebase is cou-pled to requirements, so that when the requirements change, a lot of code willhave to be thrown away and rewritten:

• GUI forms will have to be revised to reflect a new field

• There will undoubtedly be ripple effects to the database schema

• Queries will have to be revised to take a new field into account

• The authorization system will have to be updated because a new action wasintroduced

And the list goes on. The entire application has to be retrofitted to take the changeinto account.

In JMatter the repercussions are kept to a bare minimum: the database schemaderives from the domain model, as does the user interface, and the authorizationsystem, and the search system, and so on.. All reflect the domain model.

22.1 Looking Forward

What technologies to base a project on is always a difficult choice, and a movingtarget. For example, Java is used in many environments today, but we see a desireto move to languages such as Scala, Groovy, and Ruby. On the other hand, newlanguages may have less mature code libraries, and involve a certain risk.

JMatter strikes a great balance in its choice of technologies. It’s a reality today;it’s built upon a mature platform, a stable set of libraries, Hibernate being oneexample.

Looking forward, we will likely be exploring new languages for the JVM such asScala, Groovy, and JRuby.

These languages will bring about tangible benefits:

Page 249: jmatter

22.1. LOOKING FORWARD 239

• Traits (also known as mixins) are a powerful and missing feature (from Java)that will provide more flexibility in modeling. Internally, in terms of JMat-ter’s own implementation, it will help streamline the implementation evenfurther.

• The functional programming traits of some of these languages promise tobring about improvements in performance via lazy loading, and in threadsafety via immutability.

• Powerful metaobject programming facilities, and the very designs of theselanguages promise to provide the necessary tools to evolve how domainsare specified into a full-fledged domain-specific language.

As one small, concrete example, the Scala language defines the notion of a valueobject via the built-in primitive val. Much redundancy in specifying a domainmodel can be done away with. You are likely to start seeing JMatter move in thedirection of such languages in the coming years.

Page 250: jmatter

240 CHAPTER 22. SUMMARY

Page 251: jmatter

Appendix A

Keyboard Shortcuts

ShortCut DescriptionAlt-‘ Analogous to the alt-tab mechanism for switching be-

tween windows on your desktopAlt-1, Alt-2, etc.. In a window with multiple tabs, switch to the first, sec-

ond, [etc..] tabCtrl-w Closes the currently focused windowCtrl-n When a view of a listing is in focus, a shortcut for the com-

mand New on the listing’s elements type. For example, ifviewing a listing of Persons, instead of right-clicking Newin the titlebar, just press Ctrl-n

Ctrl-f A shortcut that is active in listings, that places the focuson the search field

F12 Invokes JExplose, a feature similar to Apple’s Exposé, thatwill automatically scale and sort all of the windows onyour desktop in order to facilitate the selection and man-agement of multiple windows. This feature can also beinvoked from the Desktop’s context menu (right-click onan empty spot on your desktop to bring up this menu).

241

Page 252: jmatter

242 APPENDIX A. KEYBOARD SHORTCUTS

Ctrl-command When invoking a command that generates a view win-dow: if you find yourself frequently repositioning thegenerated window, then this shortcut is for you. By hold-ing down the Ctrl key while invoking the command (ei-ther clicking on the button or right-clicking on a contextmenu item), then the generated window will be boundto your mouse: it will follow your mouse’s movements.When you find the ideal place to position the newly-created window, just click with your mouse to pin it downinto place.

Shift-Command When invoking a command that generates a view, hold-ing down the Shift key at the same time will prompt howyou’d like the new view generated: in a new window, anew tab, or in place (i.e. replacing current view).

Shift-Click Click on a JMatter internal window while holding downthe shift key to move or drag the window about. This isthe same as dragging the titlebar to move the window, butgives you a much larger surface area to work with. Thisfeature is the same as the well-known alt-click on linuxdesktops.

Ctrl-Scrollwheel In the context of a calendar window, can change the res-olution of the calendar cells from one minute to one hourusing this gesture (for either day view and week view).

Alt-/ Focus on selected item in Class BarCtrl-/ Open currently selected view’s context menu. A key-

board equivalent for right-clicking.Ctrl-I Invoke JMatter’s visual command interface (similar to

quicksilver or gnome-do)Ctrl-q Quit the application

Page 253: jmatter

Appendix B

Database Setup

The JMatter framework taps the power of database systems. JMatter employs theexcellent Hibernate “O/R Mapping” framework which affords it database inde-pendence. That is, you’re not constrained to using a specific database system.Options include PostgresQL, MySQL, Oracle, DB2, Sybase, Informix, SAP DB,and many more.

JMatter is tested primarily with PostgresQL and H2 (see http://www.h2database.

org/), and has been verified to work with Oracle and MySQL.

We recommend either H2: a full-featured, minimal administration, fast, Java-implemented database, or PostgresQL: a mature, stable and open source database.

The JMatter distribution pre-bundles JDBC drivers for PostgreSQL, MySQL, andH2 and hsqldb. If you choose to use a different database vendor, you will need toobtain the corresponding JDBC driver jar file and place it in the jmatter/lib/runtime/jdbcdirectory.

B.1 Configuring your own database for the Contact-Mgr Tutorial Application

B.1.1 Create a Database

We’ll use PostgresQL as an example.

To create a database in PostgresQL, invoke a command similar to this one:

$ createdb -U postgres contactmgr

243

Page 254: jmatter

244 APPENDIX B. DATABASE SETUP

The -U flag is used to specify the name of the user who is creating the database.The username you should use depends on your specific installation (consult thePostgresQL documentation).

You might also want to create a user specifically for this application1:

$ createuser -U postgres contactmgr

B.1.2 Specify the Database Connection Information

Make sure that you’re in the ContactMgr folder before proceeding. Edit the fileresources/hibernate.properties. Modify these three lines accordingly2:

#

hibernate.connection.url=jdbc:postgresql://localhost/contactmgr

hibernate.connection.username=contactmgr

hibernate.connection.password=

If you’re using a database other than PostgresQL, you’ll also need to revise thesetwo lines:

#

hibernate.connection.driver_class=org.postgresql.Driver

hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

Save the file.

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 | Name | Type | Owner

1Both createdb and createuser are programs that come with PostgresQL2Let’s assume for now that the database will reside on the same machine as your application.

Page 255: jmatter

B.1. CONFIGURING YOUR OWN DATABASE 245

--------+---------------------+-------+------------

public | business | table | contactmgr

public | commandrestriction | table | contactmgr

public | complextype | table | contactmgr

public | compositequery | table | contactmgr

public | contactmethod | table | contactmgr

public | fieldrestriction | table | contactmgr

public | folder | table | contactmgr

public | folder_items | table | contactmgr

public | loggedevent | table | contactmgr

public | person | table | contactmgr

public | queryspecifications | table | contactmgr

public | restriction | table | contactmgr

public | role | table | contactmgr

public | users | table | contactmgr

public | usstate | table | contactmgr

(15 rows)

Page 256: jmatter

246 APPENDIX B. DATABASE SETUP

Page 257: jmatter

Appendix C

Working from the SubversionRepository

Credits: this appendix is an adaptation of a document written and volunteered by JMatteruser “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 specific release, look for the specific 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

Page 258: jmatter

248 APPENDIX C. WORKING FROM THE SUBVERSION REPOSITORY

C.2 Directory Structure, Compiling, Running demoapplications

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 file 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 accor-dance with the way any JMatter project is compiled and run.

All the demo applications should be preconfigured to use a local, file-based H2database. If per chance it is not, then simply edit the file resources/hibernate.properties.This file lists sample connection information for a variety of databases, includinghsql, H2, postgresql, MySQL, and OracleXE. Uncomment the one you want andmake sure the jdbc url and credentials are valid and you’re ready to go.

To automate the manual step of exporting your schema, add this hibernate prop-erty:

hibernate.hbm2ddl.auto=create

Page 259: jmatter

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. What’s 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 frameworkhttp://java.dzone.com/news/interview-eitan-suez-creator-jFebruary 2008.

249

Page 260: jmatter

250 APPENDIX D. ONLINE ARTICLES ON JMATTER

Page 261: jmatter

Appendix E

FAQ

This FAQ will be expanded in future versions of this documentation.

1. How do I customize my application’s name in the main window’s title bar?

(a) Edit the file src/applicationContext.xml and look for a comment labeled“TODO: Customize App Name Here”. This is also the place where youcustomize the page size of listings in the user interface (the default is15).

2. How do I add or remove a command to all my model objects regardless oftype?

(a) The base class for all JMatter model objects is AbstractComplexEObject.When JMatter introspects commands, it recurses up the type’s inheri-tance hierarchy. To add a command to all model objects, edit Abstract-ComplexEObject and add a new command like you would any modelobject (marked with the @Cmd annotation). Likewise, to remove an ex-isting command, say for example the “Export to XML” command, sim-ply comment out or remove the @Cmd annotation on the correspond-ing method.

251

Page 262: jmatter

252 APPENDIX E. FAQ

Page 263: jmatter

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 linkfrom the jmatter.org web site). A fraction of the price of the book goes backto the developers.

4. If you’re in the business of developing commercial software solutions, buy alicense of JMatter. Or get your company to purchase licenses. These licensesare priced ridiculously low (I’ve estimated that the break-even point forJMatter is approximately one week into your first project) and are royalty-free.

5. Join the mailing list! Discuss features, suggest design improvements, be-come a part of our community

6. If you’re a software developer, contribute bug fixes, features, enhancements

7. Donate directly (see http://jmatter.org/pages/donate)

253

Page 264: jmatter

254 APPENDIX F. CONTRIBUTING TO THIS PROJECT

Page 265: jmatter

Appendix G

A Desktop within a Desktop?

One cannot help making the observation that the applications we’re developingare desktop-like in nature. We end up having a desktop running within a oper-ating system’s desktop. The features of our applications’ desktops are in manyways a replication of the features already built into our operating systems. Themain difference being that instead of managing files and folders, we’re in a senseextending the desktop to allow for the management of business objects, in anycombination we choose. When we wrote our contact manager, that combinationhappens 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. Takefor example the new MacOS reborn in v10.0. Beautiful graphics, colors, lots ofapplications we can run. On the surface, it all looks and feels like a virtual gardenof eden.

I see a much colder, harsher landscape. I see a landscape of islands of processesthat communicate with one another hardly ever. If they do, it’s via messagesin a bottle. One of the few ways for such applications to talk to one another isvia the clipboard. You copy (or drag) some text or maybe an image from oneapplication and paste it (or drop it) onto another. That’s essentially the extent towhich applications can communicate in an ad-hoc basis.

Let’s go a little further though. Let’s think about the code required to implementan email application, a web browser, a word processor, our finance application,etc.. Each application must fend for itself: each one has to build its own searchfeatures, its own mechanism for persisting information, its own user interface, itsown mechanism for calendaring, for validating information, etc..

255

Page 266: jmatter

256 APPENDIX G. A DESKTOP WITHIN A DESKTOP?

This is not entirely true; the operating system does provide certain services thatany application can avail itself to: reading a file, writing a record to a databaseperhaps, opening a socket, creating a button, a text field. Terrific. It’s a start.

Again what we see is that the notion of orthogonal services that can be providedto all the applications that run in an operating system is missing. If the ideasembodied in JMatter were to be applied to an operating system, then we couldcreate a virtual world where our software applications would suddenly and dra-matically shrink in size. The reason would be simple: all you’d have to do tobuild your application is define your model objects. Half of them would alreadybe defined in other applications and you wouldn’t be writing them from scratch:you’d be composing applications.

Contributors to such an operating system might add new and interesting behav-iors on existing objects. Maybe the ability for an email message object to receivean image object, maybe the ability to submit your financial information electroni-cally to your accountant. You’d be able to file email messages in folders that youplace on your desktop. The notion of multiple separate applications would van-ish. They’d all run under a single application, managed by the operating system.When you’re performing a search, you’ll be searching your entire virtual worldin the same way, regardless of whether you’re looking for a piece of text in a fileor an email message, or maybe looking for a financial transaction in a specificelectronic account.

We wouldn’t need such large hard drives, and for many tasks, would not requiresuch a fast microprocessor. Each application wouldn’t request of the operatingsystem a chunk of 50 megabytes to run in; your memory footprint would drop.

When you perform a software update, you’ll be inheriting new orthogonal ser-vices: new capabilities that all of your objects would inherit, not just a singleapplication.

This is my vision for operating systems. It turns out these ideas are indeed veryold ones. What I’m 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 JMatterwill be integrated into our operating systems. Until then, enjoy smashing yourcompetition to bits with JMatter.

Page 267: 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 Sys-tems. Addison-Wesley Professional; 1st edition (March 29, 2000).

[3] Simon Lewis. The Art and Science of Smalltalk. Prentice Hall; 1st edition (May11, 1995).

[4] Gamma, Helm, Johnson, Vlissides. Design Patterns. Addison-Wesley (1995).

[5] Eric Evans. Domain Driven Design. Addison-Wesley (2004).

[6] David R. Heffelfinger. JasperReports for Java Developers. PackT Publishing(2006).

257


Recommended