//$HeadURL$
/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001-2008 by:
Department of Geography, University of Bonn
http://www.giub.uni-bonn.de/deegree/
lat/lon GmbH
http://www.lat-lon.de
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact:
Andreas Poth
lat/lon GmbH
Aennchenstr. 19
53177 Bonn
Germany
E-Mail: poth@lat-lon.de
Prof. Dr. Klaus Greve
Department of Geography
University of Bonn
Meckenheimer Allee 166
53115 Bonn
Germany
E-Mail: greve@giub.uni-bonn.de
---------------------------------------------------------------------------*/
package org.deegree.kernel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import org.deegree.datatypes.QualifiedName;
import org.deegree.framework.concurrent.ExecutionFinishedEvent;
import org.deegree.framework.concurrent.ExecutionFinishedListener;
import org.deegree.framework.concurrent.Executor;
import org.deegree.framework.log.ILogger;
import org.deegree.framework.log.LoggerFactory;
import org.deegree.igeo.i18n.Messages;
import org.deegree.igeo.views.DialogFactory;
/**
*
*
*
* @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
* @author last edited by: $Author$
*
* @version. $Revision$, $Date$
*/
public class CommandProcessor implements ExecutionFinishedListener<Command> {
private static final ILogger LOG = LoggerFactory.getLogger( CommandProcessor.class );
private List<Command> doneCommands;
private List<Command> undoneCommands;
private List<CommandProcessedListener> listeners;
private static final int MAX_COMMANDS = 30;
/**
*
*/
public CommandProcessor() {
this.doneCommands = Collections.synchronizedList( new ArrayList<Command>( 100 ) );
this.undoneCommands = Collections.synchronizedList( new ArrayList<Command>( 100 ) );
this.listeners = new ArrayList<CommandProcessedListener>();
}
/**
* removes all listeners and commands from done and undone lists
*
*/
public void clear() {
clearCommands();
this.listeners.clear();
}
/**
* removes all commands from done and undone lists
*/
public void clearCommands() {
this.doneCommands.clear();
this.undoneCommands.clear();
}
/**
* executes a command, waits until execution finished and returns result of processed command.
*
* @param command
* @param notifyListener
* true if listeners registered to {@link CommandProcessor} shall be notified about executed command
* @throws Exception
*/
public Object executeSychronously( Command command, boolean notifyListener )
throws Exception {
CommandTask task = new CommandTask( command );
try {
Executor.getInstance().performSynchronously( task, Long.MAX_VALUE );
} catch ( Throwable e ) {
LOG.logError( e.getMessage(), e );
throw new Exception( e.getMessage() );
}
if ( notifyListener ) {
CommandProcessedEvent event = new CommandProcessedEvent( command );
for ( CommandProcessedListener listener : CommandProcessor.this.listeners ) {
listener.commandProcessed( event );
}
}
if ( command.isUndoSupported() ) {
this.doneCommands.add( command );
if ( this.doneCommands.size() > MAX_COMMANDS ) {
this.doneCommands.remove( 0 );
}
}
return command.getResult();
}
/**
*
* @param command
*/
public void executeASychronously( Command command ) {
CommandTask ct = new CommandTask( command );
Executor.getInstance().performAsynchronously( ct, this );
}
/**
* performs a synchronous execution of passed command with notifying registered listeners
* @param command
* @deprecated use {@link #executeASychronously(Command)} or {@link #executeSychronously(Command, boolean)} instead
*
*/
public void addCommand( Command command ) {
// CommandTask ct = new CommandTask( command );
try {
// Executor.getInstance().performAsynchronously( ct, this );
executeSychronously( command, true );
} catch ( Throwable e ) {
LOG.logError( e.getMessage(), e );
}
}
/**
* returns a list containing the names of commands that can be undone
*
* @return
*/
public List<QualifiedName> availableRedos() {
List<QualifiedName> list = new ArrayList<QualifiedName>( this.undoneCommands.size() );
for ( Command command : this.undoneCommands ) {
list.add( command.getName() );
}
return list;
}
/**
* @throws Exception
*
*
*/
public void redo()
throws Exception {
synchronized ( this.undoneCommands ) {
if ( this.undoneCommands.size() > 0 ) {
Command command = this.undoneCommands.remove( this.undoneCommands.size() - 1 );
while ( command == null ) {
int k = this.undoneCommands.size() - 1;
if ( k < 0 ) {
command = this.undoneCommands.remove( k );
} else {
command = null;
}
}
if ( command != null ) {
addCommand( command );
}
}
}
}
/**
* returns a list containing the names of commands that can be undone
*
* @return
*/
public List<QualifiedName> availableUndos() {
List<QualifiedName> list = new ArrayList<QualifiedName>( this.doneCommands.size() );
for ( Command command : this.doneCommands ) {
if ( command.isUndoSupported() ) {
list.add( command.getName() );
}
}
return list;
}
/**
* @throws Exception
*
*
*/
public void undo()
throws Exception {
synchronized ( this.doneCommands ) {
if ( this.doneCommands.size() > 0 ) {
Command command = this.doneCommands.remove( this.doneCommands.size() - 1 );
if ( command != null ) {
command.undo();
this.undoneCommands.add( command );
if ( this.undoneCommands.size() > MAX_COMMANDS ) {
this.undoneCommands.remove( 0 );
}
}
CommandProcessedEvent event = new CommandProcessedEvent( command );
for ( CommandProcessedListener listener : CommandProcessor.this.listeners ) {
listener.commandProcessed( event );
}
}
}
}
/**
*
* @param listener
* listener
*/
public void addCommandProcessedListener( CommandProcessedListener listener ) {
this.listeners.add( listener );
}
/**
*
* @param command
*
* command
*/
public void removeCommandProcessedListener( CommandProcessedListener listener ) {
this.listeners.remove( listener );
}
/*
* (non-Javadoc)
*
* @see
* org.deegree.framework.concurrent.ExecutionFinishedListener#executionFinished(org.deegree.framework.concurrent
* .ExecutionFinishedEvent)
*/
public void executionFinished( ExecutionFinishedEvent<Command> finishedEvent ) {
try {
Command command = finishedEvent.getResult();
CommandProcessedEvent event;
try {
CommandProcessor.this.doneCommands.add( command );
if ( CommandProcessor.this.doneCommands.size() > MAX_COMMANDS ) {
CommandProcessor.this.doneCommands.remove( 0 );
}
event = new CommandProcessedEvent( command );
} catch ( Throwable e ) {
LOG.logError( e.getMessage(), e );
throw new CommandException( Messages.getMessage( Locale.getDefault(), "$DG10050" ) );
}
for ( CommandProcessedListener listener : CommandProcessor.this.listeners ) {
listener.commandProcessed( event );
}
} catch ( CancellationException e ) {
LOG.logInfo( "command canceled" );
} catch ( Throwable e ) {
LOG.logError( e.getMessage(), e );
}
}
// //////////////////////////////////////////////////////////////////////////////////
// Inner class
// //////////////////////////////////////////////////////////////////////////////////
private class CommandTask implements Callable<Command> {
private Command command;
/**
*
* @param command
*/
public CommandTask( Command command ) {
this.command = command;
}
/*
* (non-Javadoc)
*
* @see java.util.concurrent.Callable#call()
*/
public Command call()
throws Exception {
try {
command.execute();
} catch (Exception e) {
LOG.logError( e );
DialogFactory.openErrorDialog( "application", null, "Command ERROR", e.getMessage(), e );
}
return command;
}
}
}