SpeedDemon - has developed been developed in a highly modular fashion. By default, it supports HTTP 1.1 & 1.0. In fact, this support for HTTP is actually developed as a plugin to prove its modular & loosely coupled architecture. Support for a protocol is developed by implementing the 'IProtocolWrapper' interface in the 'sd.core.downloadmanager' package. The class which implements this interface along with any of it's supporting classes, should be packaged as a JAR file, and the Manifest's 'Main-Class' entry should point to this implementing class with the fully qualified package name (usual Manifest rules). This JAR must then be placed in the 'pw' (ProtocolWrapper) directory of the SpeedDemon main directory. If this package in turn depends upon other packages, then they should be placed in the 'ext' (External libraries) directory of the SpeedDemon directory.

A screenshot of the SpeedDemon project.

Working: I am going to explain the working by taking the HTTP support I have built. The 'CoreDownloadManager' is instantiated for every file that is being downloaded. This inturn has references to 'CoreDownloadWorkers' which interact with the 'IProtocolWrapper' implementation. For each URL entered in the 'Mirrors' screen, there is one 'CoreDownloadWorker'. The 'ProtocolWrapperFactory' dispenses out to the 'CoreDownloadWorker', new instances of 'IProtocolWrapper' implementations which have been registered by placing the JAR files in the 'pw' directory as explained earlier. The 'CoreDownloadManager' first collects information about the file it is about to download by invoking the 'getDownloadInfo()' method on each of the 'CoreDownloadWorkers'. The 'CoreDownloadWorker' actually invokes the 'IProtocolWrapper' 'getDownloadInfo()' in a separate thread. After which, the 'CoreDownloadWorker' expects the 'ProtocolWrapper' to fill in details such as - Content Length, Resume supported or not. For each such 'CoreDownloadWorkers', the 'CoreDownloadManager' goes through the results and retains only the URLs which support resuming, if there are any at all; or, retains all the URLs if none of them support resuming.

               After this information has been collected, the user is prompted to specify the download directory and the file to save as. Also, the user can change the default 'CHUNK_SIZE' which would have been read from the 'SpeedDemon.properties' file in the main 'SpeedDemon' directory. Note that, this 'CHUNK_SIZE' cannot be lower than 1/7th of the size of the file being downloaded. This is just a precautionary measure to prevent spawning a large number of downloading-threads which can overload the system.

               Now, the 'CoreDownloadManager' instantiates as many 'CoreDownloadWorkers' as there are URLs. Note that, if resuming is supported, then the number of 'CodeDownloadWorkers' will be ~= (File size/Chunk size). Suppose resuming is not supported, then there will be only one 'CoreDownloadWorker'. Each worker will have a Range start and a Range end, which specifies what range of bytes it has to download. This information will be passed to its corresponding 'IProtocolWrapper' implementation. Sequence diagrams: Part 1 and Part 2

               When 'Stop' is clicked, the current state of the download is stored by serializing both the 'CoreDownloadManager' and its 'CoreDownloadWorkers' into 'DownloadInfo.ser' file. The 'IProtocolWrappers' will not be saved. They will be created afresh when the download is resumed. The downloading-threads keep saving their bytes they download into separate files in its specific directory. When all the downloading-threads complete, the separate files will be re-combined and saved into the directory that would have been specified by the user. The temporary directory where the downloading-threads store their bytes is specific to each file that the user downloads. The names of these directories are computed by hashing the URL that the user first specifies into an MD5 string.

               Coming to the GUI, it has been designed very carefully so as not to slow-down or deadlock the 'AWT-EventHandler' thread. Also since there are multiple threads downloading the files, updating the UI quickly is of utmost importance. As said earlier, I have followed strictly the MVC, Observer, Factory, Singleton and the Visitor patterns. The UI updating is absolutely thread-safe. The 'DownloadPanelController' and the 'DownloadStatusPanelController' are very complex I must confess. It took me quite some time to design them. Simply put, they are like 2 state machines. I suggest you read the code to understand them better.

               The 'MainFrame' is the main 'JFrame' class. It is a Singleton object, and therefore has a static method to access the single instance. The MainFrame's 'JDesktopPane', 'Command menu' and the 'JMenubar' have public access and so can be accessed/used by plugins.

               To prevent multiple instances of SpeedDemon from being opened, SpeedDemon opens a 'ServerSocket' at the port number specified by the 'SERVER_PORT' field in the 'SpeedDemon.properties' file. Allowing multiple multiple instances might corrupt the 'URLs.ser' file which stores the serialized list of URLs that have been downloaded so far.


SpeedDemon source code statistics - from JavaNCSS, a Source Measurement Suite for Java

Nr.   Classes Functions      NCSS Package
  1         1        10        82 http_protocolwrapper
  2         2         7        86 sd
  3         5        86       552 sd.core.downloadmanager
  4         1        11       151 sd.gui
  5        13        64      1502 sd.gui.downloadmanager
  6         2        17       223 sd.util
    --------- --------- ---------
           24       195      2596 Total

 Packages   Classes Functions      NCSS | per
---------------------------------------------------
     6.00     24.00    195.00  2,596.00 | Project
               4.00     32.50    432.67 | Package
                         8.13    108.17 | Class
                                  13.31 | Function

Nr. NCSS Functions Classes Javadocs Class
  1    9         0       0        1 sd.GlobalConstants
  2   63         7       1        4 sd.SpeedDemon
  3  217        35       0       11 sd.core.downloadmanager.CoreDownloadManager
  4  210        35       2        6 sd.core.downloadmanager.CoreDownloadWorker
  5   46         6       0        3 sd.core.downloadmanager.InputOutput
  6    7         6       0        1 sd.core.downloadmanager.IProtocolWrapper
  7   44         4       0        2 sd.core.downloadmanager.ProtocolWrapperFactory
  8  139        11       7        4 sd.gui.MainFrame
  9   12         3       0        3 sd.gui.downloadmanager.AddURLsPanel
 10   12         3       0        3 sd.gui.downloadmanager.BlankPanel
 11  109         7       3        3 sd.gui.downloadmanager.DownloadListPanel
 12   91         6       0        6 sd.gui.downloadmanager.DownloadManager
 13   11         0       0        1 sd.gui.downloadmanager.DownloadManagerGUIConstants
 14   45         3       0        3 sd.gui.downloadmanager.DownloadPanel
 15  482        13       4        7 sd.gui.downloadmanager.DownloadPanelController
 16   53         3       2        3 sd.gui.downloadmanager.DownloadStatusPanel
 17  314         8       4        5 sd.gui.downloadmanager.DownloadStatusPanelController
 18   36         3       0        3 sd.gui.downloadmanager.DownloadStatusPanelListComponent
 19  140         8       5        5 sd.gui.downloadmanager.FullDownloadDetailsPanel
 20  101         6       0        1 sd.gui.downloadmanager.GridLayout2
 21    2         1       0        1 sd.gui.downloadmanager.IHost
 22   14         1       0        2 sd.util.FileRecombiner
 23  201        16       5        0 sd.util.MD5
 24   73        10       0        2 http_protocolwrapper.HTTP_ProtocolWrapper
Average Object NCSS:              101.29
Average Object Functions:           8.13
Average Object Inner Classes:       1.38
Average Object Javadoc Comments:    3.33
Program NCSS:                    2,596.00