From 7e2d427cacac12c46e202e72304bc85dff6be601 Mon Sep 17 00:00:00 2001 From: angryziber Date: Sun, 8 Jul 2007 19:30:56 +0000 Subject: [PATCH] * Transition listeners are not longer stored at the ScanningState enum - it is equivalent to static. Now StateMachine does that. * More transition methods in StateMachine, they now throw exceptions if source state is unexpected. * Feeders now use varagrs for initialize method * RescanFeeder and RESTARTING state introduced to support rescanning * More tests * Warning: rescanning functionality is not yet complete - it doesn't update the correct items in the list, more work with ScanningResultList is needed git-svn-id: https://ipscan.svn.sourceforge.net/svnroot/ipscan/trunk@140 375186e5-ef17-0410-b0b6-91563547dcda --- .../azib/ipscan/config/ComponentRegistry.java | 2 +- src/net/azib/ipscan/core/ScannerThread.java | 12 +-- .../ipscan/core/ScannerThreadFactory.java | 5 +- .../azib/ipscan/core/ScanningResultList.java | 3 +- .../azib/ipscan/core/state/ScanningState.java | 39 ++++------ .../azib/ipscan/core/state/StateMachine.java | 57 +++++++++++--- src/net/azib/ipscan/feeders/Feeder.java | 4 +- src/net/azib/ipscan/feeders/FileFeeder.java | 4 +- src/net/azib/ipscan/feeders/RandomFeeder.java | 4 +- src/net/azib/ipscan/feeders/RangeFeeder.java | 4 +- src/net/azib/ipscan/feeders/RescanFeeder.java | 78 +++++++++++++++++++ .../azib/ipscan/feeders/SmartTextFeeder.java | 4 +- src/net/azib/ipscan/gui/MainMenu.java | 2 +- src/net/azib/ipscan/gui/ResultTable.java | 29 +++++-- .../ipscan/gui/ScanningResultsConsumer.java | 4 +- .../ipscan/gui/actions/CommandsActions.java | 19 ++++- .../gui/actions/StartStopScanningAction.java | 68 ++++++++++------ .../ipscan/gui/feeders/FeederGUIRegistry.java | 17 ++++ .../ipscan/core/state/ScanningStateTest.java | 29 +++++++ .../ipscan/core/state/StateMachineTest.java | 47 ++++++++--- .../azib/ipscan/feeders/FileFeederTest.java | 12 +-- .../azib/ipscan/feeders/RandomFeederTest.java | 12 +-- .../azib/ipscan/feeders/RangeFeederTest.java | 12 +-- .../azib/ipscan/feeders/RescanFeederTest.java | 47 +++++++++++ .../actions/StartStopScanningActionTest.java | 30 +++++++ 25 files changed, 421 insertions(+), 123 deletions(-) create mode 100644 src/net/azib/ipscan/feeders/RescanFeeder.java create mode 100644 test/net/azib/ipscan/core/state/ScanningStateTest.java create mode 100644 test/net/azib/ipscan/feeders/RescanFeederTest.java create mode 100644 test/net/azib/ipscan/gui/actions/StartStopScanningActionTest.java diff --git a/src/net/azib/ipscan/config/ComponentRegistry.java b/src/net/azib/ipscan/config/ComponentRegistry.java index 4d3958d6..4f8adfaf 100755 --- a/src/net/azib/ipscan/config/ComponentRegistry.java +++ b/src/net/azib/ipscan/config/ComponentRegistry.java @@ -160,7 +160,7 @@ public class ComponentRegistry { container.registerComponentImplementation(OptionsDialog.class); container.registerComponentImplementation(SelectFetchersDialog.class); - // various actions / listener + // various actions / listeners container.registerComponentImplementation(StartStopScanningAction.class); container.registerComponentImplementation(ColumnsActions.SortBy.class); container.registerComponentImplementation(ColumnsActions.FetcherOptions.class); diff --git a/src/net/azib/ipscan/core/ScannerThread.java b/src/net/azib/ipscan/core/ScannerThread.java index 9739d765..c51157d3 100755 --- a/src/net/azib/ipscan/core/ScannerThread.java +++ b/src/net/azib/ipscan/core/ScannerThread.java @@ -29,11 +29,12 @@ public class ScannerThread extends Thread { private GlobalConfig config; - public ScannerThread(Feeder feeder, Scanner scanner, StateMachine stateMachine, ScanningProgressCallback progressCallback, ScanningResultList scanningResults, GlobalConfig globalConfig) { + public ScannerThread(Feeder feeder, Scanner scanner, StateMachine stateMachine, ScanningProgressCallback progressCallback, ScanningResultList scanningResults, GlobalConfig globalConfig, ScanningResultsCallback resultsCallback) { super("Scanner Thread"); this.config = globalConfig; this.stateMachine = stateMachine; this.progressCallback = progressCallback; + this.resultsCallback = resultsCallback; // this thread is daemon because we want JVM to terminate it // automatically if user closes the program (Main thread, that is) @@ -74,7 +75,7 @@ public class ScannerThread extends Thread { int preparationNumber = resultsCallback.prepareForResults(address); // notify listeners of the progress we are doing - progressCallback.updateProgress(address, runningThreads, feeder.getPercentageComplete()); + progressCallback.updateProgress(address, runningThreads, feeder.percentageComplete()); // scan each IP in parallel, in a separate thread new IPThread(address, preparationNumber).start(); @@ -104,12 +105,7 @@ public class ScannerThread extends Thread { // finally, the scanning is complete stateMachine.complete(); } - - // TODO: remove me and change to constructor injection - public void setResultsCallback(ScanningResultsCallback resultsCallback) { - this.resultsCallback = resultsCallback; - } - + /** * This thread gets executed for each scanned IP address to do the actual * scanning. diff --git a/src/net/azib/ipscan/core/ScannerThreadFactory.java b/src/net/azib/ipscan/core/ScannerThreadFactory.java index 3bd41713..80586830 100755 --- a/src/net/azib/ipscan/core/ScannerThreadFactory.java +++ b/src/net/azib/ipscan/core/ScannerThreadFactory.java @@ -8,6 +8,7 @@ package net.azib.ipscan.core; import net.azib.ipscan.config.GlobalConfig; import net.azib.ipscan.core.state.StateMachine; import net.azib.ipscan.feeders.Feeder; +import net.azib.ipscan.gui.ScanningResultsConsumer; /** * ScannerThreadFactory. @@ -30,7 +31,7 @@ public class ScannerThreadFactory { this.globalConfig = globalConfig; } - public ScannerThread createScannerThread(Feeder feeder, ScanningProgressCallback progressCallback) { - return new ScannerThread(feeder, scanner, stateMachine, progressCallback, scanningResults, globalConfig); + public ScannerThread createScannerThread(Feeder feeder, ScanningProgressCallback progressCallback, ScanningResultsConsumer resultsConsumer) { + return new ScannerThread(feeder, scanner, stateMachine, progressCallback, scanningResults, globalConfig, resultsConsumer); } } diff --git a/src/net/azib/ipscan/core/ScanningResultList.java b/src/net/azib/ipscan/core/ScanningResultList.java index 3577741c..08793b82 100755 --- a/src/net/azib/ipscan/core/ScanningResultList.java +++ b/src/net/azib/ipscan/core/ScanningResultList.java @@ -29,7 +29,8 @@ public class ScanningResultList implements Iterable { private FetcherRegistry fetcherRegistry; // selected fetchers are cached here, because the may be changed in the registry already private List selectedFetchers; - + + /** TODO: use a Map instead of List here and remove all index-based access */ private List resultList = new ArrayList(1024); private ResultsComparator resultsComparator = new ResultsComparator(); diff --git a/src/net/azib/ipscan/core/state/ScanningState.java b/src/net/azib/ipscan/core/state/ScanningState.java index ce6b7bd8..f7549d11 100644 --- a/src/net/azib/ipscan/core/state/ScanningState.java +++ b/src/net/azib/ipscan/core/state/ScanningState.java @@ -6,8 +6,6 @@ package net.azib.ipscan.core.state; -import java.util.ArrayList; -import java.util.List; /** * ScanningState enum - all possible states. @@ -17,35 +15,24 @@ import java.util.List; public enum ScanningState { IDLE, + STARTING, SCANNING, STOPPING, - KILLING; - - private List listeners = new ArrayList(); + KILLING, + RESTARTING; /** - * Transitions the state to the next one + * Transitions the state to the next one. + * Note: not all states have the default next state; */ - public ScanningState next() { - ScanningState[] states = values(); - return states[ordinal()+1 % states.length]; - } - - public void addTransitionListener(StateTransitionListener listener) { - listeners.add(listener); - } - - public void clearListeners() { - listeners.clear(); - } - - /** - * Notifies all registered listeners of the transition to this state. - */ - public void notifyOnEntry() { - for (StateTransitionListener listener : listeners) { - listener.transitionTo(this); + ScanningState next() { + switch (this) { + case IDLE: return STARTING; + case STARTING: return SCANNING; + case SCANNING: return STOPPING; + case STOPPING: return KILLING; + case RESTARTING: return SCANNING; + default: return null; } } - } diff --git a/src/net/azib/ipscan/core/state/StateMachine.java b/src/net/azib/ipscan/core/state/StateMachine.java index 09f40203..47d313c9 100644 --- a/src/net/azib/ipscan/core/state/StateMachine.java +++ b/src/net/azib/ipscan/core/state/StateMachine.java @@ -3,25 +3,23 @@ * see http://www.azib.net/ for more information. * Licensed under GPLv2. */ - package net.azib.ipscan.core.state; -import java.util.logging.Logger; - -import net.azib.ipscan.config.LoggerFactory; - +import java.util.ArrayList; +import java.util.List; /** - * StateMachine + * StateMachine implementation. + * It holds the current state and performs transitions with corresponding methods. * * @author Anton Keks */ public class StateMachine { - private static final Logger LOG = LoggerFactory.getLogger(); - private ScanningState state = ScanningState.IDLE; + private List transitionListeners = new ArrayList(); + /** * @param state * @return true if current state is as specified @@ -37,14 +35,25 @@ public class StateMachine { return state; } + /** + * Registers state transition listener. + * @param listener instance + */ + public void addTransitionListener(StateTransitionListener listener) { + transitionListeners.add(listener); + } + /** * Transitions to the specified state, notifying all listeners. + * Note: this method is intentionally not public, use specific methods to make desired transitions. * @param newState */ - public void transitionTo(ScanningState newState) { + void transitionTo(ScanningState newState) { if (state != newState) { state = newState; - state.notifyOnEntry(); + for (StateTransitionListener listener : transitionListeners) { + listener.transitionTo(state); + } } } @@ -67,7 +76,7 @@ public class StateMachine { transitionTo(ScanningState.STOPPING); } else { - LOG.warning("Attempt to stop from " + state); + throw new IllegalStateException("Attempt to stop from " + state); } } @@ -79,7 +88,31 @@ public class StateMachine { transitionTo(ScanningState.IDLE); } else { - LOG.warning("Attempt to complete from " + state); + throw new IllegalStateException("Attempt to complete from " + state); + } + } + + /** + * Transitions to the RESTARTING state in order to rescan previously scanned results. + */ + public void rescan() { + if (state == ScanningState.IDLE) { + transitionTo(ScanningState.RESTARTING); + } + else { + throw new IllegalStateException("Attempt to rescan from " + state); + } + } + + /** + * Starts the scanning process + */ + public void startScanning() { + if (state == ScanningState.STARTING || state == ScanningState.RESTARTING) { + transitionTo(ScanningState.SCANNING); + } + else { + throw new IllegalStateException("Attempt to go scanning from " + state); } } diff --git a/src/net/azib/ipscan/feeders/Feeder.java b/src/net/azib/ipscan/feeders/Feeder.java index e1facd9c..25b54055 100755 --- a/src/net/azib/ipscan/feeders/Feeder.java +++ b/src/net/azib/ipscan/feeders/Feeder.java @@ -31,7 +31,7 @@ public interface Feeder { * @param params the meaning and the number of these Strings depend on the implementation. * @return the number of consumed parameters */ - public int initialize(String[] params); + public int initialize(String ... params); /** * @return true in case there are more IPs left for processing @@ -46,7 +46,7 @@ public interface Feeder { /** * @return value from 0 to 100, describing the amount of work already done */ - public int getPercentageComplete(); + public int percentageComplete(); /** * @return information about feeder's current settings. diff --git a/src/net/azib/ipscan/feeders/FileFeeder.java b/src/net/azib/ipscan/feeders/FileFeeder.java index 68256ea5..8c528045 100755 --- a/src/net/azib/ipscan/feeders/FileFeeder.java +++ b/src/net/azib/ipscan/feeders/FileFeeder.java @@ -56,7 +56,7 @@ public class FileFeeder implements Feeder { * @param params 1 parameter: * params[0] fileName */ - public int initialize(String[] params) { + public int initialize(String ... params) { initialize(params[0]); return 1; } @@ -104,7 +104,7 @@ public class FileFeeder implements Feeder { foundIPAddressesIterator = foundIPAddresses.iterator(); } - public int getPercentageComplete() { + public int percentageComplete() { return Math.round((float)currentIndex * 100 / totalAddresses); } diff --git a/src/net/azib/ipscan/feeders/RandomFeeder.java b/src/net/azib/ipscan/feeders/RandomFeeder.java index 31c11366..2370f515 100755 --- a/src/net/azib/ipscan/feeders/RandomFeeder.java +++ b/src/net/azib/ipscan/feeders/RandomFeeder.java @@ -43,7 +43,7 @@ public class RandomFeeder implements Feeder { * params[1] mask * params[2] count */ - public int initialize(String[] params) { + public int initialize(String ... params) { try { initialize(params[0], params[1], Integer.parseInt(params[2])); return 3; @@ -77,7 +77,7 @@ public class RandomFeeder implements Feeder { this.currentBytes = new byte[prototypeBytes.length]; } - public int getPercentageComplete() { + public int percentageComplete() { return Math.round((float)currentNumber * 100 / addressCount); } diff --git a/src/net/azib/ipscan/feeders/RangeFeeder.java b/src/net/azib/ipscan/feeders/RangeFeeder.java index aa9f08ee..0116d62b 100755 --- a/src/net/azib/ipscan/feeders/RangeFeeder.java +++ b/src/net/azib/ipscan/feeders/RangeFeeder.java @@ -43,7 +43,7 @@ public class RangeFeeder implements Feeder { * params[0] - startIP * params[1] - endIP */ - public int initialize(String[] params) { + public int initialize(String ... params) { initialize(params[0], params[1]); return 2; } @@ -96,7 +96,7 @@ public class RangeFeeder implements Feeder { return prevIP; } - public int getPercentageComplete() { + public int percentageComplete() { return (int)Math.round(percentageComplete); } diff --git a/src/net/azib/ipscan/feeders/RescanFeeder.java b/src/net/azib/ipscan/feeders/RescanFeeder.java new file mode 100644 index 00000000..af9bc50d --- /dev/null +++ b/src/net/azib/ipscan/feeders/RescanFeeder.java @@ -0,0 +1,78 @@ +/** + * This file is a part of Angry IP Scanner source code, + * see http://www.azib.net/ for more information. + * Licensed under GPLv2. + */ +package net.azib.ipscan.feeders; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; + +/** + * A Feeder for rescanning - takes a predefined list of IP addresses. + * + * @author anton + */ +public class RescanFeeder implements Feeder { + + private List addresses; + + int current; + + /** + * @see Feeder#getLabel() + */ + public String getLabel() { + // this feeder is not a regular one + return null; + } + + /** + * Initializes the RescanFeeder with required parameters + * @see Feeder#initialize(String[]) + * @param params an array of IP addresses as Strings + */ + public int initialize(String ... params) { + if (params.length == 0) + throw new IllegalArgumentException("no IP addresses specified"); + + try { + addresses = new ArrayList(params.length); + for (String s : params) { + addresses.add(InetAddress.getByName(s)); + } + } + catch (UnknownHostException e) { + throw new FeederException("malformedIP"); + } + return params.length; + } + + /** + * @see net.azib.ipscan.feeders.Feeder#hasNext() + */ + public boolean hasNext() { + return current < addresses.size(); + } + + /** + * @see net.azib.ipscan.feeders.Feeder#next() + */ + public InetAddress next() { + return addresses.get(current++); + } + + public int percentageComplete() { + return current * 100 / addresses.size(); + } + + /** + * @see net.azib.ipscan.feeders.Feeder#getInfo() + */ + public String getInfo() { + // this is a non-standard feeder + return null; + } +} diff --git a/src/net/azib/ipscan/feeders/SmartTextFeeder.java b/src/net/azib/ipscan/feeders/SmartTextFeeder.java index ac6e15f3..ab64df69 100755 --- a/src/net/azib/ipscan/feeders/SmartTextFeeder.java +++ b/src/net/azib/ipscan/feeders/SmartTextFeeder.java @@ -25,7 +25,7 @@ public class SmartTextFeeder implements Feeder { return null; } - public int initialize(String[] params) { + public int initialize(String ... params) { return 0; } @@ -52,7 +52,7 @@ public class SmartTextFeeder implements Feeder { return null; } - public int getPercentageComplete() { + public int percentageComplete() { return 0; } diff --git a/src/net/azib/ipscan/gui/MainMenu.java b/src/net/azib/ipscan/gui/MainMenu.java index 60b8bc71..0ebcee74 100755 --- a/src/net/azib/ipscan/gui/MainMenu.java +++ b/src/net/azib/ipscan/gui/MainMenu.java @@ -109,7 +109,7 @@ public class MainMenu { private void createCommandsMenuItems(Menu menu) { initMenuItem(menu, "menu.commands.details", null, null, initListener(CommandsActions.Details.class)); initMenuItem(menu, null, null, null, null); - initMenuItem(menu, "menu.commands.rescan", "Ctrl+R", new Integer(SWT.MOD1 | 'R'), null); + initMenuItem(menu, "menu.commands.rescan", "Ctrl+R", new Integer(SWT.MOD1 | 'R'), initListener(CommandsActions.Rescan.class)); initMenuItem(menu, "menu.commands.delete", "Del", null, initListener(CommandsActions.Delete.class)); initMenuItem(menu, null, null, null, null); initMenuItem(menu, "menu.commands.copy", "Ctrl+C", new Integer(SWT.MOD1 | 'C'), initListener(CommandsActions.CopyIP.class)); diff --git a/src/net/azib/ipscan/gui/ResultTable.java b/src/net/azib/ipscan/gui/ResultTable.java index 8b824a1e..5ead4800 100755 --- a/src/net/azib/ipscan/gui/ResultTable.java +++ b/src/net/azib/ipscan/gui/ResultTable.java @@ -116,7 +116,7 @@ public class ResultTable extends Table implements FetcherRegistryUpdateListener final int index = scanningResults.add(address); getDisplay().syncExec(new Runnable() { public void run() { - ResultTable.this.setItemCount(index+1); + setItemCount(index+1); } }); return index; @@ -165,6 +165,16 @@ public class ResultTable extends Table implements FetcherRegistryUpdateListener scanningResults.clear(); super.removeAll(); } + + public void resetSelection() { + int columnCount = getColumnCount(); + for (TableItem item : getSelection()) { + for (int i = 1; i < columnCount; i++) { + item.setText(i, ""); + } + item.setImage(this.listImages[ScanningSubject.RESULT_TYPE_UNKNOWN]); + } + } /** * Initializes a new scan. @@ -185,6 +195,16 @@ public class ResultTable extends Table implements FetcherRegistryUpdateListener return scanningResults; } + /** + * @return the feeder info, which used in this scan + */ + public String getFeederInfo() { + return feederInfo; + } + + /** + * This listener is used for displaying the real results in the table, on demand. + */ class SetDataListener implements Listener { public void handleEvent(Event event) { @@ -205,11 +225,4 @@ public class ResultTable extends Table implements FetcherRegistryUpdateListener } - /** - * @return the feeder info, which used in this scan - */ - public String getFeederInfo() { - return feederInfo; - } - } diff --git a/src/net/azib/ipscan/gui/ScanningResultsConsumer.java b/src/net/azib/ipscan/gui/ScanningResultsConsumer.java index ceb9230d..6a950fdd 100755 --- a/src/net/azib/ipscan/gui/ScanningResultsConsumer.java +++ b/src/net/azib/ipscan/gui/ScanningResultsConsumer.java @@ -22,14 +22,14 @@ public class ScanningResultsConsumer implements ScanningResultsCallback { this.resultTable = resultTable; } - /** + /* * @see net.azib.ipscan.core.ScanningResultsCallback#prepareForResults(InetAddress) */ public int prepareForResults(InetAddress address) { return resultTable.addResultsRow(address); } - /** + /* * @see net.azib.ipscan.core.ScanningResultsCallback#consumeResults(int, ScanningResult) */ public void consumeResults(int preparationIndex, ScanningResult results) { diff --git a/src/net/azib/ipscan/gui/actions/CommandsActions.java b/src/net/azib/ipscan/gui/actions/CommandsActions.java index b043b6ea..7b47cf4d 100755 --- a/src/net/azib/ipscan/gui/actions/CommandsActions.java +++ b/src/net/azib/ipscan/gui/actions/CommandsActions.java @@ -10,6 +10,7 @@ import java.util.Iterator; import net.azib.ipscan.config.Config; import net.azib.ipscan.config.Labels; import net.azib.ipscan.config.OpenersConfig.Opener; +import net.azib.ipscan.core.state.StateMachine; import net.azib.ipscan.fetchers.FetcherRegistry; import net.azib.ipscan.gui.DetailsDialog; import net.azib.ipscan.gui.EditOpenersDialog; @@ -56,7 +57,8 @@ public class CommandsActions { } public void handleEvent(Event event) { - // ignore other keys if this is a KeyDown event + // ignore other keys if this is a KeyDown event - + // the same listener is used for several events if (event.type == SWT.KeyDown && event.keyCode != SWT.DEL) return; checkSelection(resultTable); @@ -66,6 +68,21 @@ public class CommandsActions { } } + public static class Rescan implements Listener { + private ResultTable resultTable; + private StateMachine stateMachine; + + public Rescan(ResultTable resultTable, StateMachine stateMachine) { + this.resultTable = resultTable; + this.stateMachine = stateMachine; + } + + public void handleEvent(Event event) { + checkSelection(resultTable); + stateMachine.rescan(); + } + } + public static class CopyIP implements Listener { private ResultTable resultTable; diff --git a/src/net/azib/ipscan/gui/actions/StartStopScanningAction.java b/src/net/azib/ipscan/gui/actions/StartStopScanningAction.java index a75f12fd..6f356db1 100755 --- a/src/net/azib/ipscan/gui/actions/StartStopScanningAction.java +++ b/src/net/azib/ipscan/gui/actions/StartStopScanningAction.java @@ -35,19 +35,44 @@ public class StartStopScanningAction implements SelectionListener, ScanningProgr private ScannerThreadFactory scannerThreadFactory; private ScannerThread scannerThread; + ScanningResultsConsumer resultsConsumer; private StatusBar statusBar; private ResultTable resultTable; private FeederGUIRegistry feederRegistry; private Button button; - private Image[] buttonImages = new Image[ScanningState.values().length]; - private String[] buttonTexts = new String[ScanningState.values().length]; + + Image[] buttonImages = new Image[ScanningState.values().length]; + String[] buttonTexts = new String[ScanningState.values().length]; private Display display; private StateMachine stateMachine; + /** + * Creates internal stuff independent from all other external dependencies + */ + StartStopScanningAction() { + // pre-load button images + buttonImages[ScanningState.IDLE.ordinal()] = new Image(null, Labels.getInstance().getImageAsStream("button.start.img")); + buttonImages[ScanningState.SCANNING.ordinal()] = new Image(null, Labels.getInstance().getImageAsStream("button.stop.img")); + buttonImages[ScanningState.STARTING.ordinal()] = buttonImages[ScanningState.SCANNING.ordinal()]; + buttonImages[ScanningState.RESTARTING.ordinal()] = buttonImages[ScanningState.SCANNING.ordinal()]; + buttonImages[ScanningState.STOPPING.ordinal()] = new Image(null, Labels.getInstance().getImageAsStream("button.kill.img")); + buttonImages[ScanningState.KILLING.ordinal()] = buttonImages[ScanningState.STOPPING.ordinal()]; + + // pre-load button texts + buttonTexts[ScanningState.IDLE.ordinal()] = Labels.getLabel("button.start"); + buttonTexts[ScanningState.SCANNING.ordinal()] = Labels.getLabel("button.stop"); + buttonTexts[ScanningState.STARTING.ordinal()] = buttonTexts[ScanningState.SCANNING.ordinal()]; + buttonTexts[ScanningState.RESTARTING.ordinal()] = buttonTexts[ScanningState.SCANNING.ordinal()]; + buttonTexts[ScanningState.STOPPING.ordinal()] = Labels.getLabel("button.kill"); + buttonTexts[ScanningState.KILLING.ordinal()] = Labels.getLabel("button.kill"); + } + public StartStopScanningAction(ScannerThreadFactory scannerThreadFactory, StateMachine stateMachine, ResultTable resultTable, StatusBar statusBar, FeederGUIRegistry feederRegistry, Button startStopButton) { + this(); + this.scannerThreadFactory = scannerThreadFactory; this.resultTable = resultTable; this.statusBar = statusBar; @@ -55,23 +80,10 @@ public class StartStopScanningAction implements SelectionListener, ScanningProgr this.button = startStopButton; this.display = button.getDisplay(); this.stateMachine = stateMachine; + this.resultsConsumer = new ScanningResultsConsumer(resultTable); - // pre-load button images - buttonImages[ScanningState.IDLE.ordinal()] = new Image(null, Labels.getInstance().getImageAsStream("button.start.img")); - buttonImages[ScanningState.SCANNING.ordinal()] = new Image(null, Labels.getInstance().getImageAsStream("button.stop.img")); - buttonImages[ScanningState.STOPPING.ordinal()] = new Image(null, Labels.getInstance().getImageAsStream("button.kill.img")); - buttonImages[ScanningState.KILLING.ordinal()] = buttonImages[ScanningState.STOPPING.ordinal()]; - - // pre-load button texts - buttonTexts[ScanningState.IDLE.ordinal()] = Labels.getLabel("button.start"); - 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); - } + stateMachine.addTransitionListener(this); // set the defaultimage ScanningState state = stateMachine.getState(); @@ -79,10 +91,16 @@ public class StartStopScanningAction implements SelectionListener, ScanningProgr button.setText(buttonTexts[state.ordinal()]); } + /** + * Called when scanning button is clicked + */ public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } + /** + * Called when scanning button is clicked + */ public void widgetSelected(SelectionEvent e) { stateMachine.transitionToNext(); } @@ -101,13 +119,19 @@ public class StartStopScanningAction implements SelectionListener, ScanningProgr statusBar.setStatusText(null); statusBar.setProgress(0); break; - case SCANNING: + case STARTING: // 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 = scannerThreadFactory.createScannerThread(feederRegistry.current().getFeeder(), StartStopScanningAction.this, resultsConsumer); + stateMachine.startScanning(); + break; + case RESTARTING: + // restart the scanning - rescan + resultTable.resetSelection(); + scannerThread = scannerThreadFactory.createScannerThread(feederRegistry.createRescanFeeder(resultTable.getSelection()), StartStopScanningAction.this, resultsConsumer); + stateMachine.startScanning(); + break; + case SCANNING: scannerThread.start(); break; case STOPPING: diff --git a/src/net/azib/ipscan/gui/feeders/FeederGUIRegistry.java b/src/net/azib/ipscan/gui/feeders/FeederGUIRegistry.java index 15173be4..950bf69b 100755 --- a/src/net/azib/ipscan/gui/feeders/FeederGUIRegistry.java +++ b/src/net/azib/ipscan/gui/feeders/FeederGUIRegistry.java @@ -11,9 +11,12 @@ import java.util.List; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.TableItem; import net.azib.ipscan.config.Config; +import net.azib.ipscan.feeders.Feeder; import net.azib.ipscan.feeders.FeederException; +import net.azib.ipscan.feeders.RescanFeeder; /** * FeederGUIRegistry @@ -72,4 +75,18 @@ public class FeederGUIRegistry implements Iterable { // if not found throw new FeederException("No such feeder found: " + feederName); } + + /** + * @param items selected table items to derive IP addresses from + * @return initialized instance of RescanFeeder + */ + public Feeder createRescanFeeder(TableItem[] items) { + Feeder feeder = new RescanFeeder(); + String[] addresses = new String[items.length]; + for (int i = 0; i < items.length; i++) { + addresses[i] = items[i].getText(); + } + feeder.initialize(addresses); + return feeder; + } } diff --git a/test/net/azib/ipscan/core/state/ScanningStateTest.java b/test/net/azib/ipscan/core/state/ScanningStateTest.java new file mode 100644 index 00000000..32b9eed2 --- /dev/null +++ b/test/net/azib/ipscan/core/state/ScanningStateTest.java @@ -0,0 +1,29 @@ +/** + * This file is a part of Angry IP Scanner source code, + * see http://www.azib.net/ for more information. + * Licensed under GPLv2. + */ + +package net.azib.ipscan.core.state; + +import static org.junit.Assert.*; + +import org.junit.Test; + +/** + * ScanningStateTest + * + * @author Anton Keks + */ +public class ScanningStateTest { + + @Test + public void testNext() throws Exception { + assertEquals(ScanningState.STARTING, ScanningState.IDLE.next()); + assertEquals(ScanningState.SCANNING, ScanningState.STARTING.next()); + assertEquals(ScanningState.SCANNING, ScanningState.RESTARTING.next()); + assertEquals(ScanningState.STOPPING, ScanningState.SCANNING.next()); + assertEquals(ScanningState.KILLING, ScanningState.STOPPING.next()); + assertNull(ScanningState.KILLING.next()); + } +} diff --git a/test/net/azib/ipscan/core/state/StateMachineTest.java b/test/net/azib/ipscan/core/state/StateMachineTest.java index e57ac124..de463a65 100644 --- a/test/net/azib/ipscan/core/state/StateMachineTest.java +++ b/test/net/azib/ipscan/core/state/StateMachineTest.java @@ -33,34 +33,41 @@ public class StateMachineTest { } @Test - public void transitionTo() throws Exception { - final boolean[] called = {false}; - ScanningState.IDLE.addTransitionListener(new StateTransitionListener() { + public void transitionToSameState() throws Exception { + stateMachine.addTransitionListener(new StateTransitionListener() { public void transitionTo(ScanningState state) { fail("no transition if changing to the same state"); } }); - ScanningState.STOPPING.addTransitionListener(new StateTransitionListener() { + assertEquals(ScanningState.IDLE, stateMachine.getState()); + stateMachine.transitionTo(ScanningState.IDLE); + assertEquals(ScanningState.IDLE, stateMachine.getState()); + } + + @Test + public void transitionToAnotherState() throws Exception { + final ScanningState[] calledWithParameter = {null}; + stateMachine.addTransitionListener(new StateTransitionListener() { public void transitionTo(ScanningState state) { - called[0] = true; + calledWithParameter[0] = state; } }); - assertEquals(ScanningState.IDLE, stateMachine.getState()); - stateMachine.transitionTo(ScanningState.IDLE); assertEquals(ScanningState.IDLE, stateMachine.getState()); stateMachine.transitionTo(ScanningState.STOPPING); assertEquals(ScanningState.STOPPING, stateMachine.getState()); - assertTrue(called[0]); - - ScanningState.IDLE.clearListeners(); - ScanningState.STOPPING.clearListeners(); + assertEquals(ScanningState.STOPPING, calledWithParameter[0]); + stateMachine.transitionTo(ScanningState.STARTING); + assertEquals(ScanningState.STARTING, stateMachine.getState()); + assertEquals(ScanningState.STARTING, calledWithParameter[0]); } @Test public void transitionToNext() throws Exception { assertEquals(ScanningState.IDLE, stateMachine.getState()); stateMachine.transitionToNext(); + assertEquals(ScanningState.STARTING, stateMachine.getState()); + stateMachine.transitionToNext(); assertEquals(ScanningState.SCANNING, stateMachine.getState()); stateMachine.transitionToNext(); assertEquals(ScanningState.STOPPING, stateMachine.getState()); @@ -87,4 +94,22 @@ public class StateMachineTest { stateMachine.complete(); assertEquals(ScanningState.IDLE, stateMachine.getState()); } + + @Test + public void rescan() throws Exception { + stateMachine.transitionTo(ScanningState.IDLE); + stateMachine.rescan(); + assertEquals(ScanningState.RESTARTING, stateMachine.getState()); + } + + @Test + public void startScanning() throws Exception { + stateMachine.transitionTo(ScanningState.STARTING); + stateMachine.startScanning(); + assertEquals(ScanningState.SCANNING, stateMachine.getState()); + + stateMachine.transitionTo(ScanningState.RESTARTING); + stateMachine.startScanning(); + assertEquals(ScanningState.SCANNING, stateMachine.getState()); + } } diff --git a/test/net/azib/ipscan/feeders/FileFeederTest.java b/test/net/azib/ipscan/feeders/FileFeederTest.java index cec6eb3e..3526c584 100755 --- a/test/net/azib/ipscan/feeders/FileFeederTest.java +++ b/test/net/azib/ipscan/feeders/FileFeederTest.java @@ -89,19 +89,19 @@ public class FileFeederTest { StringReader reader = new StringReader("1.2.3.4, 2.3.4.5, mega cool 0.0.0.0"); FileFeeder fileFeeder = new FileFeeder(); fileFeeder.initialize(reader); - assertEquals(0, fileFeeder.getPercentageComplete()); + assertEquals(0, fileFeeder.percentageComplete()); fileFeeder.next(); - assertEquals(33, fileFeeder.getPercentageComplete()); + assertEquals(33, fileFeeder.percentageComplete()); fileFeeder.next(); - assertEquals(67, fileFeeder.getPercentageComplete()); + assertEquals(67, fileFeeder.percentageComplete()); fileFeeder.next(); - assertEquals(100, fileFeeder.getPercentageComplete()); + assertEquals(100, fileFeeder.percentageComplete()); reader = new StringReader("255.255.255.255"); fileFeeder.initialize(reader); - assertEquals(0, fileFeeder.getPercentageComplete()); + assertEquals(0, fileFeeder.percentageComplete()); fileFeeder.next(); - assertEquals(100, fileFeeder.getPercentageComplete()); + assertEquals(100, fileFeeder.percentageComplete()); } @Test diff --git a/test/net/azib/ipscan/feeders/RandomFeederTest.java b/test/net/azib/ipscan/feeders/RandomFeederTest.java index 07f4c7e2..3b95e2f5 100755 --- a/test/net/azib/ipscan/feeders/RandomFeederTest.java +++ b/test/net/azib/ipscan/feeders/RandomFeederTest.java @@ -119,18 +119,18 @@ public class RandomFeederTest { public void testGetPercentageComplete() throws Exception { RandomFeeder randomFeeder = new RandomFeeder(); randomFeeder.initialize("100.11.12.13", "100.11.12.15", 3); - assertEquals(0, randomFeeder.getPercentageComplete()); + assertEquals(0, randomFeeder.percentageComplete()); randomFeeder.next(); - assertEquals(33, randomFeeder.getPercentageComplete()); + assertEquals(33, randomFeeder.percentageComplete()); randomFeeder.next(); - assertEquals(67, randomFeeder.getPercentageComplete()); + assertEquals(67, randomFeeder.percentageComplete()); randomFeeder.next(); - assertEquals(100, randomFeeder.getPercentageComplete()); + assertEquals(100, randomFeeder.percentageComplete()); randomFeeder.initialize("255.255.255.255", "255.255.255.255", 1); - assertEquals(0, randomFeeder.getPercentageComplete()); + assertEquals(0, randomFeeder.percentageComplete()); randomFeeder.next(); - assertEquals(100, randomFeeder.getPercentageComplete()); + assertEquals(100, randomFeeder.percentageComplete()); } @Test diff --git a/test/net/azib/ipscan/feeders/RangeFeederTest.java b/test/net/azib/ipscan/feeders/RangeFeederTest.java index 1084f29c..595179df 100755 --- a/test/net/azib/ipscan/feeders/RangeFeederTest.java +++ b/test/net/azib/ipscan/feeders/RangeFeederTest.java @@ -74,18 +74,18 @@ public class RangeFeederTest { public void testGetPercentageComplete() throws Exception { RangeFeeder rangeFeeder = new RangeFeeder(); rangeFeeder.initialize("100.11.12.13", "100.11.12.15"); - assertEquals(0, rangeFeeder.getPercentageComplete()); + assertEquals(0, rangeFeeder.percentageComplete()); rangeFeeder.next(); - assertEquals(33, rangeFeeder.getPercentageComplete()); + assertEquals(33, rangeFeeder.percentageComplete()); rangeFeeder.next(); - assertEquals(67, rangeFeeder.getPercentageComplete()); + assertEquals(67, rangeFeeder.percentageComplete()); rangeFeeder.next(); - assertEquals(100, rangeFeeder.getPercentageComplete()); + assertEquals(100, rangeFeeder.percentageComplete()); rangeFeeder.initialize("255.255.255.255", "255.255.255.255"); - assertEquals(0, rangeFeeder.getPercentageComplete()); + assertEquals(0, rangeFeeder.percentageComplete()); rangeFeeder.next(); - assertEquals(100, rangeFeeder.getPercentageComplete()); + assertEquals(100, rangeFeeder.percentageComplete()); } @Test diff --git a/test/net/azib/ipscan/feeders/RescanFeederTest.java b/test/net/azib/ipscan/feeders/RescanFeederTest.java new file mode 100644 index 00000000..a48e747e --- /dev/null +++ b/test/net/azib/ipscan/feeders/RescanFeederTest.java @@ -0,0 +1,47 @@ +/** + * This file is a part of Angry IP Scanner source code, + * see http://www.azib.net/ for more information. + * Licensed under GPLv2. + */ + +package net.azib.ipscan.feeders; + +import static org.junit.Assert.*; + +import org.junit.Test; + +/** + * RescanFeederTest + * + * @author Anton Keks + */ +public class RescanFeederTest { + + private Feeder feeder = new RescanFeeder(); + + @Test(expected=IllegalArgumentException.class) + public void testEmpty() throws Exception { + feeder.initialize(); + } + + @Test + public void name() throws Exception { + assertEquals(3, feeder.initialize("127.0.0.15", "127.0.1.35", "127.0.2.2")); + + assertTrue(feeder.hasNext()); + assertEquals(0, feeder.percentageComplete()); + assertEquals("127.0.0.15", feeder.next().getHostAddress()); + + assertTrue(feeder.hasNext()); + assertEquals(33, feeder.percentageComplete()); + assertEquals("127.0.1.35", feeder.next().getHostAddress()); + + assertTrue(feeder.hasNext()); + assertEquals(66, feeder.percentageComplete()); + assertEquals("127.0.2.2", feeder.next().getHostAddress()); + + assertFalse(feeder.hasNext()); + assertEquals(100, feeder.percentageComplete()); + } + +} diff --git a/test/net/azib/ipscan/gui/actions/StartStopScanningActionTest.java b/test/net/azib/ipscan/gui/actions/StartStopScanningActionTest.java new file mode 100644 index 00000000..64e86688 --- /dev/null +++ b/test/net/azib/ipscan/gui/actions/StartStopScanningActionTest.java @@ -0,0 +1,30 @@ +/** + * This file is a part of Angry IP Scanner source code, + * see http://www.azib.net/ for more information. + * Licensed under GPLv2. + */ + +package net.azib.ipscan.gui.actions; + +import static org.junit.Assert.assertNotNull; +import net.azib.ipscan.core.state.ScanningState; + +import org.junit.Test; + + +/** + * StartStopScanningActionTest + * + * @author Anton Keks + */ +public class StartStopScanningActionTest { + + @Test + public void testAllImagesAreDefined() throws Exception { + StartStopScanningAction action = new StartStopScanningAction(); + for (ScanningState state : ScanningState.values()) { + assertNotNull(action.buttonImages[state.ordinal()]); + assertNotNull(action.buttonTexts[state.ordinal()]); + } + } +}