HEAD PREVIOUS

Chapter 6
A Conference Manager

In this chapter we're going to build a conference management application. The idea for this application came to me while a speaker in a real series of conferences: The No Fluff Just Stuff Java and Open Source symposia.
Here are some of the features of JMatter that I will be introducing in this chapter:
  1. Reinforcing our understanding of modeling a domain according to the conventions of the JMatter framework
  2. More metadata
  3. How to use an 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 business 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
  4. We note that a speaker has a name and a biography, as well as a list of presentations
  5. A presentation appears to have a title, an abstract, and an association back to the speaker
Let's now take a look at upcoming or past symposia. Looking at the list of past symposia, I see that the Rocky Mountain Software Symposium took place during the weekend of November 11 2005. Click on a specific symposium and you'll see a 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 that conferences will often have multiple sessions taking place at the same time, but at different presentation rooms.
So we can derive from this little stroll through the NFJS web site that some of the basic entities in a conference management system include a Speaker, a Talk (or Presentation), a Session, a Symposium, and probably a Room. We also have a fairly good understanding of how these types interrelate. We can say that:
  1. A conference management system is essentially a list of symposia
  2. Each symposium consists of a list of sessions
  3. A session is essentially a talk given at a 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 the task of planning a new symposium, perhaps with scheduling sessions, printing agenda and other materials needed for the conference.

6.2  Setting up the Project

Setting up our project should be a familiar task by now. The demo application in JMatter that corresponds to this chapter is called Sympster.
$ cd jmatter
$ ant new-project-ui
...
$ cd ../Sympster
Go ahead and setup your project in your favorite IDE (see section 5.2). We proceed by writing our model classes.

6.3  The Model

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

6.3.1  Type Icons and Config File Setup

For each type, we need to:
  1. provide a pair of icons, name them typename16.png and typename32.png, and place them in resources/images
  2. for startup ease, specify the fully-qualified type name in src/class-list.xml

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 com.u2d.persist.Persist;
@Persist
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 field so far: the symposium's name. We have a getter method for the name field, and our title() method. The new bit is the optional implementation of the static method pluralName(). The default derivation of the plural name for Symposium is not intelligent enough in this case so we provide it. We've already seen how a type's plural name is used in JMatter's user interface: each entry in the classbar displays it; the titlebar for listings also displays the list item type's plural name.

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 com.u2d.persist.Persist;
@Persist
public class Speaker extends AbstractComplexEObject
{
   private final StringEO name = new StringEO();
   private final StringEO title = new StringEO();
   private final TextEO bio = new TextEO();
   private final ImgEO photo = new ImgEO();
   
   private final RelationalList talks = new RelationalList(Talk.class);
   public static Class talksType = Talk.class;
   public static String talksInverseFieldName = "speaker";
   public static String[] fieldOrder = {"name", "title", "photo", "bio", "talks"};
   
   public Speaker() {}
   public StringEO getName() { return name; }
   public StringEO getTitle() { return title; }
   public TextEO getBio() { return bio; }
   public ImgEO getPhoto() { return photo; }
   public RelationalList getTalks() { return talks; }
   public Title title() { return name.title(); }
}
We see that speakers have a name, title, short biography, and a photo. Speakers also have a portfolio of talks, modeled as a list, or one-many relationship. Since I plan to make this relationship bidirectional (a talk will have a reference to its speaker), I also specified the inverse field's name. We also see the fieldOrder metafield 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's name. In this instance I chose to keep the name simple as a single atomic field.

6.3.4  The Talk Class

We're still in the process of laying the foundation for our application. Here's the code 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 com.u2d.persist.Persist;
@Persist
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 event when 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;
import com.u2d.type.atom.StringEO;
import com.u2d.persist.Persist;
@Persist
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 com.u2d.persist.Persist;
@Persist
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);
   }
   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 the time span. TimeSpan is yet another basic type provided by the framework. It's a combination of a date-time field and a duration. You can also think of a time span as having both a start time and end time fields. Actually, this is how its default renderer and editor depict it.
The title() method is also somewhat interesting as it attempts to concatenate the time span along with the 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 written one class at a time and each time ran our application, thus building our application more incrementally. This in fact is a very good practice and a highly recommended one. Feel free not to follow me to the letter here.
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 to figure 6.1.
figures/NFJS-1.png
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 a speaker and assign him or her a photo. Since a speaker has a list of talks, you can create and associate a talk to your speaker very simply by clicking the plus (+) icon, which is a popup menu, and selecting the New action, and then entering the information about the talk. The association will be made for you automatically. Alternatively, you can create a talk separately and then drag and drop the talk onto the speaker's talks listing. Figure 6.2 is a snapshot of my screen after creating a speaker and a talk.
figures/NFJS-2.png
Figure 6.2: A Speaker and Associated Talk
Now that we have created a talk and a room, go ahead and create a session object. The timespan can be edited by specifying the date and start and end times. Notice that the date editor provides a date picker to facilitate entry. The time editors likewise attempt to facilitate entry by providing small spinner arrows for incrementing and decrementing the hour and minute fields. To associate a talk and a room, again you have two choices:
  1. Drop a talk onto the talk field of the session object (and similarly for the location field, drop a room object), or
  2. Right-click Browse, Find, or New to browse and select an existing talk to associate to this session, to query for and select a talk, or to create a new talk and then associate it to the session in question
