/** * Copyright (C) 2015 Valkyrie RCP * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.valkyriercp.command.support; import java.util.Iterator; /** * CommandGroupModelBuilder is a helper class that allows to build Object Models * derived from ready command-group structures. * * These command-group structures are tree-like structures that this class will * traverse. Actual building of specific matching object models (often also * trees) is done through callbacks to specific buildXXXModel methods. (which * are abstract on this generic traversing base-class) * * Actual use assumes one sublasses and implements those required abstract * methods. * * Internally this class will traverse the commandGroup-structure and offer * subclasses the opportunity to build up his matching model matching the * command-group nesting by calling the various buildXXXModel methods. */ public abstract class CommandGroupModelBuilder { /** * Builds the real root object that will be returned from * {@link #buildModel(CommandGroup)}. * * @param commandGroup * at the root of the structure * @return the top level object model to build. */ protected abstract Object buildRootModel(CommandGroup commandGroup); /** * Allows the implementation subclass to decide (by overriding) if * traversing the structure should continue deeper down. * * Implementations can decide based on the current visited commandGroup and * the level information. * * Default implementation at this abstract class level, is to keep on going * down the structure. (subclasses should only override when needing to * change that.) * * @param commandGroup * currently visited. * @param level * in the structure we are at ATM * @return <code>true</code> if children of the group should be visted, * <code>false</code> if not. */ protected boolean continueDeeper(CommandGroup commandGroup, int level) { return true; } /** * Allows the implementation subclass to build a mapping object-model * corresponding to a visited leaf node in the command-group structure. * <i>(Note: for non-leaf nodes the * {@link #buildGroupModel(Object, CommandGroup, int) version is called)}</i> * * Since the parentModel is also passed in, the implementation can use it to * downcast that and possibly hook up the new client-structure. * * @param parentModel * the objectmodel that was created for the parent-command. * @param command * currently visited command in the structure. * @param level * in the structure we are at ATM * @return the top level object model to build. */ protected abstract Object buildChildModel(Object parentModel, AbstractCommand command, int level); /** * Allows the implementation subclass to build a mapping object-model * corresponding to a visited non-leaf node in the command-group structure. * <i>(Note: for leaf nodes the * {@link #buildChildModel(Object, AbstractCommand, int)} version is called)}</i> * * Since the parentModel is also passed in, this implementation can use it * to downcast and decide to hook up the new client-structure. * * In a same manner the object-structure returned by this method will be * passed down in the tree as the parentModel for nested nodes. * * In general, if an implementation subclass is not building extra stuff for * a particular command at a particular level, then it is generally wise to * just pass down the parentModel. * * @param parentModel * the objectmodel that was created for the parent-command. * @param commandGroup * currently visited command in the structure. * @param level * in the structure we are at ATM * @return the top level object model to build. */ protected abstract Object buildGroupModel(Object parentModel, CommandGroup commandGroup, int level); /** * Main service method of this method to call. * * This builds the complete mapping object-model by traversing the complete * passed in command-group structure by performing the appropriate callbacks * to the subclass implementations of {@link #buildRootModel(CommandGroup)}, * {@link #buildChildModel(Object, AbstractCommand, int)}, and * {@link #buildGroupModel(Object, CommandGroup, int)}. * * Additionally, * * @param commandGroup * the root of the structure for which an mapping objectmodel * will be built. * @return the build object model */ public final Object buildModel(CommandGroup commandGroup) { Object model = buildRootModel(commandGroup); recurse(commandGroup, model, 0); return model; } private void recurse(AbstractCommand childCommand, Object parentModel, int level) { if (childCommand instanceof CommandGroup) { CommandGroup commandGroup = (CommandGroup) childCommand; parentModel = buildGroupModel(parentModel, commandGroup, level); if (continueDeeper(commandGroup, level)) { Iterator members = commandGroup.memberIterator(); while (members.hasNext()) { GroupMember member = (GroupMember) members.next(); AbstractCommand memberCommand = member.getCommand(); recurse(memberCommand, parentModel, level + 1); } } } else { buildChildModel(parentModel, childCommand, level); } } }