Last Updated 3/31/01- Go Back
Problem Definition, February 22 Meeting
Iteration 1, March 1 Meeting
Iteration 2, March 8 Meeting
Iteration 3, between meetings on March 10
Iteration 4, March 15 Meeting
Iteration 5, March 29 Meeting
Introduction
This series of JSL meetings will focus on Framework Patterns. See "Patterns" in Frameworks. The original problem statement from a JSL email was:
PROBLEM - Overall our products are doing well in the marketplace but we know we can do better. Our products all use J2EE. Most of our J2EE components are business logic. There are hundreds of them. They have become a subsystem in themselves, but they are only slightly organized. We are finding it harder than we'd like to get them to work together cohesively. Our designs feel awkward, kinda forced, and are usually the result of bottom up organic growth.
We have quality problems too, and suspect they are related to inadequate architecture. Changes in one component too often cause bugs elsewhere. Most bugs are not caught until Integration Testing, and we are finding way too many bugs in beta.
Also, things are not modular enough to do localized releases. Instead we have to do a release every 6 months or so of the whole product, after lots of testing. We are also seeing low component reuse between the several products we make. We think we can hit 80% but are stuck at 30%.
Hmmmmmm, is that a common problem? :-)
At the February 22 meeting we discussed frameworks and the Exposed Delegation and Inverted Layers Patterns. Then we did a quick Mini Process on a solution to the above problem. In order to simplify things we will not be using J2EE. Instead we will do a standalone small framework to illustrate various framework patterns.
Artifacts So Far
Here's the result of the February 22 meeting. Note this is not production quality since this is an educational exercise, but it should give you the feel for how to approach even a nebulous problem like this using a standard process.
At the March 1 meeting we did iteration 1 of the framework. Highlights were:
1. Showing how "marker classes" work. A marker class marks the root location of resources that can be read using Class.getResourceAsStream(). A familiar example is an Applet and its images. In our case a marker class was used to mark the root location of a system and the resources are XML files. See the Container class for this line of code:
String text = reader.readText(markerClass, DK_FILE_NAME);2. Parsing XML text into a datatron. Jack's reusables from VCB were used for this, allowing it to be done in one powerful line of code, again in the Container class:
Datatron dk = parser.parseXMLtoDatatron(text);The following can be downloaded in one WinZip file. We discussed how each of us should study this closely and practice coding it up from scratch, using only the model.
- The datatron package, which includes a simple XML parser.
- ListOne, a one based list used by the datatron package.
- The ClassResourceReader, for reading class resouce text files.
- The Visio file containing our visual artifacts.
- The jsl.fw1 branch, which contains the first iteration.For easy reference the model for iteration 1 was:
At the March 8 meeting we did iteration 2 of the framework. Highlights were:
1. Using DK to define the contents of a Container. As you can see from our artifacts, the sample DK defines three nodes. Each has a Name (unique to the container) and a Type. Notice how a Type can be used more than once in the same container.
The code in the Container class that did this is worth studying. See below. Note the use of deferred initialization. This allows a large system to startup quickly. Note the use of "myDK", which is a Datatron, to get the DK for each node. DatatronIterator is very handy for iterating through a Datatron's collection. Note how getString() is used to get a particular key's value from the Datatron. In createNode() notice the way we create an instance from a String class name, called a "Type" in our DK. This is a very powerful technique that lies at the heart of DK driven frameworks. Finally, notice how after we create the instance we cast it to a Node and then set various properties to configure the Node properly.
protected void checkDeferredInit() { if (isInitialized) return; isInitialized = true; DatatronIterator nodes = myDK.getDatatron("Nodes").iterateEntries(); while (nodes.hasNext()) { Datatron nodeDK = nodes.nextDatatron(); String name = nodeDK.getString("Name"); String type = nodeDK.getString("Type"); Node node = createNode(name, type); addNode(node); } } protected Node createNode(String name, String type) { if (nodes.containsKey(name)) throw new IllegalStateException ("The name " + name + " already exists."); Node node = null; if (type.equals("Container")) { node = new Container(); } else { try { node = (Node)Class.forName(type).newInstance(); } catch(Exception ex) { ex.printStackTrace(); throw new RuntimeException("Cannot create type " + type); } } node.setName(name); node.setParent(this); if (node.isDKDriven()) provideNodeDK(node); return node; } protected void provideNodeDK(Node node) { print(".provideNodeDK() - Not yet implemented"); } |
Download Iteration 2 with one WinZip file. Study the file structure and code closely. Run the test with "java jsl.fw1.qc.System1Test". Try making changes to the _Container.DK file to see what happens in your ouput. For example add another leaf and container. For quick reference the iteration 2 artifacts are:
In between meetings, on Saturday March 10, Jack did Iteration 3 at home. This iteration added "nesting" to the framework. Nesting allows nodes to be nested as deep as you want. Each node has a parent node, except the root node which has a null parent. The tree of nodes mirrors the directory structure of DK files. This simple design allows very powerful reuse. Download Iteration 3. The main changes were:
1. We have edited some DK and added the "ContainerA" directory. This is an example of how the directory structure mirrors a system's tree of nodes.
2. The Node class now has a String marker field, with a setter and getter.
3. Extensive changes were made to the Container class. First we added the static method getDK(String markerClass, String resource). Then we implemented the previously stubbed in provideNodeDK(Node node) method. Study these methods closely:
protected static Datatron getDK(String markerClass, String resource) { String text = reader.readText(markerClass, resource); return parser.parseXMLtoDatatron(text); } // Note the careful use of searching upward in the system tree of // nodes to build the relative resource path. protected static void provideNodeDK(Node node) { // Calculate resource path to first marker found String resource = CONTAINER_DK_FILE_NAME; Node parent = node; if (node instanceof Leaf) { resource = node.getName() + "." + LEAF_DK_FILE_TYPE; parent = node.getParent(); } String marker = parent.getMarker(); while(marker == null) { resource = parent.getName() + "/" + resource; parent = parent.getParent(); marker = parent.getMarker(); } // The rest is easy :-) print(".provideNodeDK() - marker = " + marker + ", resource = " + resource); node.setDK(getDK(marker, resource)); } |
Notice when you run the test with "java jsl.fw1.qc.System1Test " you can see the marker and resource used to provide each node with its DK. Note how one resource is "ContainerA/_Container.dk". Note also that Leaf11 in the ContainerA directory doesn't have its DK provided. Why? That's because we have designed our framework to not initialize a container until the first time its nodes are requested via iterateNodes() or getNode(). Later we will use Leaf11, but for now it is not yet instantiated during the test.
For quick reference the iteration 3 artifacts are: