package com.limegroup.gnutella.downloader; import java.io.File; import java.io.IOException; import java.net.Socket; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ScheduledExecutorService; import junit.framework.Test; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.limewire.collection.Range; import org.limewire.core.api.download.SaveLocationException; import org.limewire.core.api.download.SaveLocationException.LocationCode; import org.limewire.io.ConnectableImpl; import org.limewire.io.GUID; import org.limewire.io.IpPort; import org.limewire.io.IpPortImpl; import org.limewire.io.LocalSocketAddressProvider; import org.limewire.io.NetworkInstanceUtils; import org.limewire.net.SocketsManager; import org.limewire.net.TLSManager; import org.limewire.util.FileUtils; import org.limewire.util.OSUtils; import org.limewire.util.PrivilegedAccessor; import com.google.inject.AbstractModule; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Module; import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.inject.name.Named; import com.google.inject.name.Names; import com.limegroup.gnutella.BandwidthManager; import com.limegroup.gnutella.ConnectionManager; import com.limegroup.gnutella.DownloadManager; import com.limegroup.gnutella.DownloadManagerImpl; import com.limegroup.gnutella.Endpoint; import com.limegroup.gnutella.LimeTestUtils; import com.limegroup.gnutella.MessageRouter; import com.limegroup.gnutella.NetworkManager; import com.limegroup.gnutella.PushEndpoint; import com.limegroup.gnutella.PushEndpointCache; import com.limegroup.gnutella.PushEndpointFactory; import com.limegroup.gnutella.RemoteFileDesc; import com.limegroup.gnutella.URN; import com.limegroup.gnutella.Downloader.DownloadState; import com.limegroup.gnutella.altlocs.AltLocManager; import com.limegroup.gnutella.altlocs.AlternateLocation; import com.limegroup.gnutella.altlocs.AlternateLocationFactory; import com.limegroup.gnutella.downloader.serial.DownloadMemento; import com.limegroup.gnutella.library.CreationTimeCache; import com.limegroup.gnutella.library.FileDesc; import com.limegroup.gnutella.library.FileDescStub; import com.limegroup.gnutella.library.FileManager; import com.limegroup.gnutella.library.FileManagerStub; import com.limegroup.gnutella.library.IncompleteFileDescStub; import com.limegroup.gnutella.messages.QueryRequest; import com.limegroup.gnutella.statistics.TcpBandwidthStatistics; import com.limegroup.gnutella.stubs.ConnectionManagerStub; import com.limegroup.gnutella.stubs.LocalSocketAddressProviderStub; import com.limegroup.gnutella.stubs.MessageRouterStub; import com.limegroup.gnutella.stubs.NetworkManagerStub; import com.limegroup.gnutella.tigertree.ThexReaderFactory; import com.limegroup.gnutella.util.LimeTestCase; public class ManagedDownloaderTest extends LimeTestCase { private static final Log LOG = LogFactory.getLog(ManagedDownloaderTest.class); private final static int PORT=6666; private DownloadManagerImpl downloadManager; private FileManagerStub fileManager; private CoreDownloaderFactory gnutellaDownloaderFactory; private static NetworkManagerStub networkManager; private Injector injector; private ScheduledExecutorService background; public ManagedDownloaderTest(String name) { super(name); } public static void main(java.lang.String[] args) { junit.textui.TestRunner.run(suite()); } public static Test suite() { return buildTestSuite(ManagedDownloaderTest.class); } @Override public void setUp() throws Exception { doSetUp(); } private void doSetUp(Module... modules) throws Exception { List<Module> allModules = new LinkedList<Module>(); final LocalSocketAddressProviderStub localSocketAddressProvider = new LocalSocketAddressProviderStub(); localSocketAddressProvider.setLocalAddressPrivate(false); allModules.add(new AbstractModule() { @Override protected void configure() { bind(ConnectionManager.class).to(ConnectionManagerStub.class); bind(MessageRouter.class).to(MessageRouterStub.class); bind(FileManager.class).to(FileManagerStub.class); bind(NetworkManager.class).to(NetworkManagerStub.class); bind(LocalSocketAddressProvider.class).toInstance(localSocketAddressProvider); } }); allModules.addAll(Arrays.asList(modules)); injector = LimeTestUtils.createInjector(allModules.toArray(new Module[allModules.size()])); ConnectionManagerStub connectionManager = (ConnectionManagerStub)injector.getInstance(ConnectionManager.class); connectionManager.setConnected(true); downloadManager = (DownloadManagerImpl)injector.getInstance(DownloadManager.class); fileManager = (FileManagerStub)injector.getInstance(FileManager.class); gnutellaDownloaderFactory = injector.getInstance(CoreDownloaderFactory.class); networkManager = (NetworkManagerStub)injector.getInstance(NetworkManager.class); downloadManager.start(); downloadManager.scheduleWaitingPump(); background = injector.getInstance(Key.get(ScheduledExecutorService.class, Names.named("backgroundExecutor"))); RequeryManager.NO_DELAY = false; } @Override protected void tearDown() throws Exception { background.shutdown(); } /** * tests if firewalled altlocs are added to the file descriptor * but not sent to uploaders. (i.e. the informMesh method) */ public void testFirewalledLocs() throws Exception { doSetUp(new AbstractModule() { @Override protected void configure() { bind(HTTPDownloaderFactory.class).to(AltLocDownloaderStubFactory.class); bind(DownloadWorkerFactory.class).to(AltLocWorkerStubFactory.class); } }); networkManager.setAcceptedIncomingConnection(true); //first make sure we are sharing an incomplete file URN partialURN = URN.createSHA1Urn("urn:sha1:PLSTHIPQGSSZTS5FJUPAKUZWUGYQYPFE"); IncompleteFileDescStub partialDesc = new IncompleteFileDescStub("incomplete",partialURN,3); fileManager.getIncompleteFileList().add(partialDesc); // then create an rfd from a firewalled host RemoteFileDesc rfd = newPushRFD("incomplete","urn:sha1:PLSTHIPQGSSZTS5FJUPAKUZWUGYQYPFE",GUID.makeGuid()); //test that currently we have no altlocs for the incomplete file FileDesc test = fileManager.getIncompleteFileList().getFileDesc(partialURN); assertNotNull(test); AltLocManager altLocManager = injector.getInstance(AltLocManager.class); assertEquals(0, altLocManager.getNumLocs(test.getSHA1Urn())); //add one fake downloader to the downloader list Endpoint e = new Endpoint("1.2.3.5",12345); RemoteFileDesc other = injector.getInstance(RemoteFileDescFactory.class).createRemoteFileDesc(newRFD("incomplete"), e); HTTPDownloaderFactory httpDownloaderFactory =injector.getInstance(HTTPDownloaderFactory.class); AltLocDownloaderStub fakeDownloader = (AltLocDownloaderStub)httpDownloaderFactory.create(null, new RemoteFileDescContext(other), null, false); ManagedDownloaderImpl md = (ManagedDownloaderImpl)gnutellaDownloaderFactory.createManagedDownloader(new RemoteFileDesc[] { rfd}, null, null, null, false); DownloadWorkerFactory downloadWorkerFactory = injector.getInstance(DownloadWorkerFactory.class); AltLocWorkerStub worker = (AltLocWorkerStub)downloadWorkerFactory.create(md, new RemoteFileDescContext(rfd), null); worker.setHTTPDownloader(fakeDownloader); List<DownloadWorker> l = new LinkedList<DownloadWorker>(); l.add(worker); md.initialize(); setDloaders(md, l); setSHA1(md, partialURN); setIncompleteFile(md, partialDesc.getFile()); //and see if it behaves correctly md.informMesh(rfd,true); //make sure the downloader did not get notified assertFalse(fakeDownloader._addedFailed); assertFalse(fakeDownloader._addedSuccessfull); //the altloc should have been added to the file descriptor assertEquals(1, altLocManager.getNumLocs(partialURN)); //now repeat the test, pretending the uploader wants push altlocs fakeDownloader.setWantsFalts(true); //and see if it behaves correctly md.informMesh(rfd,true); //make sure the downloader did get notified assertFalse(fakeDownloader._addedFailed); assertTrue(fakeDownloader._addedSuccessfull); //make sure the file was added to the file descriptor assertEquals(1, altLocManager.getNumLocs(partialURN)); //rince and repeat, saying this was a bad altloc. //it should be sent to the other downloaders. fakeDownloader._addedSuccessfull=false; md.informMesh(rfd,false); //make sure the downloader did get notified assertTrue(fakeDownloader._addedFailed); assertFalse(fakeDownloader._addedSuccessfull); //make sure the altloc is demoted now assertEquals(0, altLocManager.getNumLocs(test.getSHA1Urn())); } // requeries are gone now - now we only have user-driven queries (sort of // like requeries but not automatic. public void testNewRequery() throws Exception { LOG.info("testing new requery"); RemoteFileDesc[] rfds={ newRFD("Susheel_Daswani_Neil_Daswani.txt", "urn:sha1:GLSTHIPQGSSZTS5FJUPAKPZWUGYQYPFB"), newRFD("Susheel/cool\\Daswani.txt", "urn:sha1:LSTHGIPQGSSZTS5FJUPAKPZWUGYQYPFB"), newRFD("Sumeet (Susheel) Anurag (Daswani)Chris.txt"), newRFD("Susheel/cool\\Daswani.txt", "urn:sha1:XXXXGIPQGXXXXS5FJUPAKPZWUGYQYPFB") //ignored }; ManagedDownloaderImpl downloader= (ManagedDownloaderImpl)gnutellaDownloaderFactory.createManagedDownloader(rfds, null, null, null, false); downloader.initialize(); QueryRequest qr=downloader.newRequery(); assertNotNull("Couldn't make query", qr); assertTrue(qr.getQuery().equals("neil daswani susheel") || qr.getQuery().equals("neil susheel daswani") || qr.getQuery().equals("daswani neil susheel") || qr.getQuery().equals("daswani susheel neil") || qr.getQuery().equals("susheel neil daswani") || qr.getQuery().equals("susheel daswani neil")); // minspeed mask | firewalled | xml = 224 assertEquals(224, qr.getMinSpeed()); // the guid should be a lime guid but not a lime requery guid assertTrue((GUID.isLimeGUID(qr.getGUID())) && !(GUID.isLimeRequeryGUID(qr.getGUID()))); assertTrue((qr.getRichQuery() == null) || (qr.getRichQuery().equals(""))); Set urns=qr.getQueryUrns(); assertEquals(0, urns.size()); networkManager.setCanDoFWT(true); qr=downloader.newRequery(); // minspeed mask | firewalled | xml | firewall transfer = 226 assertEquals(226, qr.getMinSpeed()); } /** Catches a bug with earlier keyword intersection code. */ public void testNewRequery2() throws Exception { LOG.info("testing new requery 2"); RemoteFileDesc[] rfds={ newRFD("LimeWire again LimeWire the 34") }; ManagedDownloaderImpl downloader= (ManagedDownloaderImpl) gnutellaDownloaderFactory.createManagedDownloader(rfds, null, null, null, false); downloader.initialize(); QueryRequest qr=downloader.newRequery(); assertEquals("limewire again", qr.getQuery()); assertEquals(new HashSet(), qr.getQueryUrns()); } /** Tests that the progress is retained for deserialized downloaders. */ public void testSerializedProgress() throws Exception { LOG.info("test serialized progress"); networkManager.setAddress(new byte[] { 127, 0, 0, 1 }); IncompleteFileManager ifm = injector.getInstance(IncompleteFileManager.class); RemoteFileDesc rfd=newRFD("some file.txt", FileDescStub.DEFAULT_URN); File incompleteFile=ifm.getFile(rfd); int amountDownloaded=100; VerifyingFileFactory verifyingFileFactory = injector.getInstance(VerifyingFileFactory.class); VerifyingFile vf=verifyingFileFactory.createVerifyingFile(1024); vf.addInterval(Range.createRange(0, amountDownloaded-1)); //inclusive ifm.addEntry(incompleteFile, vf, true); //Start downloader, make it sure requeries, etc. ManagedDownloader downloader = gnutellaDownloaderFactory.createManagedDownloader(new RemoteFileDesc[] { rfd }, null, null, null, false); downloader.initialize(); requestStart(downloader); try { Thread.sleep(200); } catch (InterruptedException e) { } //assertEquals(Downloader.WAITING_FOR_RESULTS, downloader.getState()); assertEquals(amountDownloaded, downloader.getAmountRead()); DownloadMemento memento = downloader.toMemento(); downloader.stop(false); downloader = (ManagedDownloader)downloadManager.prepareMemento(memento); downloader.initialize(); requestStart(downloader); //Check same state as before serialization. try {Thread.sleep(500);}catch(InterruptedException ignroed){} //assertEquals(Downloader.WAITING_FOR_RESULTS, downloader.getState()); assertEquals(amountDownloaded, downloader.getAmountRead()); downloader.stop(false); Thread.sleep(1000); } /** Tests that the progress is not 0% when resume button is hit while * requerying. This was caused by the call to cleanup() from * tryAllDownloads3() and was reported by Sam Berlin. * Changed after requeries have been shut off (requery-expunge-branch). */ public void testRequeryProgress() throws Exception { LOG.info("test requery progress"); TestUploader uploader=null; ManagedDownloader downloader=null; // TestFile's static initializer does all kinds of expensive stuff // that can cause the http communication to timeout when it's // done lazily TestFile.length(); try { //Start uploader and download. uploader = new TestUploader(injector); uploader.start("ManagedDownloaderTest", PORT, false); uploader.stopAfter(500); uploader.setSendThexTreeHeader(false); uploader.setSendThexTree(false); downloader= gnutellaDownloaderFactory.createManagedDownloader( new RemoteFileDesc[] {newRFD("another testfile.txt", FileDescStub.DEFAULT_URN)}, null, null, null, false); downloader.initialize(); requestStart(downloader); Thread.sleep(1000); //Wait for it to download until error, need to wait uploader.waitForUploaderToStop(); try { Thread.sleep(65 * 1000); } catch (InterruptedException ie) { } // no more auto requeries - so the download should be waiting for // input from the user assertEquals("should have read 500 bytes", 500, downloader.getAmountRead()); assertEquals("should be waiting for user", DownloadState.WAITING_FOR_USER, downloader.getState()); //Hit resume, make sure progress not erased. downloader.resume(); try { Thread.sleep(2000); } catch (InterruptedException e) { } // you would think we'd expect wating for results here, but instead // we will wait for connections (since we have no one to query) assertEquals(DownloadState.WAITING_FOR_CONNECTIONS, downloader.getState()); assertEquals(500, downloader.getAmountRead()); } finally { if (uploader!=null) uploader.stopThread(); if (downloader!=null) downloader.stop(false); } } public void testSetSaveFileExceptionPathNameTooLong() throws Exception { RemoteFileDesc[] rfds = new RemoteFileDesc[] { newRFD("download") }; File saveDir = createMaximumPathLengthDirectory(); try { gnutellaDownloaderFactory.createManagedDownloader(rfds, new GUID(GUID.makeGuid()), saveDir, "does not matter", false); fail("No exception thrown for dir " + saveDir); } catch (SaveLocationException sle) { assertEquals("Parent dir should exceed max path length", LocationCode.PATH_NAME_TOO_LONG, sle.getErrorCode()); } finally { File parent = saveDir; while (parent.getName().startsWith("zzzzzzz")) { saveDir = parent; parent = parent.getParentFile(); } FileUtils.deleteRecursive(saveDir); } } public void testSetSaveFileExceptions() throws Exception { RemoteFileDesc[] rfds = new RemoteFileDesc[] { newRFD("download") }; File file = File.createTempFile("existing", "file"); file.deleteOnExit(); File noWritePermissionDir = null; if (OSUtils.isLinux()) { noWritePermissionDir = new File("/"); } else if (OSUtils.isWindows()) { // doesn't work on // noWritePermissionDir = new File("C:\\WINDOWS\\"); } if (noWritePermissionDir != null) { try { gnutellaDownloaderFactory.createManagedDownloader(rfds, new GUID(GUID.makeGuid()), noWritePermissionDir, "does not matter", false); fail("No exception thrown for dir " + noWritePermissionDir); } catch (SaveLocationException sle) { assertEquals("Should have no write permissions", LocationCode.DIRECTORY_NOT_WRITEABLE, sle.getErrorCode()); } } try { gnutellaDownloaderFactory.createManagedDownloader(rfds, new GUID(GUID.makeGuid()), new File("/non existent directory"), null, false); fail("No exception thrown"); } catch (SaveLocationException sle) { assertEquals("Error code should be: directory does not exist", LocationCode.DIRECTORY_DOES_NOT_EXIST, sle.getErrorCode()); } try { gnutellaDownloaderFactory.createManagedDownloader(rfds, new GUID(GUID.makeGuid()), file.getParentFile(), file.getName(), false); fail("No exception thrown"); } catch (SaveLocationException sle) { assertEquals("Error code should be: file exists", LocationCode.FILE_ALREADY_EXISTS, sle.getErrorCode()); } try { // should not throw an exception because of overwrite gnutellaDownloaderFactory.createManagedDownloader(rfds, new GUID(GUID.makeGuid()), file.getParentFile(), file.getName(), true); } catch (SaveLocationException sle) { fail("There shouldn't have been an exception of type " + sle.getErrorCode()); } try { File f = File.createTempFile("notadirectory", "file"); f.deleteOnExit(); gnutellaDownloaderFactory.createManagedDownloader(rfds, new GUID(GUID.makeGuid()), f, null, false); fail("No exception thrown"); } catch (SaveLocationException sle) { assertEquals("Error code should be: file not a directory", LocationCode.NOT_A_DIRECTORY, sle.getErrorCode()); } // we force filename normalization gnutellaDownloaderFactory.createManagedDownloader(rfds, new GUID(GUID.makeGuid()), null, "./", false); gnutellaDownloaderFactory.createManagedDownloader(rfds, new GUID(GUID.makeGuid()), null, "../myfile.txt", false); // should not throw an exception gnutellaDownloaderFactory.createManagedDownloader(rfds, new GUID(GUID.makeGuid()), null, null, false); List<RemoteFileDesc> emptyRFDList = Collections.emptyList(); // already downloading based on filename and same size downloadManager.download(rfds, emptyRFDList, new GUID(GUID.makeGuid()), false, null, null); try { downloadManager.download(rfds, emptyRFDList, new GUID(GUID.makeGuid()), false, null, null); fail("No exception thrown"); } catch (SaveLocationException sle) { assertEquals("Error code should be: already downloading", LocationCode.FILE_ALREADY_DOWNLOADING, sle.getErrorCode()); } // already downloading based on hash RemoteFileDesc[] hashRFDS = new RemoteFileDesc[] { newRFD("dl", "urn:sha1:GLSTHIPQGSSZTS5FJUPAKPZWUGYQYPFB") }; downloadManager.download(hashRFDS, emptyRFDList, new GUID(GUID.makeGuid()), false, null, null); try { downloadManager.download(hashRFDS, emptyRFDList, new GUID(GUID.makeGuid()), false, null, null); fail("No exception thrown"); } catch (SaveLocationException sle) { assertEquals("Error code should be: already downloading", LocationCode.FILE_ALREADY_DOWNLOADING, sle.getErrorCode()); } // other download is already being saved to the same file with different hashes { RemoteFileDesc[] fds = new RemoteFileDesc[] { newRFD("savedto", "urn:sha1:QLSTHIPQGSSZTS5FJUPAKOZWUGZQYPFB") }; downloadManager.download(fds, emptyRFDList, new GUID(GUID.makeGuid()), false, null, "alreadysavedto"); } try { RemoteFileDesc[] fds = new RemoteFileDesc[] { newRFD("otherfd", "urn:sha1:PLSTHIPQGSSZTS5FJUPAKOZWUGZQYPFB") }; downloadManager.download(fds, emptyRFDList, new GUID(GUID.makeGuid()), false, null, "alreadysavedto"); fail("should have gotten exception!"); } catch (SaveLocationException sle) { assertEquals("Error code should be: already being saved to", LocationCode.FILE_IS_ALREADY_DOWNLOADED_TO, sle.getErrorCode()); } // TODO SaveLocationException.FILE_ALREADY_SAVED // SaveLocationException.FILESYSTEM_ERROR is not really reproducible } private RemoteFileDesc newRFD(String name) throws Exception { return newRFD(name, null); } private RemoteFileDesc newRFD(String name, String hash) throws Exception { Set<URN> urns = Collections.emptySet(); if (hash!=null) { urns=new HashSet<URN>(1); try { urns.add(URN.createSHA1Urn(hash)); } catch (IOException e) { fail("Couldn't create URN", e); } } return injector.getInstance(RemoteFileDescFactory.class).createRemoteFileDesc(new ConnectableImpl("127.0.0.1", PORT, false), 13l, name, 1024, new byte[16], 56, 4, true, null, urns, false, "", -1); } @SuppressWarnings({"unchecked", "SynchronizeOnNonFinalField"}) private void requestStart(ManagedDownloader dl) throws Exception { List<CoreDownloader> waiting = (List<CoreDownloader>)PrivilegedAccessor.getValue(downloadManager, "waiting"); List<CoreDownloader> active = (List<CoreDownloader>)PrivilegedAccessor.getValue(downloadManager, "active"); synchronized(downloadManager) { waiting.remove(dl); active.add(dl); dl.startDownload(); } } private RemoteFileDesc newPushRFD(String name, String hash, byte[] guid) throws Exception { IpPort ppi = new IpPortImpl("1.2.3.10", 2000); Set<IpPort> ppis = new TreeSet<IpPort>(IpPort.COMPARATOR); ppis.add(ppi); PushEndpointFactory pushEndpointFactory = injector.getInstance(PushEndpointFactory.class); PushEndpoint pe = pushEndpointFactory.createPushEndpoint(guid, ppis); pe.updateProxies(true); return injector.getInstance(RemoteFileDescFactory.class).createRemoteFileDesc(newRFD(name, hash), pe); } private File createMaximumPathLengthDirectory() throws IOException { File tmpFile = File.createTempFile("temp", "file"); File tmpDir = tmpFile.getParentFile(); tmpFile.delete(); char[] dirName = new char[OSUtils.getMaxPathLength() - tmpDir.getAbsolutePath().length()]; Arrays.fill(dirName, 'z'); for (int i = 0; i < dirName.length; i += 254) { dirName[i] = File.separatorChar; } File longestDir = new File(tmpDir.getAbsolutePath() + new String(dirName)); // currently fails due to JRE bug if (!longestDir.mkdirs()) { // go through path and create them one by one till JRE bug is fixed LinkedList<File> dirs = new LinkedList<File>(); File current = longestDir; while (!current.equals(tmpDir)) { dirs.add(current); current = current.getParentFile(); } while (!dirs.isEmpty()) { current = dirs.removeLast(); assertTrue("Could not create " + current, current.mkdir()); } } return longestDir; } /** * allows overriding of the list of current downloaders */ private void setDloaders(ManagedDownloader managedDownloader, List l) throws Exception { PrivilegedAccessor.setValue(managedDownloader,"_activeWorkers",l); } private void setSHA1(ManagedDownloader managedDownloader, URN sha1) throws Exception{ PrivilegedAccessor.setValue(managedDownloader,"downloadSHA1",sha1); } private void setIncompleteFile(ManagedDownloader managedDownloader, File f) throws Exception { PrivilegedAccessor.setValue(managedDownloader,"incompleteFile",f); } @Singleton private static class AltLocDownloaderStubFactory implements HTTPDownloaderFactory { private final NetworkManager networkManager; private final AlternateLocationFactory alternateLocationFactory; private final DownloadManager downloadManager; private final Provider<CreationTimeCache> creationTimeCache; private final BandwidthManager bandwidthManager; private final Provider<PushEndpointCache> pushEndpointCache; private final PushEndpointFactory pushEndpointFactory; private final RemoteFileDescFactory remoteFileDescFactory; private final ThexReaderFactory thexReaderFactory; private final TcpBandwidthStatistics tcpBandwidthStatistics; private final NetworkInstanceUtils networkInstanceUtils; @Inject public AltLocDownloaderStubFactory(NetworkManager networkManager, AlternateLocationFactory alternateLocationFactory, DownloadManager downloadManager, Provider<CreationTimeCache> creationTimeCache, BandwidthManager bandwidthManager, Provider<PushEndpointCache> pushEndpointCache, PushEndpointFactory pushEndpointFactory, RemoteFileDescFactory remoteFileDescFactory, ThexReaderFactory thexReaderFactory, TcpBandwidthStatistics tcpBandwidthStatistics, NetworkInstanceUtils networkInstanceUtils) { this.networkManager = networkManager; this.alternateLocationFactory = alternateLocationFactory; this.downloadManager = downloadManager; this.creationTimeCache = creationTimeCache; this.bandwidthManager = bandwidthManager; this.pushEndpointCache = pushEndpointCache; this.pushEndpointFactory = pushEndpointFactory; this.remoteFileDescFactory = remoteFileDescFactory; this.thexReaderFactory = thexReaderFactory; this.tcpBandwidthStatistics = tcpBandwidthStatistics; this.networkInstanceUtils = networkInstanceUtils; } public HTTPDownloader create(Socket socket, RemoteFileDescContext rfdContext, VerifyingFile incompleteFile, boolean inNetwork) { return new AltLocDownloaderStub(rfdContext, networkManager, alternateLocationFactory, downloadManager, creationTimeCache.get(), bandwidthManager, pushEndpointCache, pushEndpointFactory, remoteFileDescFactory, thexReaderFactory, tcpBandwidthStatistics, networkInstanceUtils); } } private static class AltLocDownloaderStub extends HTTPDownloaderStub { private boolean _stubFalts; private final RemoteFileDesc rfd; public AltLocDownloaderStub(RemoteFileDescContext rfdContext, NetworkManager networkManager, AlternateLocationFactory alternateLocationFactory, DownloadManager downloadManager, CreationTimeCache creationTimeCache, BandwidthManager bandwidthManager, Provider<PushEndpointCache> pushEndpointCache, PushEndpointFactory pushEndpointFactory, RemoteFileDescFactory remoteFileDescFactory, ThexReaderFactory thexReaderFactory, TcpBandwidthStatistics tcpBandwidthStatistics, NetworkInstanceUtils networkInstanceUtils) { super(rfdContext, null, networkManager, alternateLocationFactory, downloadManager, creationTimeCache, bandwidthManager, pushEndpointCache, pushEndpointFactory, remoteFileDescFactory, thexReaderFactory, tcpBandwidthStatistics, networkInstanceUtils); this.rfd = rfdContext.getRemoteFileDesc(); } public boolean _addedFailed,_addedSuccessfull; @Override public void addFailedAltLoc(AlternateLocation loc) { _addedFailed = true; } @Override public void addSuccessfulAltLoc(AlternateLocation loc) { _addedSuccessfull=true; } @Override public RemoteFileDesc getRemoteFileDesc() { return rfd; } public void setWantsFalts(boolean doesIt) { _stubFalts=doesIt; } @Override public boolean wantsFalts(){ return _stubFalts; } } @Singleton private static class AltLocWorkerStubFactory implements DownloadWorkerFactory { private final HTTPDownloaderFactory httpDownloaderFactory; private final ScheduledExecutorService backgroundExecutor; private final ScheduledExecutorService nioExecutor; private final Provider<PushDownloadManager> pushDownloadManager; private final SocketsManager socketsManager; @Inject public AltLocWorkerStubFactory( HTTPDownloaderFactory httpDownloaderFactory, @Named("backgroundExecutor") ScheduledExecutorService backgroundExecutor, @Named("nioExecutor") ScheduledExecutorService nioExecutor, Provider<PushDownloadManager> pushDownloadManager, SocketsManager socketsManager) { this.httpDownloaderFactory = httpDownloaderFactory; this.backgroundExecutor = backgroundExecutor; this.nioExecutor = nioExecutor; this.pushDownloadManager = pushDownloadManager; this.socketsManager = socketsManager; } public DownloadWorker create(DownloadWorkerSupport manager, RemoteFileDescContext rfd, VerifyingFile vf) { return new AltLocWorkerStub(manager, rfd, vf, httpDownloaderFactory, backgroundExecutor, nioExecutor, pushDownloadManager, socketsManager, networkManager); } } private static class AltLocWorkerStub extends DownloadWorkerStub { private volatile HTTPDownloader httpDownloader; public AltLocWorkerStub(DownloadWorkerSupport manager, RemoteFileDescContext rfd, VerifyingFile vf, HTTPDownloaderFactory httpDownloaderFactory, ScheduledExecutorService backgroundExecutor, ScheduledExecutorService nioExecutor, Provider<PushDownloadManager> pushDownloadManager, SocketsManager socketsManager, TLSManager TLSManager) { super(manager, rfd, vf, httpDownloaderFactory, backgroundExecutor, nioExecutor, pushDownloadManager, socketsManager, TLSManager); } public void setHTTPDownloader(HTTPDownloader httpDownloader) { this.httpDownloader = httpDownloader; } @Override public HTTPDownloader getDownloader() { return httpDownloader; } } }