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 }