/** * 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.springframework.util.ObjectUtils; import org.valkyriercp.command.ActionCommandExecutor; import org.valkyriercp.command.GuardedActionCommandExecutor; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; /** * An {@link ActionCommand} that delegates to an internal {@link ActionCommandExecutor}. * The executor can be provided at construction but can also be provided * programmatically at runtime and replaced during program execution. This enables a shared * global command feature whereby a single command is specified that can perform different * actions depending on the currently active context. * * @author Keith Donald */ public class TargetableActionCommand extends ActionCommand { private ActionCommandExecutor commandExecutor; private PropertyChangeListener guardRelay; /** * Creates a new uninitialized {@code TargetableActionCommand}. If defined * in a Spring bean factory, the name of the bean will become the id of this instance. */ public TargetableActionCommand() { this(null); } /** * Creates a new {@code TargetableActionCommand} with the given identifier. * The instance will be initialized in a disabled state. * * @param commandId The identifier for this instance. */ public TargetableActionCommand(String commandId) { this(commandId, null); } /** * Creates a new {@code TargetableActionCommand} with the given identifier and initial * executor. The instance will be initialized in a disabled state. * * @param commandId The identifier for this instance. * @param commandExecutor The initial command executor. */ public TargetableActionCommand(String commandId, ActionCommandExecutor commandExecutor) { super(commandId); setEnabled(false); setCommandExecutor(commandExecutor); } /** * Attaches the given executor to this command instance, detaching the current executor in the process. * * @param commandExecutor The executor to be attached. May be null, in which case this command * will be disabled. */ public void setCommandExecutor(ActionCommandExecutor commandExecutor) { if (ObjectUtils.nullSafeEquals(this.commandExecutor, commandExecutor)) { return; } if (commandExecutor == null) { detachCommandExecutor(); } else { if (this.commandExecutor instanceof GuardedActionCommandExecutor) { unsubscribeFromGuardedCommandDelegate(); } this.commandExecutor = commandExecutor; attachCommandExecutor(); } } /** * Attaches the currently assigned command executor to this instance. The command will * be enabled by default unless the executor is a {@link GuardedActionCommandExecutor}, * in which case the command will be assigned the enabled state of the executor. */ private void attachCommandExecutor() { if (this.commandExecutor instanceof GuardedActionCommandExecutor) { GuardedActionCommandExecutor dynamicHandler = (GuardedActionCommandExecutor)commandExecutor; setEnabled(dynamicHandler.isEnabled()); subscribeToGuardedCommandDelegate(); } else { setEnabled(true); } if (logger.isDebugEnabled()) { logger.debug("Command executor '" + this.commandExecutor + "' attached."); } } private void subscribeToGuardedCommandDelegate() { this.guardRelay = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { setEnabled(((GuardedActionCommandExecutor)commandExecutor).isEnabled()); } }; ((GuardedActionCommandExecutor)commandExecutor).addEnabledListener(guardRelay); } /** * Detaches the current executor from this command and sets the command to disabled state. */ public void detachCommandExecutor() { if (this.commandExecutor instanceof GuardedActionCommandExecutor) { unsubscribeFromGuardedCommandDelegate(); } this.commandExecutor = null; setEnabled(false); logger.debug("Command delegate detached."); } private void unsubscribeFromGuardedCommandDelegate() { ((GuardedActionCommandExecutor)this.commandExecutor).removeEnabledListener(guardRelay); } /** * Executes this command by delegating to the currently assigned executor. */ protected void doExecuteCommand() { if (this.commandExecutor instanceof ParameterizableActionCommandExecutor) { ((ParameterizableActionCommandExecutor) this.commandExecutor).execute(getParameters()); } else { if (this.commandExecutor != null) { this.commandExecutor.execute(); } } } }