/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.apps.jpartition.commands.framework;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import org.apache.log4j.Logger;
import org.jnode.apps.jpartition.Context;
/**
* Command processor which handle a stack of commands to execute.
* @author Fabien DUMINY (fduminy@jnode.org)
*
*/
public class CommandProcessor {
private static final Logger log = Logger.getLogger(CommandProcessor.class);
/**
* The context to use.
*/
private final Context context;
/**
* The stack of commands.
*/
private Stack<Command> commands = new Stack<Command>();
/**
* The listeners of this command processor.
*/
private List<CommandProcessorListener> listeners = new ArrayList<CommandProcessorListener>();
/**
* Are we actually executing the commands in our stack ?
*/
private boolean running = false;
/**
* Cosntructor.
* @param context The context to use.
*/
public CommandProcessor(Context context) {
this.context = context;
}
/**
* Get the pending commands.
* @return The pending commands.
*/
public List<Command> getPendingCommands() {
return new ArrayList<Command>(commands);
}
/**
* Main loop processing all commands in the stack.
*/
public synchronized void process() {
try {
if (!running) {
running = true;
boolean quit = false;
while (!commands.isEmpty() && !quit) {
quit = processCommand();
}
running = false;
}
} catch (Throwable t) {
context.getErrorReporter().reportError(log, this, t);
}
}
private boolean processCommand() {
boolean quit = false;
Command command = null;
try {
command = peekCommand();
command.execute(this);
} catch (CommandException e) {
log.error("error in command processing", e);
quit = true;
} catch (Throwable t) {
log.error("unexpected error in command processing", t);
quit = true;
} finally {
if (command != null) {
for (CommandProcessorListener l : listeners) {
l.commandFinished(this, command);
}
try {
removeCommand();
} catch (Throwable t) {
log.error("error in removeCommand", t);
}
}
}
return quit;
}
/**
* Add a command to the stack of pending commands.
* @param command The command to add.
*/
public void addCommand(Command command) {
if (command.getStatus() != CommandStatus.NOT_RUNNING) {
throw new IllegalArgumentException("command must be in status NOT_RUNNING");
}
commands.push(command);
for (CommandProcessorListener l : listeners) {
l.commandAdded(this, command);
}
}
protected Command peekCommand() throws Exception {
Command command = commands.peek();
if (command.getStatus() != CommandStatus.NOT_RUNNING) {
throw new Exception("command already started : " + command);
}
return command;
}
protected void removeCommand() {
Command command = commands.pop();
for (CommandProcessorListener l : listeners) {
l.commandRemoved(this, command);
}
}
/**
* Callback method used to notify the command processor that a command
* has started to execute.
* @param command The command that has started.
*/
public void commandStarted(Command command) {
for (CommandProcessorListener l : listeners) {
l.commandStarted(this, command);
}
}
/**
* Add a listener of command processor events.
* @param listener The listener to add.
*/
public void addListener(CommandProcessorListener listener) {
listeners.add(listener);
}
/**
* Remove a listener of command processor events.
* @param listener The listener to remove.
*/
public void removeListener(CommandProcessorListener listener) {
listeners.remove(listener);
}
/**
* @return
*/
public Context getContext() {
return context;
}
}