Coverage Report - org.openpermis.editor.policy.command.CommandManager
 
Classes in this File Line Coverage Branch Coverage Complexity
CommandManager
71%
43/60
66%
16/24
2.818
 
 1  
 /*
 2  
  * Copyright (c) 2009, Swiss Federal Department of Defence Civil Protection and Sport
 3  
  *                     (http://www.vbs.admin.ch)
 4  
  * Copyright (c) 2009, Ergon Informatik AG (http://www.ergon.ch)
 5  
  * All rights reserved.
 6  
  *
 7  
  * Licensed under the Open Permis License which accompanies this distribution,
 8  
  * and is available at http://www.openpermis.org/BSDlicenceKent.txt
 9  
  */
 10  
 package org.openpermis.editor.policy.command;
 11  
 
 12  
 import java.beans.PropertyChangeListener;
 13  
 import java.beans.PropertyChangeSupport;
 14  
 import java.util.ArrayList;
 15  
 import java.util.List;
 16  
 
 17  
 import org.slf4j.Logger;
 18  
 import org.slf4j.LoggerFactory;
 19  
 
 20  
 import org.openpermis.policy.bean.PolicyBean;
 21  
 
 22  
 /**
 23  
  * Basic implementation of a command dispatcher.
 24  
  * @since 0.1.0
 25  
  */
 26  
 public class CommandManager
 27  
         implements CommandDispatcher
 28  
 {
 29  
         
 30  
         //---- Static
 31  
         
 32  
         /**
 33  
          * The logger object of this class.
 34  
          * @since 0.1.0
 35  
          */
 36  1
         private static final Logger LOGGER = 
 37  
                 LoggerFactory.getLogger(CommandManager.class);
 38  
 
 39  
         //---- State
 40  
         
 41  
         /**
 42  
          * The policy this command dispatcher operates on.
 43  
          * @since 0.1.0
 44  
          */
 45  
         private final PolicyBean policy;
 46  
         
 47  
         /**
 48  
          * The stack holding executed commands.
 49  
          * @since 0.1.0
 50  
          */
 51  
         private final List<Command> undoStack;
 52  
         
 53  
         /**
 54  
          * The stack holding reverted commands.
 55  
          * @since 0.1.0
 56  
          */
 57  
         private final List<Command> redoStack;
 58  
         
 59  
         /**
 60  
          * Beans property change support.
 61  
          * @since 0.1.0
 62  
          */
 63  
         private final PropertyChangeSupport changeSupport;
 64  
         
 65  
         //---- Constructors
 66  
         
 67  
         /**
 68  
          * Creates a new command dispatcher for the specified policy.
 69  
          * @param policy the policy the dispatcher operates on.
 70  
          * @since 0.1.0
 71  
          */
 72  7
         public CommandManager (PolicyBean policy) {
 73  7
                 this.policy = policy;
 74  7
                 this.undoStack = new ArrayList<Command>();
 75  7
                 this.redoStack = new ArrayList<Command>();
 76  7
                 this.changeSupport = new PropertyChangeSupport(this);
 77  7
         }
 78  
 
 79  
         //---- JavaBean
 80  
 
 81  
         /**
 82  
          * Registers the specified property change listener.
 83  
          * @param listener the listener to register.
 84  
          * @since 0.1.0
 85  
          */
 86  
         public void addPropertyChangeListener (PropertyChangeListener listener) {
 87  7
                 this.changeSupport.addPropertyChangeListener(listener);
 88  7
         }
 89  
 
 90  
         /**
 91  
          * Removes the specified property change listener.
 92  
          * @param listener the listener to remove.
 93  
          * @since 0.1.0
 94  
          */
 95  
         public void removePropertyChangeListener (PropertyChangeListener listener) {
 96  0
                 this.changeSupport.removePropertyChangeListener(listener);
 97  0
         }
 98  
 
 99  
         /**
 100  
          * Support for reporting bound property changes for Object properties. 
 101  
          * <p>Use this method to inform registered property change listeners of a change in 
 102  
          * a bound property.</p>
 103  
          * <p>This method will not throw any exceptions.</p>
 104  
          * @param property the property whose value has changed.
 105  
          * @param oldValue the previous value of the property.
 106  
          * @param newValue the new value of the property.
 107  
          * @since 0.1.0
 108  
          */
 109  
         protected void sureFirePropertyChange (String property, boolean oldValue, boolean newValue) {
 110  
                 try {
 111  25
                         this.changeSupport.firePropertyChange(property, oldValue, newValue);
 112  0
                 } catch (Exception e) {
 113  
                         // SureFire, we discard listener problems.
 114  25
                 }
 115  25
         }
 116  
         
 117  
         //---- Methods
 118  
         
 119  
         /**
 120  
          * Check if there is at least one command to undo.
 121  
          * @return {@code true} if there is a command to undo.
 122  
          * @since 0.1.0
 123  
          */
 124  
         public synchronized boolean isUndoAvailable () {
 125  0
                 return !this.undoStack.isEmpty();
 126  
         }
 127  
         
 128  
         /**
 129  
          * Returns the name of the first command on the undo stack.
 130  
          * @return the name or {@code null} if there is none.
 131  
          * @since 0.1.0
 132  
          */
 133  
         public synchronized String getUndoName () {
 134  0
                 if (this.undoStack.isEmpty()) {
 135  0
                         return null;
 136  
                 }
 137  0
                 return this.undoStack.get(this.undoStack.size() - 1).getName();
 138  
         }
 139  
         
 140  
         /**
 141  
          * Performs an undo of the last command executed.
 142  
          * @return {@code true} if a command was executed successfully.
 143  
          * @since 0.1.0
 144  
          */
 145  
         public synchronized boolean undo () {
 146  55
                 if (this.undoStack.isEmpty()) {
 147  27
                         return false;
 148  
                 }
 149  28
                 final Command command = this.undoStack.remove(this.undoStack.size() - 1);
 150  28
                 if (this.undoStack.isEmpty()) {
 151  4
                         sureFirePropertyChange("undoAvailable", true, false);
 152  
                 }
 153  
                 try {
 154  28
                         command.undo(this.policy);
 155  28
                         this.redoStack.add(command);
 156  28
                         if (this.redoStack.size() == 1) {
 157  7
                                 sureFirePropertyChange("redoAvailable", false, true);
 158  
                         }
 159  28
                         return true;
 160  0
                 } catch (Exception e) {
 161  0
                         LOGGER.warn("Error undoing command [" + command.getName() + "].", e);
 162  0
                         return false;
 163  
                 }
 164  
         }
 165  
         
 166  
         /**
 167  
          * Check if there is at least one command to undo.
 168  
          * @return {@code true} if there is a command to undo.
 169  
          * @since 0.1.0
 170  
          */
 171  
         public synchronized boolean isRedoAvailable () {
 172  0
                 return !this.redoStack.isEmpty();
 173  
         }
 174  
         
 175  
         /**
 176  
          * Returns the name of the first command on the redo stack.
 177  
          * @return the name or {@code null} if there is none.
 178  
          * @since 0.1.0
 179  
          */
 180  
         public synchronized String getRedoName () {
 181  0
                 if (this.redoStack.isEmpty()) {
 182  0
                         return null;
 183  
                 }
 184  0
                 return this.redoStack.get(this.redoStack.size() - 1).getName();
 185  
         }
 186  
         
 187  
         /**
 188  
          * Executes the last command that was undone again.
 189  
          * @return {@code true} if a command was executed successfully.
 190  
          * @since 0.1.0
 191  
          */
 192  
         public boolean redo () {
 193  29
                 if (this.redoStack.isEmpty()) {
 194  15
                         return false;
 195  
                 }
 196  14
                 final Command command = this.redoStack.remove(this.redoStack.size() - 1);
 197  14
                 if (this.redoStack.isEmpty()) {
 198  2
                         sureFirePropertyChange("redoAvailable", true, false);
 199  
                 }
 200  
                 try {
 201  14
                         command.execute(this.policy);
 202  14
                         this.undoStack.add(command);
 203  14
                         if (this.undoStack.size() == 1) {
 204  3
                                 sureFirePropertyChange("undoAvailable", false, true);
 205  
                         }
 206  14
                         return true;
 207  0
                 } catch (Exception e) {
 208  0
                         LOGGER.warn("Error redoing command [" + command.getName() + "].", e);
 209  0
                         return false;
 210  
                 }
 211  
         }
 212  
 
 213  
         //---- CommandDispatcher
 214  
         
 215  
         /**
 216  
          * @since 0.1.0
 217  
          */
 218  
         public synchronized void execute (Command command) {
 219  
                 try {
 220  72
                         command.execute(this.policy);
 221  42
                         this.undoStack.add(command);
 222  42
                         if (this.undoStack.size() == 1) {
 223  7
                                 sureFirePropertyChange("undoAvailable", false, true);
 224  
                         }
 225  42
                         if (!this.redoStack.isEmpty()) {
 226  2
                                 this.redoStack.clear();
 227  2
                                 sureFirePropertyChange("redoAvailable", true, false);
 228  
                         }
 229  30
                 } catch (Exception e) {
 230  30
                         LOGGER.warn("Error executing command [" + command.getName() + "].", e);
 231  42
                 }
 232  72
         }
 233  
         
 234  
 }