package org.springframework.roo.file.undo;
import java.util.HashSet;
import java.util.Set;
import java.util.Stack;
import org.apache.commons.lang3.Validate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.osgi.service.component.ComponentContext;
import org.springframework.roo.file.undo.UndoEvent.UndoOperation;
/**
* Default implementation of the {@link UndoManager} interface.
*
* @author Ben Alex
* @since 1.0
*/
@Component
@Service
public class DefaultUndoManager implements UndoManager {
private final Set<UndoListener> listeners = new HashSet<UndoListener>();
private final Stack<UndoableOperation> stack = new Stack<UndoableOperation>();
private boolean undoEnabled = true;
protected void activate(final ComponentContext context) {}
public void add(final UndoableOperation undoableOperation) {
Validate.notNull(undoableOperation, "Undoable operation required");
stack.push(undoableOperation);
}
public void addUndoListener(final UndoListener undoListener) {
listeners.add(undoListener);
}
public void flush() {
notifyListeners(UndoOperation.FLUSH);
}
private void notifyListeners(final UndoOperation operation) {
for (final UndoListener listener : listeners) {
listener.onUndoEvent(new UndoEvent(operation));
}
}
public void removeUndoListener(final UndoListener undoListener) {
listeners.remove(undoListener);
}
public void reset() {
while (!stack.empty()) {
final UndoableOperation op = stack.pop();
try {
op.reset();
} catch (final Throwable t) {
throw new IllegalStateException("UndoableOperation '" + op
+ "' threw an exception, in violation of the interface contract");
}
}
notifyListeners(UndoOperation.RESET);
}
public void setUndoEnabled(final boolean undoEnabled) {
this.undoEnabled = undoEnabled;
}
public boolean undo() {
boolean undoMode = true;
if (!undoEnabled) {
// Force the undo stack to simply reset (but not perform any undos)
undoMode = false;
}
while (!stack.empty()) {
final UndoableOperation op = stack.pop();
try {
if (undoMode) {
if (!op.undo()) {
// Undo failed, so switch to reset mode going forward
undoMode = false;
}
} else {
// In reset mode
op.reset();
}
} catch (final Throwable t) {
throw new IllegalStateException("UndoableOperation '" + op
+ "' threw an exception, in violation of the interface contract");
}
}
notifyListeners(UndoOperation.UNDO);
return undoMode;
}
}