 |
Architecting Applications 1: the model
Posted by zixle on January 18, 2006 at 04:33 PM | Comments (18)
While in Russia (see Shannon's blog) I wrote a long blog on undo, actions and various other things. At the time I felt this a bit long for a blog and so it languishes in my unposted blog queue (with many others, but that's a different story). I really liked the idea of writing a series of blogs centered around a real app though, hence this blog and hopefully more to follow.
As part of the series I'll cover architecting the app (this blog) including using beans persistence as a way to save the model, Actions, Undo, the need for an application class, data binding and various other things that come up.
In writing a series of blogs around an app I thought it important that the app be compelling enough, but not too big such that you become bogged down in all the implementation details. So, I needed something small but not too small as to be trivial. I may have erred on the side of trivial, none-the-less the concepts and points are still worth while to explore.
If you're like me you have a ton of passwords for various machines and web sites that you're expected to remember. As an added wrinkle each password should be unique and unreadable, ugh! Added together this makes it nearly impossible to remember all your passwords. For this series I'm going to stick with a simple app that manages passwords. A Java based app that stores passwords has the added bonus of being able to run from a USB memory stick on the three major platforms: Windows, OS X and Linux. I realize there are loads of commercial apps in this space that undoubtedly go way beyond what I'm going to do. None-the-less such an app is at least interesting and not too complicated (at least as far I'm going to take it).
Here's roughly where I'll end up when done with the series:
A password store will need to be encrypted, I'm going to leave that out as I don't want to worry about the legal issues of such a blog.
There are various approaches to designing apps. Some of the more popular patterns are model-view-presenter , presentation model and model-view-controller. I'm a fan of the latter, and especially for an app of this size. In creating any app you'll need to make the desicision as to which approach is applicable to your design space and requirements.
Model-View-Controller dictates that you have a clear model for your application. The Controller coordinates keeping the view and model in sync. The model for Password Store is going to be trivial. It'll consist of a List of PasswordEntrys. Each PasswordEntry will have the following properties: host, user and password. PasswordEntry will be a proper bean in that it'll communicate changes to listeners by way of a PropertyChangeListener notification. That means any time you change a property all PropertyChangeListeners are notified of the change. Here's the code for setting the host property:
public void setHost(String host) {
String oldHost = this.host;
this.host = host;
if (propertySupport != null) {
propertySupport.firePropertyChange("host", oldHost, host);
}
}
The methods for setting the user and password follow the same pattern. This may seem like a lot of boilerplate code for something so trivial, and I would agree. I'll try and address that in a later blog.
The List of PasswordEntrys will be managed by a PasswordModel. PasswordModel will initially expose the List as modifiable. I suspect this is a bad long term decision, but I'm going to stick with it in hopes of keeping the API simple and not getting bogged down in details. Here's the code:
public class PasswordModel {
private List passwordEntries;
public PasswordModel() {
passwordEntries = new ArrayList(1);
}
public List getPasswordEntries() {
return passwordEntries;
}
The biggest downside with choosing List is that it doesn't notify listeners of changes to the contents. This is key, and something I'll touch on later.
An added bonus of making the PasswordEntrys proper beans is that I can save and restore the PasswordEntrys using beans persistence. Here's the code:
public void load(String file) throws IOException {
BufferedInputStream inputStream = new BufferedInputStream(
new FileInputStream(file));
XMLDecoder decoder = new XMLDecoder(inputStream);
List entries = (List)decoder.readObject();
decoder.close();
passwordEntries.clear();
passwordEntries.addAll(entries);
}
public void save(String file) throws IOException {
BufferedOutputStream outputStream = new BufferedOutputStream(
new FileOutputStream(file));
XMLEncoder encoder = new XMLEncoder(outputStream);
encoder.writeObject(passwordEntries);
encoder.close();
}
At this point we have the model, which by itself isn't all that interesting. Next time around by the end of the blog we should have something that you can at least run.
-Scott
Bookmark blog post: del.icio.us Digg DZone Furl Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment
-
Great to see someone addressing this. I'm looking forward to the read the next entries.
Our trading applications get relativley large, and in our architecture we have models similar to the one your depicting. It seems however we've dumbed it down slightly, having a concept of an Operation for manipulating models. The model simply holds state. In our case we're able to unit test our headless layer, constructing tests of sequences of operations. Any given sequence will result in a deterministic state in the model.
Posted by: hkverneland on January 19, 2006 at 09:34 AM
-
re:
The biggest downside with choosing List is that it doesn't notify listeners of changes to the contents. This is key, and something I'll touch on later.
You might lookat at the Glazed Lists project. Glazed Lists can provide Lists that have notification of changes built in. They also provide easy sorting and filtering of lists.
Posted by: parishd on January 19, 2006 at 11:10 AM
-
I'd really like to hear your thoughts on undo, actions, etc. Please publish that blog entry.
Posted by: neilweber on January 19, 2006 at 12:20 PM
-
parishd,
You might look at at the Glazed Lists project.
Glazed lists is pretty cool and does indeed solve some of the problems I've mentioned.
I forgot to mention that I wanted to limit myself to what's in core. Once I finish doing the initial version I'll explore replacing parts with open source projects.
-Scott
Posted by: zixle on January 19, 2006 at 03:32 PM
-
neilweber,
I'd really like to hear your thoughts on undo, actions, etc.
Thanks for the feedback! The interesting parts of the unpublished blog you're referring to will make their way into this blog:)
-Scott
Posted by: zixle on January 19, 2006 at 03:34 PM
-
General weakness of Swing is lack of articles and tutorials talking how make your app. Not how to add component to panel, not how to change renderer in JList. This is rather simple technical details presented in countless webpages. I'm talking here about things like:
- how to make good architecture of your Swing app
- how to do efficient background task
- how to resolve problem of notyfying gui about undergoing changes (EDT, here I come...)
- more about this Action thingie
- how to minimize burden of very verbose way of creating Swing based GUI
- and so on, and so on
This knowledge is absent or fragmented in Sun Swing Tutorials or just isn't presented in comprehensive way. In web developers world noone is bulding any non-trivial app without some kind of framework - place it JSF, Tapestry, Struts, whatever you want. Desktop side is left screaming, frightened and unsure here ;-). I'm exaggerating a lot, of course - there are few Action frameworks, etc. but no solid, well defined and complete solution comes to my mind. Anyway, Swing is apparently taking second breath over last year or so, so I think that there is a hope for me (I'm so bored of making web apps...). Java is nice language, Swing is good UI toolkit - probably best I've had pleasure deal with (I know quite a lot, my first GUI apps were made on Amiga... oh so long time ago :p).
Soz for my english, I'm tired and cold (temperature is -20 celsiuss degree here.. outside of course :x)... Many wishes to you Scott and whole Swing team.
Posted by: spk on January 20, 2006 at 02:39 AM
-
spk,
I hope you'll find this series of blogs helpful. Interacting with separate threads is something I'll get to a bit later on in the series.
Thanks for the feedback!
-Scott
Posted by: zixle on January 20, 2006 at 08:03 AM
-
Hey Scott.
Everyone is right: this is an excellent topic, and it should be included in the tutorial online. End of story!
I have comment about the simple method body you posted for setting the host property. You posted this:
public void setHost(String host) {
String oldHost = this.host;
this.host = host;
if (propertySupport != null) {
propertySupport.firePropertyChange("host", oldHost, host);
}
}
Supposedly, if you fire an event with 2 null values, this indicates to your clients that an "arbitrary set of properties" has changed in your bean. So I was going to just mention that you might re-work the code to check for this condition so you don't fire needless events.
And I wanted to add my observation here: The term "JavBeans Event Model" applies here. But the thing about this and even one or two other JavaBeans/Swing/AWT machinery-related concepts is that they don't really come together as a cohesive standard until you merge the JavBeans spec, the tutorial, and the API all together. It can be hard to know all the intended usages and effects if you haven't really read all over the place. And one spec merges with another architecture until you discover how it is all working.
But anyway, your topic is nice! You should see what Bob Eckstein would say about all this in his topic in the "Engineer's Sandbox": Swing Networking Question/Challenge. I had trouble posting there and after talking with him I wound up sending him an email with a bunch of comments, but I think he was too busy to respond! I never heard back.
Vada facile.
Ciao!
Steev Coco.
Posted by: steevcoco on January 21, 2006 at 01:55 PM
-
any idea how often this "series" of blog entries will be updated?
Posted by: codecraig on January 24, 2006 at 09:10 AM
-
I've done a Swing framework that can be found here:
https://tframe.dev.java.net/
It basically uses a simple Mediator pattern.
I've got lots of util classes for things like:
* loading icons from a jar or WebStrart class loader
* JTable that supports sorting
* pre-built ActionItems with icons and key strokes as defined in the 2nd edition Sun L&F GUI guide
* Toolbar that has the vertical or horizontal spacer. (Can't believe it isn't standard but oh well)
I'm a Swing guy so my web page really stinks but I'm trying to get time to clean it up. It basically creates a simple SDI framework with pre-built items.
Happy to send folks example code if they want to see it.
Posted by: cupofjoe on January 24, 2006 at 05:44 PM
-
It would be also good to cover handling application/applet preferences technique. All in all it' a very useful track... looking forward for the next entries.
Posted by: zak_d on January 25, 2006 at 10:20 AM
-
Hi Steev Coco,
Supposedly, if you fire an event with 2 null values, this indicates to your clients that an "arbitrary set of properties" has changed in your bean.
That is certainly true and is worth guarding against. Thanks for pointing it out!
but I think he was too busy to respond! I never heard back
I believe Bob was at documentation offsite for a week or so. Hopefully he's responded to you by now.
-Scott
Posted by: zixle on January 26, 2006 at 06:58 AM
-
Hi codecraig,
any idea how often this "series" of blog entries will be updated?
I'm going to try for every two weeks, only time will tell how well that works out.
-Scott
Posted by: zixle on January 26, 2006 at 06:59 AM
-
zak_d,
It would be also good to cover handling application/applet preferences technique.
That's certainly a good idea. I'm initially going to focus on standalone app, but if time permits I'll go over how the app can be webstarted and what effects that has on the app.
-Scott
Posted by: zixle on January 26, 2006 at 07:01 AM
-
Supose the above window is spawned by a parent whose job is to keep password lists for a number of monikered identities. Once a moniker to maintain is selected, the window at the top of this page would pop up. It would be natural then to have a list of UserPasswords beans (one per user) in the parent window. When your window comes up, it would be given an instance of:
public class UserPasswords {
private List passwordEntries;
// each entry would contain [host,userName,password]
private String moniker;
// accessors left out for brevity
}
Now, obviously, this app is a very simple case. But, my question is, "How, in general, do you tie fields from a bean to the visual controls on the screen?" When constructing my latest GUI (using Swing), I was dismayed to find no easy way to map the hundreds of fields from my Hibernate-manufactured beans to my nearly-as-numerous on-screen controls. I ended up writing a reflection-based mapper where the 'name' property of Swing field corresponded to the fully-qualified reflected name of bean property. I'd did not like using reflection and recursion to perform the often-used function of moving data from the bean to the Swings fields and vice-versa, but I could not find an alternative. What is the way I should have done this? Could you increase the scope of your article to include this topic?
Posted by: derekbennett on January 27, 2006 at 07:31 AM
-
derekbennett,
You're referring to data binding. There are a number of options for Swing apps. There are two versions in swinglabs, JGoodies binding, Oracle's jclient and various others. Data binding is certainly a hot topic and I'll touch on it at a later date. For the first round of this article I'm restricting myself to just Swing. After that I'll explore other alternatives.
Thanks for the feedback!
-Scott
Posted by: zixle on January 27, 2006 at 08:21 AM
-
I wanted to clarify my last point. By After that I'll explore other alternatives I meant other open source projects that build on Swing, such as SwingLabs.
-Scott
Posted by: zixle on January 27, 2006 at 08:25 AM
-
CORRECTION
CORRECTION
I'm terribly sorry everyone: I posted bad information above about checking for null values when firing JavaBeans events. What I posted was wrong, and I wanted to try to at least post a correction to it so people wouldn't have the wrong advice.
I just read Scott's post about Changes to Actions in 1.6 and I read through the Beans spec to find the relevant part, which is actually thus, relating to event values when firing an event -- not as I posted:
Null values may be provided for the old and the new values if their true values are not known.
An event source may send a null object as the name to indicate that an arbitrary set of if its properties have changed.
In this case the old and new values should also be null.
It's an important difference and I hope nobody got the wrong information from that post. Sorry about that, whoever was reading. Hopefully this can help clear up any mistaken information people might have gotten as a result.
And sorry, Scott especially, since you have hosted this forum for discussion.
This comes from the end of section 7, Properties, Class PropertyChangeEvent.
While I obviously am not the final authority on any JavaBeans Specification information, it is not helpful to post bad information... I hope no one implements incorrect behavior and winds up with some problem.
Again: sorry about that.
Steven.
Posted by: steevcoco on February 15, 2006 at 10:15 AM
|