/**
* 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 org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.valkyriercp.command.ActionCommandExecutor;
import org.valkyriercp.command.CommandRegistry;
import org.valkyriercp.command.CommandRegistryListener;
import java.util.*;
/**
* The default implementation of the {@link CommandRegistry} interface. This implementation
* may act as the child of another registry, allowing for a hierarchy of registries to be created.
* If a command is requested from this registry but cannot be found, the request will be delegated
* to the parent registry.
*
*
* @author Keith Donald
* @author Kevin Stembridge
*/
public class DefaultCommandRegistry implements CommandRegistry, CommandRegistryListener {
/**
* Class logger, available to subclasses.
*/
protected final Log logger = LogFactory.getLog(getClass());
private final List commandRegistryListeners = new LinkedList();
private final Map commandMap = new Hashtable();
private CommandRegistry parent;
/**
* Creates a new uninitialized {@code DefaultCommandRegistry}.
*/
public DefaultCommandRegistry() {
//do nothing
}
/**
* Creates a new {@code DefaultCommandRegistry} as a child of the given registry. The newly
* created instance will be added as a listener on the parent registry.
*
* @param parent The parent registry. May be null.
*/
public DefaultCommandRegistry(CommandRegistry parent) {
internalSetParent(parent);
}
/**
* Sets the given registry to be the parent of this instance. If the new parent is not null,
* this instance will act as a registry listener on it.
*
* @param parent The parent registry. May be null.
*/
public void setParent(CommandRegistry parent) {
internalSetParent(parent);
}
/**
* This method is provided as a private helper so that it can be called by the constructor,
* instead of the constructor having to call the public overridable setParent method.
*/
private void internalSetParent(CommandRegistry parentRegistry) {
if (!ObjectUtils.nullSafeEquals(this.parent, parentRegistry)) {
if (this.parent != null) {
this.parent.removeCommandRegistryListener(this);
}
this.parent = parentRegistry;
if (this.parent != null) {
this.parent.addCommandRegistryListener(this);
}
}
}
/**
* {@inheritDoc}
*/
public void commandRegistered(CommandRegistryEvent event) {
Assert.notNull(event, "event");
fireCommandRegistered(event.getCommand());
}
/**
* {@inheritDoc}
* @deprecated
*/
public ActionCommand getActionCommand(String commandId) {
if (logger.isDebugEnabled()) {
logger.debug("Attempting to retrieve ActionCommand with id ["
+ commandId
+ "] from the command registry.");
}
Object command = getCommand(commandId, ActionCommand.class);
return (ActionCommand) command;
}
/**
* {@inheritDoc}
* @deprecated
*/
public CommandGroup getCommandGroup(String groupId) {
if (logger.isDebugEnabled()) {
logger.debug("Attempting to retrieve command group with id ["
+ groupId
+ "] from the command registry.");
}
Object command = getCommand(groupId, CommandGroup.class);
return (CommandGroup) command;
}
/**
* {@inheritDoc}
* @deprecated
*/
public boolean containsActionCommand(String commandId) {
if (commandMap.containsKey(commandId)) {
return true;
}
if (parent != null) {
return parent.containsActionCommand(commandId);
}
return false;
}
/**
* {@inheritDoc}
* @deprecated
*/
public boolean containsCommandGroup(String groupId) {
if (commandMap.get(groupId) instanceof CommandGroup) {
return true;
}
if (parent != null) {
return parent.containsCommandGroup(groupId);
}
return false;
}
/**
* {@inheritDoc}
*/
public void registerCommand(AbstractCommand command) {
Assert.notNull(command, "Command cannot be null.");
Assert.isTrue(command.getId() != null, "A command must have an identifier to be placed in a registry.");
Object previousCommand = this.commandMap.put(command.getId(), command);
if (previousCommand != null && logger.isWarnEnabled()) {
logger.info("The command ["
+ previousCommand
+ "] was overwritten in the registry with the command ["
+ command
+ "]");
}
if (command instanceof CommandGroup) {
((CommandGroup) command).setCommandRegistry(this);
}
if (logger.isDebugEnabled()) {
logger.debug("Command registered '" + command.getId() + "'");
}
fireCommandRegistered(command);
}
/**
* Fires a 'commandRegistered' {@link CommandRegistryEvent} for the given command to all
* registered listeners.
*
* @param command The command that has been registered. Must not be null.
*
* @throws IllegalArgumentException if {@code command} is null.
*/
protected void fireCommandRegistered(AbstractCommand command) {
Assert.notNull(command, "command");
if (commandRegistryListeners.isEmpty()) {
return;
}
CommandRegistryEvent event = new CommandRegistryEvent(this, command);
for (Iterator i = commandRegistryListeners.iterator(); i.hasNext();) {
((CommandRegistryListener)i.next()).commandRegistered(event);
}
}
/**
* {@inheritDoc}
*/
public void setTargetableActionCommandExecutor(String commandId, ActionCommandExecutor executor) {
Assert.notNull(commandId, "commandId");
TargetableActionCommand command
= (TargetableActionCommand) getCommand(commandId, TargetableActionCommand.class);
if (command != null) {
command.setCommandExecutor(executor);
}
}
/**
* {@inheritDoc}
*/
public void addCommandRegistryListener(CommandRegistryListener listener) {
if (logger.isDebugEnabled()) {
logger.debug("Adding command registry listener " + listener);
}
commandRegistryListeners.add(listener);
}
/**
* {@inheritDoc}
*/
public void removeCommandRegistryListener(CommandRegistryListener listener) {
if (logger.isDebugEnabled()) {
logger.debug("Removing command registry listener " + listener);
}
commandRegistryListeners.remove(listener);
}
/**
* Returns the parent registry of this instance.
*
* @return The parent registry, or null.
*/
public CommandRegistry getParent() {
return parent;
}
/**
* {@inheritDoc}
*/
public boolean containsCommand(String commandId) {
Assert.notNull(commandId, "commandId");
if (this.commandMap.containsKey(commandId)) {
return true;
}
if (this.parent != null) {
return this.parent.containsCommand(commandId);
}
return false;
}
/**
* {@inheritDoc}
*/
public Object getCommand(String commandId) {
return getCommand(commandId, null);
}
/**
* {@inheritDoc}
*/
public Object getCommand(String commandId, Class requiredType) throws CommandNotOfRequiredTypeException {
Assert.notNull(commandId, "commandId");
Object command = this.commandMap.get(commandId);
if (command == null && this.parent != null) {
command = this.parent.getCommand(commandId);
}
if (command == null) {
return null;
}
if (requiredType != null && !ClassUtils.isAssignableValue(requiredType, command)) {
throw new CommandNotOfRequiredTypeException(commandId, requiredType, command.getClass());
}
return command;
}
/**
* {@inheritDoc}
*/
public Class getType(String commandId) {
Assert.notNull(commandId, "commandId");
Object command = getCommand(commandId);
if (command == null) {
return null;
}
else {
return command.getClass();
}
}
/**
* {@inheritDoc}
*/
public boolean isTypeMatch(String commandId, Class targetType) {
Assert.notNull(commandId, "commandId");
Assert.notNull(targetType, "targetType");
Class commandType = getType(commandId);
if (commandType == null) {
return false;
}
else {
return ClassUtils.isAssignable(targetType, commandType);
}
}
}