001 package org.springframework.richclient.command;
002
003 import java.util.Iterator;
004
005 /**
006 * CommandGroupModelBuilder is a helper class that allows to build Object Models
007 * derived from ready command-group structures.
008 *
009 * These command-group structures are tree-like structures that this class will
010 * traverse. Actual building of specific matching object models (often also
011 * trees) is done through callbacks to specific buildXXXModel methods. (which
012 * are abstract on this generic traversing base-class)
013 *
014 * Actual use assumes one sublasses and implements those required abstract
015 * methods.
016 *
017 * Internally this class will traverse the commandGroup-structure and offer
018 * subclasses the opportunity to build up his matching model matching the
019 * command-group nesting by calling the various buildXXXModel methods.
020 */
021 public abstract class CommandGroupModelBuilder
022 {
023
024 /**
025 * Builds the real root object that will be returned from
026 * {@link #buildModel(CommandGroup)}.
027 *
028 * @param commandGroup
029 * at the root of the structure
030 * @return the top level object model to build.
031 */
032 protected abstract Object buildRootModel(CommandGroup commandGroup);
033
034 /**
035 * Allows the implementation subclass to decide (by overriding) if
036 * traversing the structure should continue deeper down.
037 *
038 * Implementations can decide based on the current visited commandGroup and
039 * the level information.
040 *
041 * Default implementation at this abstract class level, is to keep on going
042 * down the structure. (subclasses should only override when needing to
043 * change that.)
044 *
045 * @param commandGroup
046 * currently visited.
047 * @param level
048 * in the structure we are at ATM
049 * @return <code>true</code> if children of the group should be visted,
050 * <code>false</code> if not.
051 */
052 protected boolean continueDeeper(CommandGroup commandGroup, int level)
053 {
054 return true;
055 }
056
057 /**
058 * Allows the implementation subclass to build a mapping object-model
059 * corresponding to a visited leaf node in the command-group structure.
060 * <i>(Note: for non-leaf nodes the
061 * {@link #buildGroupModel(Object, CommandGroup, int) version is called)}</i>
062 *
063 * Since the parentModel is also passed in, the implementation can use it to
064 * downcast that and possibly hook up the new client-structure.
065 *
066 * @param parentModel
067 * the objectmodel that was created for the parent-command.
068 * @param command
069 * currently visited command in the structure.
070 * @param level
071 * in the structure we are at ATM
072 * @return the top level object model to build.
073 */
074 protected abstract Object buildChildModel(Object parentModel, AbstractCommand command, int level);
075
076 /**
077 * Allows the implementation subclass to build a mapping object-model
078 * corresponding to a visited non-leaf node in the command-group structure.
079 * <i>(Note: for leaf nodes the
080 * {@link #buildChildModel(Object, CommandGroup, int) version is called)}</i>
081 *
082 * Since the parentModel is also passed in, this implementation can use it
083 * to downcast and decide to hook up the new client-structure.
084 *
085 * In a same manner the object-structure returned by this method will be
086 * passed down in the tree as the parentModel for nested nodes.
087 *
088 * In general, if an implementation subclass is not building extra stuff for
089 * a particular command at a particular level, then it is generally wise to
090 * just pass down the parentModel.
091 *
092 * @param parentModel
093 * the objectmodel that was created for the parent-command.
094 * @param command
095 * currently visited command in the structure.
096 * @param level
097 * in the structure we are at ATM
098 * @return the top level object model to build.
099 */
100 protected abstract Object buildGroupModel(Object parentModel, CommandGroup commandGroup, int level);
101
102 /**
103 * Main service method of this method to call.
104 *
105 * This builds the complete mapping object-model by traversing the complete
106 * passed in command-group structure by performing the appropriate callbacks
107 * to the subclass implementations of {@link #buildRootModel(CommandGroup)},
108 * {@link #buildChildModel(Object, AbstractCommand, int)}, and
109 * {@link #buildGroupModel(Object, CommandGroup, int)}.
110 *
111 * Additionally,
112 *
113 * @param commandGroup
114 * the root of the structure for which an mapping objectmodel
115 * will be built.
116 * @return the build object model
117 */
118 public final Object buildModel(CommandGroup commandGroup)
119 {
120 Object model = buildRootModel(commandGroup);
121
122 recurse(commandGroup, model, 0);
123
124 return model;
125 }
126
127 private void recurse(AbstractCommand childCommand, Object parentModel, int level)
128 {
129 if (childCommand instanceof CommandGroup)
130 {
131 CommandGroup commandGroup = (CommandGroup) childCommand;
132 parentModel = buildGroupModel(parentModel, commandGroup, level);
133 if (continueDeeper(commandGroup, level))
134 {
135 Iterator members = commandGroup.memberIterator();
136 while (members.hasNext())
137 {
138 GroupMember member = (GroupMember) members.next();
139 AbstractCommand memberCommand = member.getCommand();
140 recurse(memberCommand, parentModel, level + 1);
141 }
142 }
143
144 }
145 else
146 {
147 buildChildModel(parentModel, childCommand, level);
148
149 }
150
151 }
152
153 }
154