Here is a snapshot of my screen after creating and setting a session:
figures/NFJS-3.png
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 of objects in our system: color-coding. Here's an example of how to specify this metadata:
public static Color colorCode = new Color(0xffff00);
Just add the above line to any of your model classes (Room, Talk, Speaker, and so on) using a different color value for each, of course. The titlebar for each object will automatically be painted with a gradient background that starts with the specified color. Also, type listings paint the background color of alternating lines using that color code combined with a semi-transparent alpha value. This should help users quickly distinguish various listings or types of objects in your user interface.

6.4.2  Speaker's Photo for Speaker Icon

We have a nice little icon representing a speaker. However, we have an even nicer one, and one that could help distinguish between speakers: their photo. Can't we 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 delegate the 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 look at. Figure 6.4 shows two views of the speakers' listing along with a maximized view of Jason Hunter, a long-time NFJS speaker.
figures/NFJS-4.png
Figure 6.4: Speaker Icon using Photo Property
By opening other listings and other types of instances we can also quickly see the color-coding in effect. These are small, nice, and valued enhancements to our user interface.

6.5  Calendaring

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

6.5.1  How JMatter Models Calendaring

The JMatter framework defines three main types of objects that work together to provide calendaring features:
  1. Calendar Events
    These are basically items that one puts on a calendar. A meeting is a calendar event, for example. A visit between a physician and a patient is another example. Here's a third example: a session at a conference.
  2. Resources, or Schedulables
    As its name implies, a Resource is something that can be occupied or consumed for a span of time. In our example, a room where a presentation is given is a resource. In the code, JMatter calls them schedulables. In a physician's clinic, the physician becomes the resource.
  3. Grouping of Resources, or Calendarables
    Finally, it's important to get a view of how multiple resources are utilized in time. We'd like to be able to see what sessions are going on at the same time in six different rooms, so we can pick which presentation we want to attend, for example. A nurse would like to see which physicians are available during a 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 and so each one will have its own calendar. Each room will have its own schedule.
Technically, we need to extend our model to make this work in the field: symposia can take place in different venues. One could take place at a hotel in New York City, another at a convention center in San Francisco, and a third could be taking place at a university campus in Austin. Each venue would then have its own list of rooms where presentations are held.
For now we're going to keep the venue constant. We'll extend the model to support 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 to our 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 can proceed 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;
  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 corresponds to its timespan, so that JMatter knows how to display sessions in a calendar 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 need to provide the name of the schedulable field on Session: location.
The third requirement, the calTitle() method could have been made optional but it is required by JMatter at the moment. It gives you a chance to specify a title for a Session object that is more appropriate in the context of a calendar. For example, the calendar will make obvious the time and duration and location of the session, so you might not want to repeat that information in the title. In this case, we specify the 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
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 resources that this calendar maintains. If each symposium had its own venue, the implementation would simply have been:
return getVenue().getRooms();
In our case, we decided to keep our venue constant so we return the entire list of rooms.
The second requirement is to provide the default calendar event type, which again is Session.
That's it. We're done.

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 Calendar. This command was inherited by CalendarEO. We see a calendar widget, similar to the one shown in figure 6.5.
figures/NFJS-5.png
Figure 6.5: Symposium Calendar, along with a few Sessions
Feel free to explore this widget. It has a few useful features:
  1. A week view and a day view
  2. The ability to view the calendar using a time resolution of 15 minutes, 30 minutes, or 60 minutes per row
  3. The ability to navigate to the next day or week by clicking on the navigation arrows (in day view, you'll be navigating to the next or previous day, in week view, you'll be navigating to the next or previous week)
  4. A mini month calendar, for quickly navigating to a specific date in another month or year
  5. A date navigation text field, to quickly navigate to a specific date by simply entering it and pressing enter (e.g. 10212004 will take you to Oct 21 2004)
  6. The ability to toggle any schedule on or off the calendar
  7. You can create a new session at a 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 specific talk by simply dropping a talk onto a cell in day view
  9. You can alter the default session duration by right-clicking on the Session class'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 onto another cell
  11. You can open an existing session by double clicking on its representation's titlebar in the calendar
  12. You can invoke any commands on a session displayed in the calendar by right-clicking on its titlebar
I think you'll agree that here again, JMatter provides tremendous leverage. The designers of the JMatter framework are reusing this calendar across different applications that span entirely different business domains. As the features of this calendar improve, all JMatter applications will inherit these improvements. One more time we ask you to compare the effort required to build such a feature traditionally into an existing software application and what it took to integrate scheduling into Sympster here.

6.5.4  Inheritance vs Interfaces

In order to gain the benefits of calendaring, we had to extend existing classes in our system. Luckily, our Session, Room, and Symposium did not already extend another base class. Designing by inheritance has its problems in a world where multiple inheritance is not supported. But you don't have to be locked in to it.
It turns out that JMatter does not require that you extend ScheduleEO or CalendarEO to obtain these benefits. You can implement the Calendarable and Schedulable 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 little indeed. All they do is instantiate a Calendar and Schedule object respectively, and expose an accessor method on it. That's basically it.
At the moment, the same cannot be said about a CalEvent. We are required to subclass CalEvent. As we refine JMatter's calendaring feature further, we expect this requirement to be removed21.

6.6  Inheritance-Based Polymorphism

Let's discuss how we would revise our application to accommodate symposia with different venues:
  1. Define a new field on Symposium called venue
    The goal is for a venue to be a base type for multiple specializations, such as a Hotel, a Conference Center, or a Campus (each of these three would be concrete implementations of a Venue)
  2. Define the base type Venue
    At the very least, a venue should have a name and a list of rooms. So Venue would likely include two methods: getName() and getRooms()
  3. Revise the implementation of Symposium.schedulables() to return venue.getRooms()
  4. Update our schema
  5. Possibly add one or more of these new types to one of our Class Bar subfolders (or edit the Class Bar directly from the GUI)
This particular situation lends itself nicely to implementing polymorphism via inheritance. 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 ConferenceCenter. Here is Hotel:
public class Hotel extends Venue
{
   public Hotel() {}
}
Hotel is ready to be extended with specialized behaviours. We can similarly define Campus and ConferenceCenter. We can distinguish these three types by the icon we choose 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 joined subclass inheritance mapping strategy.
And we should be ready to check out our application:
$ ant run
I added Venue to the class list. Remember that Venue is an abstract base type. Figure 6.6 shows two things:
  1. Right-clicking Browse on Venues in the Class Bar will perform a polymorphic query and return a listing including hotels, campuses, and conference centers.
  2. Right-clicking New on Venues will prompt the user to select which concrete type they would like to instantiate. This is baked in to the user interface. When associating a venue to a symposium, right-clicking New, Browse, or Find on the symposium's venue association field will do the right thing.
figures/NFJS-6.png
Figure 6.6: Sympster Extended with Venues
JMatter supports both inheritance-based polymorphism (as shown in this example) and interface-based polymorphism.

6.7  Interface-Based Polymorphism

We are taught that interface-based modeling is preferred over models that do not employ interfaces. I concur. I'd like to demonstrate how to do interface-based modeling in JMatter.
As an illustration, let's extend our Sympster application further. Right now, we can define a symposium, speakers, their talks, and we can schedule sessions. A session is defined as a talk given at a specific date and time, and with a specific duration, at a specific location.
I'd like to broaden the definition of a session to include events other than speakers' presentations. What about BOF's (Birds of a Feature session) for example? Or maybe a panel discussion including a number of participants. At NFJS symposia, we actually hold informal BOFs with 2-3 participants where we discuss a particular topic.
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 does and BOFs will too. I still want to define this interface as it serves as a mechanism for 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; 
import java.awt.Color;
-public class Talk extends AbstractComplexEObject 
+public class Talk extends AbstractComplexEObject implements Event
{
  private final StringEO title = new StringEO();
  private final TextEO talkAbstract = new TextEO();
As you can see from the above diff, all I had to do was specify that Talk implement Event.
Finally, remaining is broadening Session's definition. Rather than define an association to a Talk, we'll revise that to be be an association to an Event. I won't show you 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 in our application:
figures/listing_events.png
Figure 6.7: Polymorphic Queries: Listing Events
JMatter models the polymorphic association using Hibernate's implicit polymorphism mechanism, otherwise known as *any* associations.
figures/creating_events.png
Figure 6.8: Polymorphic Instantiation: Creating a new Event
JMatter will prompt the user whether they wish to create a talk or a BOF.
figures/events_calendar.png
Figure 6.9: Events Calendar
We see two events on this calendar. The first is a talk on JMatter, and the second is a BOF on Programming. :-)

6.8  Summary

I hope you enjoyed this chapter. We didn't have to work too hard and yet we developed a fully-functional conference manager.
In summary, new features of JMatter covered in this chapter include:
  1. type color coding,
  2. using an image 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 leverage we derived from JMatter in this application:
/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 of developing 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 demo application, the one referenced in the introduction. We'll be focusing on JMatter's support for objects with lifecycles.

HEAD NEXT