StateMachine is now in charge of state transitions

git-svn-id: https://ipscan.svn.sourceforge.net/svnroot/ipscan/trunk@137 375186e5-ef17-0410-b0b6-91563547dcda
This commit is contained in:
angryziber 2007-06-24 19:47:37 +00:00
parent 662e111d04
commit 43df609c1b
5 changed files with 84 additions and 67 deletions

View File

@ -38,6 +38,7 @@ public class ScannerThread extends Thread {
// this thread is daemon because we want JVM to terminate it
// automatically if user closes the program (Main thread, that is)
setDaemon(true);
this.feeder = feeder;
this.scanner = scanner;
this.scanningResultList = scanningResults;
@ -47,11 +48,8 @@ public class ScannerThread extends Thread {
}
public void run() {
stateMachine.transitionTo(ScanningState.SCANNING);
while(feeder.hasNext() && stateMachine.isState(ScanningState.SCANNING)) {
while(feeder.hasNext() && stateMachine.inState(ScanningState.SCANNING)) {
try {
// make a small delay between thread creation
Thread.sleep(config.threadDelay);
@ -81,13 +79,13 @@ public class ScannerThread extends Thread {
// scan each IP in parallel, in a separate thread
new IPThread(address, preparationNumber).start();
}
catch (InterruptedException e) {
catch (InterruptedException e) {
return;
}
}
// inform that no more addresses left
stateMachine.transitionTo(ScanningState.STOPPING);
stateMachine.stop();
// now wait for all threads, which are still running
try {
@ -104,17 +102,9 @@ public class ScannerThread extends Thread {
scanner.cleanup();
// finally, the scanning is complete
stateMachine.transitionTo(ScanningState.IDLE);
stateMachine.complete();
}
public void forceStop() {
stateMachine.transitionTo(ScanningState.STOPPING);
}
public void abort() {
stateMachine.transitionTo(ScanningState.KILLING);
}
// TODO: remove me and change to constructor injection
public void setResultsCallback(ScanningResultsCallback resultsCallback) {
this.resultsCallback = resultsCallback;

View File

@ -7,23 +7,13 @@ package net.azib.ipscan.core;
import java.net.InetAddress;
import net.azib.ipscan.core.state.ScanningState;
/**
* This callback is called on scanning state updates.
*
* @author anton
*/
public interface ScanningProgressCallback {
/**
* This method is called on scanner state changes,
* eg. when scanning is about to stop.
*
* @param new state
*/
public void scannerStateChanged(ScanningState state);
/**
* This method is called on scanning progress updates.
* There are no guarantees that this method is called on every

View File

@ -6,8 +6,8 @@
package net.azib.ipscan.core.state;
import java.util.HashSet;
import java.util.Set;
import java.util.ArrayList;
import java.util.List;
/**
* ScanningState enum - all possible states.
@ -21,7 +21,7 @@ public enum ScanningState {
STOPPING,
KILLING;
private Set<StateTransitionListener> listeners = new HashSet<StateTransitionListener>();
private List<StateTransitionListener> listeners = new ArrayList<StateTransitionListener>();
/**
* Transitions the state to the next one
@ -31,6 +31,10 @@ public enum ScanningState {
return states[ordinal()+1 % states.length];
}
public void addTransitionListener(StateTransitionListener listener) {
listeners.add(listener);
}
/**
* Notifies all registered listeners of the transition to this state.
*/

View File

@ -6,7 +6,10 @@
package net.azib.ipscan.core.state;
import net.azib.ipscan.core.ScanningProgressCallback;
import java.util.logging.Logger;
import net.azib.ipscan.config.LoggerFactory;
/**
* StateMachine
@ -15,19 +18,15 @@ import net.azib.ipscan.core.ScanningProgressCallback;
*/
public class StateMachine {
private ScanningProgressCallback progressCallback;
private static final Logger LOG = LoggerFactory.getLogger();
private ScanningState state = ScanningState.IDLE;
public void transitionTo(ScanningState newState) {
this.state = newState;
progressCallback.scannerStateChanged(newState);
}
/**
* @param state
* @return true if current state is as specified
*/
public boolean isState(ScanningState state) {
public boolean inState(ScanningState state) {
return this.state == state;
}
@ -38,8 +37,48 @@ public class StateMachine {
return state;
}
public void setScanningProgressCallback(ScanningProgressCallback progressCallback) {
this.progressCallback = progressCallback;
/**
* Transitions to the specified state, notifying all listeners.
* @param newState
*/
public void transitionTo(ScanningState newState) {
state = newState;
state.notifyOnEntry();
}
/**
* Transitions to the next state in the sequence.
* Called when user presses the scan button.
*/
public void transitionToNext() {
// killing state cannot be transitioned from by pressing a button
if (state != ScanningState.KILLING) {
transitionTo(state.next());
}
}
/**
* Transitions to the stopping state
*/
public void stop() {
if (state == ScanningState.SCANNING) {
transitionTo(ScanningState.STOPPING);
}
else {
LOG.warning("Attempt to stop from " + state);
}
}
/**
* Transitions back to the idle state
*/
public void complete() {
if (state == ScanningState.STOPPING || state == ScanningState.KILLING) {
transitionTo(ScanningState.IDLE);
}
else {
LOG.warning("Attempt to complete from " + state);
}
}
}

View File

@ -13,6 +13,7 @@ import net.azib.ipscan.core.ScannerThreadFactory;
import net.azib.ipscan.core.ScanningProgressCallback;
import net.azib.ipscan.core.state.ScanningState;
import net.azib.ipscan.core.state.StateMachine;
import net.azib.ipscan.core.state.StateTransitionListener;
import net.azib.ipscan.gui.ResultTable;
import net.azib.ipscan.gui.ScanningResultsConsumer;
import net.azib.ipscan.gui.StatusBar;
@ -30,7 +31,7 @@ import org.eclipse.swt.widgets.Display;
*
* @author anton
*/
public class StartStopScanningAction implements SelectionListener, ScanningProgressCallback {
public class StartStopScanningAction implements SelectionListener, ScanningProgressCallback, StateTransitionListener {
private ScannerThreadFactory scannerThreadFactory;
private ScannerThread scannerThread;
@ -53,10 +54,7 @@ public class StartStopScanningAction implements SelectionListener, ScanningProgr
this.feederRegistry = feederRegistry;
this.button = startStopButton;
this.display = button.getDisplay();
this.stateMachine = stateMachine;
// TODO: remove this, use state transition notifications
this.stateMachine.setScanningProgressCallback(this);
// pre-load button images
buttonImages[ScanningState.IDLE.ordinal()] = new Image(null, Labels.getInstance().getImageAsStream("button.start.img"));
@ -69,6 +67,11 @@ public class StartStopScanningAction implements SelectionListener, ScanningProgr
buttonTexts[ScanningState.SCANNING.ordinal()] = Labels.getLabel("button.stop");
buttonTexts[ScanningState.STOPPING.ordinal()] = Labels.getLabel("button.kill");
buttonTexts[ScanningState.KILLING.ordinal()] = Labels.getLabel("button.kill");
// add listeners to all state changes
for (ScanningState state : ScanningState.values()) {
state.addTransitionListener(this);
}
// set the defaultimage
ScanningState state = stateMachine.getState();
@ -81,31 +84,13 @@ public class StartStopScanningAction implements SelectionListener, ScanningProgr
}
public void widgetSelected(SelectionEvent e) {
switch (stateMachine.getState()) {
case IDLE:
// start the scan!
resultTable.initNewScan(feederRegistry.current().getInfo());
ScanningResultsConsumer resultsConsumer = new ScanningResultsConsumer(resultTable);
scannerThread = scannerThreadFactory.createScannerThread(feederRegistry.current().getFeeder(), this);
// TODO: fix this: this is needed here to avoid cylic dependencies...
scannerThread.setResultsCallback(resultsConsumer);
scannerThread.start();
break;
case SCANNING:
scannerThread.forceStop();
break;
case STOPPING:
scannerThread.abort();
break;
case KILLING:
break;
}
stateMachine.transitionToNext();
}
public void scannerStateChanged(final ScanningState state) {
public void transitionTo(final ScanningState state) {
if (display.isDisposed())
return;
display.asyncExec(new Runnable() {
display.syncExec(new Runnable() {
public void run() {
if (statusBar.isDisposed())
return;
@ -116,6 +101,15 @@ public class StartStopScanningAction implements SelectionListener, ScanningProgr
statusBar.setStatusText(null);
statusBar.setProgress(0);
break;
case SCANNING:
// start the scan!
resultTable.initNewScan(feederRegistry.current().getInfo());
ScanningResultsConsumer resultsConsumer = new ScanningResultsConsumer(resultTable);
scannerThread = scannerThreadFactory.createScannerThread(feederRegistry.current().getFeeder(), StartStopScanningAction.this);
// TODO: fix this: this is needed here to avoid cylic dependencies...
scannerThread.setResultsCallback(resultsConsumer);
scannerThread.start();
break;
case STOPPING:
statusBar.setStatusText(Labels.getLabel("state.waitForThreads"));
break;
@ -150,5 +144,5 @@ public class StartStopScanningAction implements SelectionListener, ScanningProgr
}
});
}
}