HEAD PREVIOUS

Chapter 4
A Zero-Code Contact Manager

Let's write our own version of the contact manager. The point of this chapter is to lay the foundation for writing JMatter applications. You will learn how to create and setup a project, what information goes where, some of the configuration files and their role in a JMatter application. As the title of this chapter indicates, we will not have to write a single line of code to implement our 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 for ContactMgr), so as not to conflict with the existing demo version of the contact manager application.
figures/new-project-ui.png
Figure 4.1: New Project User Interface
We have the option of creating a standalone or dependent project. It doesn't really matter at this point. Let's go with dependent15. Go ahead and click on the Create Project button. This action will launch an ant target that takes our input and creates a complete directory structure for us. If you 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's base directory:
$ cd ../CM
$ ls
build.xml   doc/   resources/   src/   test/
JMatter creates the directory structure for your project, along with its own ant build file.

4.2  The Schema

We would normally proceed by modeling our application: identifying the entities, and implementing them as Java classes. With JMatter however, things are a little different. JMatter was designed to be a framework for building business applications. As such, JMatter predefines a number of common types of business objects, including persons, their contact information, addresses, and businesses. In this chapter we'll reuse the predefined implementations of Person and Business, whose fully-qualified class names are com.u2d.type.composite.Person and com.u2d.type.composite.Business, respectively.
Before we generate our schema, we need a way to communicate to JMatter the various types of objects we would like to persist. We typically do this by adding an annotation (@Entity) directly on the model classes that we define. However in this case, since we're using pre-existing model classes, we do this by editing the underlying template, src/persistClasses.st, directly:
..
<value>com.u2d.type.composite.Person</value>
<value>com.u2d.type.composite.Business</value>
..
We simply add the fully qualified names of the two classes Person and Business to the 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 generates a Hibernate database mapping file, and finally asks hibernate to generate the 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 it contains these tables. By default, JMatter uses the H2 database, which is lightweight and requires no work on your part 16. By default, JMatter created the database CMh2db in the db/ subdirectory of your project. To view its contents, you can use the H2 web-based console. First you must start the H2 server, with this command:
$ java -cp ../jmatter/lib/runtime/jdbc/h2.jar org.h2.tools.Server
Then point your web browser to http://localhost:8082/ and login to the database (default username is sa, and the password is blank). These details are much better documented by 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 also need to specify which types to expose to the user interface via the Class Bar. This step is not really necessary, because we can edit (in this case, add types to) the classbar directly from the user interface. Feel free to skip this section if you wish.
The way to predefine the default classbar items is to edit src/class-list.json:
{
  "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 format17). When the application starts up, the file will be unmarshalled back as a Folder object. JMatter will detect that our database is empty (it contains no classbar) and will automatically persist the folder. Each user has his or her own class list. The xml file serves as a template. This is useful since many applications have multiple users, with different 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 the resources/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 and exercise it: create new person objects, etc.. (see figure 4.2).
figures/CH4-1.png
Figure 4.2: Classes organized into two subfolders: Manager and Administrative

4.5  Custom Views Revisited

In subsection 3.2.5.1 I had mentioned that the Class Bar can be customized directly from the User Interface. 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't have an icon, and thus shows up with a question mark icon).
  1. Click on the Manager folder in the Class Bar
  2. Drag Contact Methods to the empty area inside the Manager folder in the class bar
We have just added a type to the class list. Our class bar should now resemble figure 4.3.
figures/ClassBar-1.png
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 are probably very similar to your existing project conventions. Here is a summary of these conventions:
  1. Source code resides in the src/ directory
  2. You will 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 resides in your project's base directory
  4. Your source code is compiled to the target directory build/classes
  5. JMatter generates Hibernate mapping files for persisting your domain objects; these files by convention bear the suffix ".hbm.xml" and also are written to the build/classes directory
  6. When deploying your application with Java Web Start (see chapter 18), the distribution file is placed in the dist directory
  7. The doc directory contains a simple README file, serving as a quick reference or as simple setup instructions to help you get started on a new project. You are also urged to use this folder to place any relevant documentation for your project.
  8. The test directory is created for you to place JUnit tests you write to ensure that your code and business logic is correct and bug-free

4.6.2  Ant Targets

You don't need to memorize the names of the ant targets that we invoke (e.g. ant run, ant schema-export); simply type:
ant -projecthelp
to view a list of all the defined targets: their name and description (Of course, if you're running GNU/Linux and have bash smart completion turned on, simply pressing the tab key will display a list of valid ant targets).

4.6.3  A Peek at the Source Code

Open the file Person.java in a text editor or IDE18 (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 Name class is composed of the parts that make up a name: prefix, first, middle, last, and suffix.
If you dig a little deeper, you will see that Contact.java defines these fields:
private final USPhone _workPhone = new USPhone();
private final USPhone _mobilePhone = new USPhone();
private final USPhone _fax = new USPhone();
private final Email _email = new Email();
private final USAddress _address = new USAddress();
private ContactMethod _preferredContactMethod = new ContactMethod();
Here we see that JMatter has a built-in understanding of types such as a US Phone number, an Email address, a US Address and a Contact Method.
If you inspect the generated database schema for our application, you will not find a database table to hold contact information or addresses.
The reason is that with JMatter, you have the choice of modeling a field either as an association or as an aggregation. In the context of the class Person, Contact and USAddress are modeled as aggregates, and so are treated in a manner similar to value fields such as the work phone or email address. The fields that make up the 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 book Domain-Driven Design [5], then you're already familiar with both Aggregates and Value Objects.
We'll learn more about ways of modeling relationships between objects in the next chapter. 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-ui command;
  2. We are aware of two configuration files src/persistClasses.st and src/class-list.json and 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 our application: 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 to get a chance to write some code in the MyTunes music application.

HEAD NEXT