001 /* 002 * Copyright 2002-2004 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.springframework.richclient.command.support; 017 018 import java.util.Hashtable; 019 import java.util.Iterator; 020 import java.util.LinkedList; 021 import java.util.List; 022 import java.util.Map; 023 024 import org.apache.commons.logging.Log; 025 import org.apache.commons.logging.LogFactory; 026 import org.springframework.richclient.command.AbstractCommand; 027 import org.springframework.richclient.command.ActionCommand; 028 import org.springframework.richclient.command.ActionCommandExecutor; 029 import org.springframework.richclient.command.CommandGroup; 030 import org.springframework.richclient.command.CommandNotOfRequiredTypeException; 031 import org.springframework.richclient.command.CommandRegistry; 032 import org.springframework.richclient.command.CommandRegistryEvent; 033 import org.springframework.richclient.command.CommandRegistryListener; 034 import org.springframework.richclient.command.TargetableActionCommand; 035 import org.springframework.richclient.util.Assert; 036 import org.springframework.util.ClassUtils; 037 import org.springframework.util.ObjectUtils; 038 039 /** 040 * The default implementation of the {@link CommandRegistry} interface. This implementation 041 * may act as the child of another registry, allowing for a hierarchy of registries to be created. 042 * If a command is requested from this registry but cannot be found, the request will be delegated 043 * to the parent registry. 044 * 045 * 046 * @author Keith Donald 047 * @author Kevin Stembridge 048 */ 049 public class DefaultCommandRegistry implements CommandRegistry, CommandRegistryListener { 050 051 /** 052 * Class logger, available to subclasses. 053 */ 054 protected final Log logger = LogFactory.getLog(getClass()); 055 056 private final List commandRegistryListeners = new LinkedList(); 057 058 private final Map commandMap = new Hashtable(); 059 060 private CommandRegistry parent; 061 062 /** 063 * Creates a new uninitialized {@code DefaultCommandRegistry}. 064 */ 065 public DefaultCommandRegistry() { 066 //do nothing 067 } 068 069 /** 070 * Creates a new {@code DefaultCommandRegistry} as a child of the given registry. The newly 071 * created instance will be added as a listener on the parent registry. 072 * 073 * @param parent The parent registry. May be null. 074 */ 075 public DefaultCommandRegistry(CommandRegistry parent) { 076 internalSetParent(parent); 077 } 078 079 /** 080 * Sets the given registry to be the parent of this instance. If the new parent is not null, 081 * this instance will act as a registry listener on it. 082 * 083 * @param parent The parent registry. May be null. 084 */ 085 public void setParent(CommandRegistry parent) { 086 internalSetParent(parent); 087 } 088 089 /** 090 * This method is provided as a private helper so that it can be called by the constructor, 091 * instead of the constructor having to call the public overridable setParent method. 092 */ 093 private void internalSetParent(CommandRegistry parentRegistry) { 094 095 if (!ObjectUtils.nullSafeEquals(this.parent, parentRegistry)) { 096 097 if (this.parent != null) { 098 this.parent.removeCommandRegistryListener(this); 099 } 100 101 this.parent = parentRegistry; 102 103 if (this.parent != null) { 104 this.parent.addCommandRegistryListener(this); 105 } 106 107 } 108 109 } 110 111 /** 112 * {@inheritDoc} 113 */ 114 public void commandRegistered(CommandRegistryEvent event) { 115 Assert.required(event, "event"); 116 fireCommandRegistered(event.getCommand()); 117 } 118 119 /** 120 * {@inheritDoc} 121 * @deprecated 122 */ 123 public ActionCommand getActionCommand(String commandId) { 124 125 if (logger.isDebugEnabled()) { 126 logger.debug("Attempting to retrieve ActionCommand with id [" 127 + commandId 128 + "] from the command registry."); 129 } 130 131 Object command = getCommand(commandId, ActionCommand.class); 132 133 return (ActionCommand) command; 134 135 } 136 137 /** 138 * {@inheritDoc} 139 * @deprecated 140 */ 141 public CommandGroup getCommandGroup(String groupId) { 142 143 if (logger.isDebugEnabled()) { 144 logger.debug("Attempting to retrieve command group with id [" 145 + groupId 146 + "] from the command registry."); 147 } 148 149 Object command = getCommand(groupId, CommandGroup.class); 150 151 return (CommandGroup) command; 152 153 } 154 155 /** 156 * {@inheritDoc} 157 * @deprecated 158 */ 159 public boolean containsActionCommand(String commandId) { 160 161 if (commandMap.containsKey(commandId)) { 162 return true; 163 } 164 165 if (parent != null) { 166 return parent.containsActionCommand(commandId); 167 } 168 169 return false; 170 171 } 172 173 /** 174 * {@inheritDoc} 175 * @deprecated 176 */ 177 public boolean containsCommandGroup(String groupId) { 178 if (commandMap.get(groupId) instanceof CommandGroup) { 179 return true; 180 } 181 if (parent != null) { 182 return parent.containsCommandGroup(groupId); 183 } 184 return false; 185 } 186 187 /** 188 * {@inheritDoc} 189 */ 190 public void registerCommand(AbstractCommand command) { 191 192 Assert.notNull(command, "Command cannot be null."); 193 Assert.isTrue(command.getId() != null, "A command must have an identifier to be placed in a registry."); 194 195 Object previousCommand = this.commandMap.put(command.getId(), command); 196 197 if (previousCommand != null && logger.isWarnEnabled()) { 198 logger.warn("The command [" 199 + previousCommand 200 + "] was overwritten in the registry with the command [" 201 + command 202 + "]"); 203 } 204 205 if (command instanceof CommandGroup) { 206 ((CommandGroup) command).setCommandRegistry(this); 207 } 208 209 if (logger.isDebugEnabled()) { 210 logger.debug("Command registered '" + command.getId() + "'"); 211 } 212 213 fireCommandRegistered(command); 214 215 } 216 217 /** 218 * Fires a 'commandRegistered' {@link CommandRegistryEvent} for the given command to all 219 * registered listeners. 220 * 221 * @param command The command that has been registered. Must not be null. 222 * 223 * @throws IllegalArgumentException if {@code command} is null. 224 */ 225 protected void fireCommandRegistered(AbstractCommand command) { 226 227 Assert.required(command, "command"); 228 229 if (commandRegistryListeners.isEmpty()) { 230 return; 231 } 232 233 CommandRegistryEvent event = new CommandRegistryEvent(this, command); 234 235 for (Iterator i = commandRegistryListeners.iterator(); i.hasNext();) { 236 ((CommandRegistryListener)i.next()).commandRegistered(event); 237 } 238 239 } 240 241 /** 242 * {@inheritDoc} 243 */ 244 public void setTargetableActionCommandExecutor(String commandId, ActionCommandExecutor executor) { 245 246 Assert.required(commandId, "commandId"); 247 248 TargetableActionCommand command 249 = (TargetableActionCommand) getCommand(commandId, TargetableActionCommand.class); 250 251 if (command != null) { 252 command.setCommandExecutor(executor); 253 } 254 255 } 256 257 /** 258 * {@inheritDoc} 259 */ 260 public void addCommandRegistryListener(CommandRegistryListener listener) { 261 262 if (logger.isDebugEnabled()) { 263 logger.debug("Adding command registry listener " + listener); 264 } 265 266 commandRegistryListeners.add(listener); 267 268 } 269 270 /** 271 * {@inheritDoc} 272 */ 273 public void removeCommandRegistryListener(CommandRegistryListener listener) { 274 275 if (logger.isDebugEnabled()) { 276 logger.debug("Removing command registry listener " + listener); 277 } 278 279 commandRegistryListeners.remove(listener); 280 281 } 282 283 /** 284 * Returns the parent registry of this instance. 285 * 286 * @return The parent registry, or null. 287 */ 288 public CommandRegistry getParent() { 289 return parent; 290 } 291 292 /** 293 * {@inheritDoc} 294 */ 295 public boolean containsCommand(String commandId) { 296 297 Assert.required(commandId, "commandId"); 298 299 if (this.commandMap.containsKey(commandId)) { 300 return true; 301 } 302 303 if (this.parent != null) { 304 return this.parent.containsCommand(commandId); 305 } 306 307 return false; 308 309 } 310 311 /** 312 * {@inheritDoc} 313 */ 314 public Object getCommand(String commandId) { 315 return getCommand(commandId, null); 316 } 317 318 /** 319 * {@inheritDoc} 320 */ 321 public Object getCommand(String commandId, Class requiredType) throws CommandNotOfRequiredTypeException { 322 323 Assert.required(commandId, "commandId"); 324 325 Object command = this.commandMap.get(commandId); 326 327 if (command == null && this.parent != null) { 328 command = this.parent.getCommand(commandId); 329 } 330 331 if (command == null) { 332 return null; 333 } 334 335 if (requiredType != null && !ClassUtils.isAssignableValue(requiredType, command)) { 336 throw new CommandNotOfRequiredTypeException(commandId, requiredType, command.getClass()); 337 } 338 339 return command; 340 341 } 342 343 /** 344 * {@inheritDoc} 345 */ 346 public Class getType(String commandId) { 347 348 Assert.required(commandId, "commandId"); 349 350 Object command = getCommand(commandId); 351 352 if (command == null) { 353 return null; 354 } 355 else { 356 return command.getClass(); 357 } 358 359 } 360 361 /** 362 * {@inheritDoc} 363 */ 364 public boolean isTypeMatch(String commandId, Class targetType) { 365 366 Assert.required(commandId, "commandId"); 367 Assert.required(targetType, "targetType"); 368 369 Class commandType = getType(commandId); 370 371 if (commandType == null) { 372 return false; 373 } 374 else { 375 return ClassUtils.isAssignable(targetType, commandType); 376 } 377 378 } 379 380 }