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