diff --git a/src/net/azib/ipscan/core/ScanningResult.java b/src/net/azib/ipscan/core/ScanningResult.java index dbcd83b3..4a7ea658 100755 --- a/src/net/azib/ipscan/core/ScanningResult.java +++ b/src/net/azib/ipscan/core/ScanningResult.java @@ -37,10 +37,27 @@ public class ScanningResult { type = ScanningSubject.RESULT_TYPE_UNKNOWN; } + /** + * Resets scanned data: returns the result to the "just created" state. + * Used for rescanning. + */ + public void reset() { + values = new Object[values.length]; + values[0] = address.getHostAddress(); + type = ScanningSubject.RESULT_TYPE_UNKNOWN; + } + public InetAddress getAddress() { return address; } + /** + * @return true if the result is ready (completely scanned) + */ + public boolean isReady() { + return type != ScanningSubject.RESULT_TYPE_UNKNOWN; + } + /** * @return the scanning results as an unmodifiable List, result of each Fetcher is an element */ diff --git a/src/net/azib/ipscan/core/ScanningResultList.java b/src/net/azib/ipscan/core/ScanningResultList.java index bfd4775b..cfb16dc3 100755 --- a/src/net/azib/ipscan/core/ScanningResultList.java +++ b/src/net/azib/ipscan/core/ScanningResultList.java @@ -44,7 +44,8 @@ public class ScanningResultList implements Iterable { /** Feeder name that was used for this scan */ private String feederName; - private ScanInfo info; + /** Information and statistics about the last scan */ + ScanInfo info; private ResultsComparator resultsComparator = new ResultsComparator(); @@ -92,9 +93,9 @@ public class ScanningResultList implements Iterable { * @return pre-initialized empty ScanningResult */ public synchronized ScanningResult createResult(InetAddress address) { + info.numScanned++; Integer index = resultIndexes.get(address); if (index == null) { - info.numScanned++; return new ScanningResult(address, fetcherRegistry.getSelectedFetchers().size()); } return resultList.get(index); @@ -103,7 +104,7 @@ public class ScanningResultList implements Iterable { /** * Registers the provided results holder at the specified index in this list. * This index will later be used to retrieve the result when redrawing items. - * TODO: index parameter is not really needed here - add method with index will not work with sparce lists anyway + * TODO: index parameter is not really needed here - add method with index will not work with sparse lists anyway * @param index * @param result */ @@ -112,15 +113,11 @@ public class ScanningResultList implements Iterable { throw new IllegalStateException(result.getAddress() + " is already registered in the list"); resultList.add(index, result); - - // update statistics - if (result.getType() == ScanningSubject.RESULT_TYPE_ALIVE) { - info.numAlive++; - } - else if (result.getType() == ScanningSubject.RESULT_TYPE_ADDITIONAL_INFO) { - info.numAlive++; - info.numWithPorts++; - } + + // if the result is already ready, then update statistics right away + // otherwise it will be done later + if (result.isReady()) + updateStatistics(result); } /** @@ -131,9 +128,14 @@ public class ScanningResultList implements Iterable { } /** - * @return the index of the result in the list, if it is registered + * Updates statistics. + * @return the index of the result in the list, if it is registered. */ - public synchronized int getIndex(ScanningResult result) { + public synchronized int update(ScanningResult result) { + // if now the result is ready, we need to update statistics + if (result.isReady()) + updateStatistics(result); + return resultIndexes.get(result.getAddress()); } @@ -172,12 +174,10 @@ public class ScanningResultList implements Iterable { } /** - * Clears previous scanning results, prepares for a new scan. + * Prepares for a new scan. Note: previous results are not automatically cleared. * @param feeder the feeder that will be used for the scan */ public synchronized void initNewScan(Feeder feeder) { - // first clear - clear(); // reload currently selected fetchers selectedFetchers = new ArrayList(fetcherRegistry.getSelectedFetchers()); // store feeder info for later @@ -265,6 +265,16 @@ public class ScanningResultList implements Iterable { return -1; } + private void updateStatistics(ScanningResult result) { + if (result.getType() == ScanningSubject.RESULT_TYPE_ALIVE) { + info.numAlive++; + } + else if (result.getType() == ScanningSubject.RESULT_TYPE_ADDITIONAL_INFO) { + info.numAlive++; + info.numWithPorts++; + } + } + /** * Additional information about the last scan */ diff --git a/src/net/azib/ipscan/feeders/RescanFeeder.java b/src/net/azib/ipscan/feeders/RescanFeeder.java index af9bc50d..9c4c7644 100644 --- a/src/net/azib/ipscan/feeders/RescanFeeder.java +++ b/src/net/azib/ipscan/feeders/RescanFeeder.java @@ -17,16 +17,24 @@ import java.util.List; */ public class RescanFeeder implements Feeder { + private Feeder oldFeeder; private List addresses; int current; /** - * @see Feeder#getLabel() + * Initializes the RescanFeeder using the old feeder used for the real scan to delegate some calls to. + * @param oldFeeder + */ + public RescanFeeder(Feeder oldFeeder) { + this.oldFeeder = oldFeeder; + } + + /** + * @return the label of the "old" feeder */ public String getLabel() { - // this feeder is not a regular one - return null; + return oldFeeder.getLabel(); } /** @@ -69,10 +77,9 @@ public class RescanFeeder implements Feeder { } /** - * @see net.azib.ipscan.feeders.Feeder#getInfo() + * @return the info of the "old" feeder */ public String getInfo() { - // this is a non-standard feeder - return null; + return oldFeeder.getInfo(); } } diff --git a/src/net/azib/ipscan/gui/ResultTable.java b/src/net/azib/ipscan/gui/ResultTable.java index 9acb17a3..3ac52d76 100755 --- a/src/net/azib/ipscan/gui/ResultTable.java +++ b/src/net/azib/ipscan/gui/ResultTable.java @@ -125,8 +125,9 @@ public class ResultTable extends Table implements FetcherRegistryUpdateListener getDisplay().syncExec(new Runnable() { public void run() { if (scanningResults.isRegistered(result)) { - // redraw the item - clear(scanningResults.getIndex(result)); + // just redraw the item + int index = scanningResults.update(result); + clear(index); } else { // first register, then add - otherwise first redraw may fail (the table is virtual) @@ -172,25 +173,15 @@ public class ResultTable extends Table implements FetcherRegistryUpdateListener * This is used for removing of any scanned data for rescanning of items. */ 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]); + int[] selectionIndices = getSelectionIndices(); + // clear scanning results + for (int itemNum : selectionIndices) { + scanningResults.getResult(itemNum).reset(); } + // redraw items in the table + clear(selectionIndices); } - /** - * Initializes a new scan. - * (clears all elments, etc) - * @param newFeederInfo feeder info of the new feeder/settings - */ - public void initNewScan() { - // remove all items from the table - removeAll(); - } - /** * @return the internal ScanningResultList instance, containing the results. */ diff --git a/src/net/azib/ipscan/gui/StatisticsDialog.java b/src/net/azib/ipscan/gui/StatisticsDialog.java index 04ac8953..9d83688e 100644 --- a/src/net/azib/ipscan/gui/StatisticsDialog.java +++ b/src/net/azib/ipscan/gui/StatisticsDialog.java @@ -8,13 +8,10 @@ package net.azib.ipscan.gui; import java.text.DecimalFormat; import java.text.NumberFormat; -import java.util.List; import net.azib.ipscan.config.Labels; import net.azib.ipscan.core.ScanningResultList; import net.azib.ipscan.core.ScanningResultList.ScanInfo; -import net.azib.ipscan.fetchers.Fetcher; -import net.azib.ipscan.fetchers.PortsFetcher; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Font; @@ -90,10 +87,10 @@ public class StatisticsDialog extends AbstractModalDialog { .append(scanningResults.getFeederInfo()).append(ln).append(ln); text.append(Labels.getLabel("text.scan.hosts.total")).append(scanInfo.getHostCount()).append(ln); - text.append(Labels.getLabel("text.scan.hosts.alive")).append(scanInfo.getAliveCount()).append(ln); - if (isPortsFetcherPresent(scanningResults.getFetchers())) { + if (scanInfo.getAliveCount() > 0) + text.append(Labels.getLabel("text.scan.hosts.alive")).append(scanInfo.getAliveCount()).append(ln); + if (scanInfo.getWithPortsCount() > 0) text.append(Labels.getLabel("text.scan.hosts.ports")).append(scanInfo.getWithPortsCount()).append(ln); - } Text statsText = new Text(shell, SWT.MULTI | SWT.READ_ONLY); statsText.setBackground(currentDisplay.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); @@ -101,15 +98,6 @@ public class StatisticsDialog extends AbstractModalDialog { statsText.setText(text.toString()); } - static boolean isPortsFetcherPresent(List fetchers) { - for (Fetcher f : fetchers) { - if (f instanceof PortsFetcher) { - return true; - } - } - return false; - } - /** * @param scanTime in milliseconds * @return provided time in human-readable form diff --git a/src/net/azib/ipscan/gui/actions/StartStopScanningAction.java b/src/net/azib/ipscan/gui/actions/StartStopScanningAction.java index 75bc3a44..4964f754 100755 --- a/src/net/azib/ipscan/gui/actions/StartStopScanningAction.java +++ b/src/net/azib/ipscan/gui/actions/StartStopScanningAction.java @@ -125,8 +125,8 @@ public class StartStopScanningAction implements SelectionListener, ScanningProgr statusBar.setProgress(0); break; case STARTING: - // start the scan! - resultTable.initNewScan(); + // start the scan from scratch! + resultTable.removeAll(); scannerThread = scannerThreadFactory.createScannerThread(feederRegistry.current().getFeeder(), StartStopScanningAction.this, createResultsCallback()); stateMachine.startScanning(); break; diff --git a/src/net/azib/ipscan/gui/feeders/FeederGUIRegistry.java b/src/net/azib/ipscan/gui/feeders/FeederGUIRegistry.java index 950bf69b..597b1efd 100755 --- a/src/net/azib/ipscan/gui/feeders/FeederGUIRegistry.java +++ b/src/net/azib/ipscan/gui/feeders/FeederGUIRegistry.java @@ -81,7 +81,8 @@ public class FeederGUIRegistry implements Iterable { * @return initialized instance of RescanFeeder */ public Feeder createRescanFeeder(TableItem[] items) { - Feeder feeder = new RescanFeeder(); + // TODO: passing of currentFeederGUI.getFeeder() is probably wrong - we need to have the "real" feeder that was used for the previous scan + Feeder feeder = new RescanFeeder(currentFeederGUI.getFeeder()); String[] addresses = new String[items.length]; for (int i = 0; i < items.length; i++) { addresses[i] = items[i].getText(); diff --git a/test/net/azib/ipscan/core/ScannerThreadTest.java b/test/net/azib/ipscan/core/ScannerThreadTest.java new file mode 100644 index 00000000..a6d9aa24 --- /dev/null +++ b/test/net/azib/ipscan/core/ScannerThreadTest.java @@ -0,0 +1,52 @@ +/** + * 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; + +import java.net.InetAddress; +import java.util.Collections; + +import net.azib.ipscan.core.ScanningResultList.ScanInfo; +import net.azib.ipscan.feeders.Feeder; +import net.azib.ipscan.fetchers.Fetcher; +import net.azib.ipscan.fetchers.FetcherRegistry; +import net.azib.ipscan.fetchers.IPFetcher; + +import static org.easymock.EasyMock.*; +import static org.junit.Assert.*; + +import org.junit.Test; + +/** + * ScannerThreadTest + * + * @author Anton Keks + */ +public class ScannerThreadTest { + + @Test + public void testConstructor() throws Exception { + FetcherRegistry registry = createMock(FetcherRegistry.class); + expect(registry.getSelectedFetchers()).andReturn(Collections.singleton(new IPFetcher())).anyTimes(); + Feeder feeder = createMock(Feeder.class); + expect(feeder.getInfo()).andReturn("info"); + expect(feeder.getLabel()).andReturn("text.ip"); + replay(registry, feeder); + + ScanningResultList scanningResults = new ScanningResultList(registry); + scanningResults.info = new ScanInfo(); // initialize info so we can add a dummy result + scanningResults.registerAtIndex(0, scanningResults.createResult(InetAddress.getLocalHost())); + + ScannerThread thread = new ScannerThread(feeder, new Scanner(registry), null, null, scanningResults, null, null); + + assertTrue("ScannerThread should not clear the results - otherwise rescanning will not work", + scanningResults.areResultsAvailable()); + assertEquals("Scanner Thread", thread.getName()); + assertTrue(thread.isDaemon()); + verify(registry, feeder); + } + +} diff --git a/test/net/azib/ipscan/core/ScanningResultListTest.java b/test/net/azib/ipscan/core/ScanningResultListTest.java index 788dfa8c..8003823c 100755 --- a/test/net/azib/ipscan/core/ScanningResultListTest.java +++ b/test/net/azib/ipscan/core/ScanningResultListTest.java @@ -76,6 +76,51 @@ public class ScanningResultListTest { assertTrue(scanningResults.getScanInfo().isFinished()); } + @Test + public void testStatisticsInCaseOfNormalFlow() throws Exception { + // display method: all - first register, then update + ScanningResult result = scanningResults.createResult(InetAddress.getByName("6.6.6.6")); + assertFalse(result.isReady()); + assertFalse(scanningResults.isRegistered(result)); + scanningResults.registerAtIndex(0, result); + + result.setType(ScanningSubject.RESULT_TYPE_ADDITIONAL_INFO); + assertTrue(result.isReady()); + assertTrue(scanningResults.isRegistered(result)); + assertEquals(0, scanningResults.update(result)); + assertEquals(1, scanningResults.getScanInfo().getHostCount()); + assertEquals(1, scanningResults.getScanInfo().getAliveCount()); + assertEquals(1, scanningResults.getScanInfo().getWithPortsCount()); + + // display method: alive - register only when ready + result = scanningResults.createResult(InetAddress.getByName("7.7.7.7")); + result.setType(ScanningSubject.RESULT_TYPE_ADDITIONAL_INFO); + assertTrue(result.isReady()); + assertFalse(scanningResults.isRegistered(result)); + scanningResults.registerAtIndex(1, result); + assertTrue(scanningResults.isRegistered(result)); + assertEquals(2, scanningResults.getScanInfo().getHostCount()); + assertEquals(2, scanningResults.getScanInfo().getAliveCount()); + assertEquals(2, scanningResults.getScanInfo().getWithPortsCount()); + + // rescan: result is already registered, thus updated twice + scanningResults.info = new ScanInfo(); + result = scanningResults.createResult(InetAddress.getByName("6.6.6.6")); + result.setType(ScanningSubject.RESULT_TYPE_ALIVE); + result.reset(); + assertFalse(result.isReady()); + assertTrue(scanningResults.isRegistered(result)); + assertEquals(0, scanningResults.update(result)); + + result.setType(ScanningSubject.RESULT_TYPE_ALIVE); + assertTrue(result.isReady()); + assertTrue(scanningResults.isRegistered(result)); + assertEquals(0, scanningResults.update(result)); + assertEquals(1, scanningResults.getScanInfo().getHostCount()); + assertEquals(1, scanningResults.getScanInfo().getAliveCount()); + assertEquals(0, scanningResults.getScanInfo().getWithPortsCount()); + } + @Test public void testCreateResult() throws Exception { ScanningResult result = scanningResults.createResult(InetAddress.getByName("10.0.0.5")); @@ -109,13 +154,11 @@ public class ScanningResultListTest { scanningResults.registerAtIndex(2, result); assertTrue(scanningResults.isRegistered(result)); - assertEquals(2, scanningResults.getIndex(result)); + assertEquals(2, scanningResults.update(result)); assertSame(result, scanningResults.getResult(2)); assertSame(result, scanningResults.createResult(InetAddress.getByName("10.0.0.5"))); - assertEquals(3, scanningResults.getScanInfo().getHostCount()); - assertEquals(2, scanningResults.getScanInfo().getAliveCount()); - assertEquals(1, scanningResults.getScanInfo().getWithPortsCount()); + assertEquals(4, scanningResults.getScanInfo().getHostCount()); } @Test(expected=IllegalStateException.class) @@ -156,12 +199,11 @@ public class ScanningResultListTest { scanningResults.initNewScan(feeder); verify(feeder); - assertFalse("Results must be empty", scanningResults.iterator().hasNext()); + assertTrue("initNewScan() must not clear results - otherwise rescanning will be broken", scanningResults.areResultsAvailable()); assertEquals("Cached Fetchers must be re-initilized", 1, scanningResults.getFetchers().size()); assertEquals("I am the best Feeder in the World!", scanningResults.getFeederInfo()); assertEquals(Labels.getLabel("feeder.range"), scanningResults.getFeederName()); assertNotNull(scanningResults.getScanInfo()); - assertFalse("No results are available yet", scanningResults.areResultsAvailable()); assertFalse("Scanning is not yet finished", scanningResults.getScanInfo().isFinished()); assertEquals(0, scanningResults.getScanInfo().getHostCount()); assertEquals(0, scanningResults.getScanInfo().getAliveCount()); @@ -192,8 +234,8 @@ public class ScanningResultListTest { assertFalse(i.hasNext()); // now check that there are no forgotten indexes - assertEquals(0, scanningResults.getIndex(scanningResults.createResult(InetAddress.getByName("127.9.9.1")))); - assertEquals(1, scanningResults.getIndex(scanningResults.createResult(InetAddress.getByName("127.9.9.4")))); + assertEquals(0, scanningResults.update(scanningResults.createResult(InetAddress.getByName("127.9.9.1")))); + assertEquals(1, scanningResults.update(scanningResults.createResult(InetAddress.getByName("127.9.9.4")))); assertFalse(scanningResults.isRegistered(scanningResults.createResult(InetAddress.getByName("127.9.9.3")))); assertFalse(scanningResults.isRegistered(scanningResults.createResult(InetAddress.getByName("127.9.9.2")))); } diff --git a/test/net/azib/ipscan/feeders/RescanFeederTest.java b/test/net/azib/ipscan/feeders/RescanFeederTest.java index a48e747e..af604e1e 100644 --- a/test/net/azib/ipscan/feeders/RescanFeederTest.java +++ b/test/net/azib/ipscan/feeders/RescanFeederTest.java @@ -7,6 +7,7 @@ package net.azib.ipscan.feeders; import static org.junit.Assert.*; +import static org.easymock.EasyMock.*; import org.junit.Test; @@ -17,7 +18,7 @@ import org.junit.Test; */ public class RescanFeederTest { - private Feeder feeder = new RescanFeeder(); + private Feeder feeder = new RescanFeeder(createMockFeeder()); @Test(expected=IllegalArgumentException.class) public void testEmpty() throws Exception { @@ -25,7 +26,13 @@ public class RescanFeederTest { } @Test - public void name() throws Exception { + public void testDelegatedMethods() { + assertEquals("SomeInfo", feeder.getInfo()); + assertEquals("someLabel", feeder.getLabel()); + } + + @Test + public void testFunctionality() throws Exception { assertEquals(3, feeder.initialize("127.0.0.15", "127.0.1.35", "127.0.2.2")); assertTrue(feeder.hasNext()); @@ -43,5 +50,13 @@ public class RescanFeederTest { assertFalse(feeder.hasNext()); assertEquals(100, feeder.percentageComplete()); } + + private Feeder createMockFeeder() { + Feeder feeder = createMock(Feeder.class); + expect(feeder.getInfo()).andReturn("SomeInfo"); + expect(feeder.getLabel()).andReturn("someLabel"); + replay(feeder); + return feeder; + } }