├── LICENSE ├── README.md └── src └── com └── luugiathuy └── apps └── downloadmanager ├── DownloadManager.java ├── DownloadManagerGUI.form ├── DownloadManagerGUI.java ├── DownloadTableModel.java ├── Downloader.java ├── HttpDownloader.java └── ProgressRenderer.java /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011 Luu Gia Thuy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Download Manager in Java 2 | ===================== 3 | 4 | A download manager application written in Java. 5 | 6 | ##Usage 7 | Use eclipse to open the project. 8 | 9 | ##Contact 10 | [@luugiathuy](http://twitter.com/luugiathuy) 11 | -------------------------------------------------------------------------------- /src/com/luugiathuy/apps/downloadmanager/DownloadManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2011-present - Luu Gia Thuy 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | package com.luugiathuy.apps.downloadmanager; 27 | 28 | import java.net.URL; 29 | import java.util.ArrayList; 30 | 31 | public class DownloadManager { 32 | 33 | // The unique instance of this class 34 | private static DownloadManager sInstance = null; 35 | 36 | // Constant variables 37 | private static final int DEFAULT_NUM_CONN_PER_DOWNLOAD = 8; 38 | public static final String DEFAULT_OUTPUT_FOLDER = ""; 39 | 40 | // Member variables 41 | private int mNumConnPerDownload; 42 | private ArrayList mDownloadList; 43 | 44 | /** Protected constructor */ 45 | protected DownloadManager() { 46 | mNumConnPerDownload = DEFAULT_NUM_CONN_PER_DOWNLOAD; 47 | mDownloadList = new ArrayList(); 48 | } 49 | 50 | /** 51 | * Get the max. number of connections per download 52 | */ 53 | public int getNumConnPerDownload() { 54 | return mNumConnPerDownload; 55 | } 56 | 57 | /** 58 | * Set the max number of connections per download 59 | */ 60 | public void SetNumConnPerDownload(int value) { 61 | mNumConnPerDownload = value; 62 | } 63 | 64 | /** 65 | * Get the downloader object in the list 66 | * @param index 67 | * @return 68 | */ 69 | public Downloader getDownload(int index) { 70 | return mDownloadList.get(index); 71 | } 72 | 73 | public void removeDownload(int index) { 74 | mDownloadList.remove(index); 75 | } 76 | 77 | /** 78 | * Get the download list 79 | * @return 80 | */ 81 | public ArrayList getDownloadList() { 82 | return mDownloadList; 83 | } 84 | 85 | 86 | public Downloader createDownload(URL verifiedURL, String outputFolder) { 87 | HttpDownloader fd = new HttpDownloader(verifiedURL, outputFolder, mNumConnPerDownload); 88 | mDownloadList.add(fd); 89 | 90 | return fd; 91 | } 92 | 93 | /** 94 | * Get the unique instance of this class 95 | * @return the instance of this class 96 | */ 97 | public static DownloadManager getInstance() { 98 | if (sInstance == null) 99 | sInstance = new DownloadManager(); 100 | 101 | return sInstance; 102 | } 103 | 104 | /** 105 | * Verify whether an URL is valid 106 | * @param fileURL 107 | * @return the verified URL, null if invalid 108 | */ 109 | public static URL verifyURL(String fileURL) { 110 | // Only allow HTTP URLs. 111 | if (!fileURL.toLowerCase().startsWith("http://")) 112 | return null; 113 | 114 | // Verify format of URL. 115 | URL verifiedUrl = null; 116 | try { 117 | verifiedUrl = new URL(fileURL); 118 | } catch (Exception e) { 119 | return null; 120 | } 121 | 122 | // Make sure URL specifies a file. 123 | if (verifiedUrl.getFile().length() < 2) 124 | return null; 125 | 126 | return verifiedUrl; 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/com/luugiathuy/apps/downloadmanager/DownloadManagerGUI.form: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 |
154 | -------------------------------------------------------------------------------- /src/com/luugiathuy/apps/downloadmanager/DownloadManagerGUI.java: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2011-present - Luu Gia Thuy 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | package com.luugiathuy.apps.downloadmanager; 27 | 28 | import java.net.URL; 29 | import java.util.Observable; 30 | import java.util.Observer; 31 | 32 | import javax.swing.JOptionPane; 33 | import javax.swing.JProgressBar; 34 | import javax.swing.ListSelectionModel; 35 | import javax.swing.UIManager; 36 | import javax.swing.event.ListSelectionEvent; 37 | import javax.swing.event.ListSelectionListener; 38 | 39 | public class DownloadManagerGUI extends javax.swing.JFrame implements Observer{ 40 | 41 | private static final long serialVersionUID = 8489399426552541643L; 42 | 43 | private DownloadTableModel mTableModel; 44 | 45 | private Downloader mSelectedDownloader; 46 | 47 | private boolean mIsClearing; 48 | 49 | /** Creates new form DownloadManagerGUI */ 50 | public DownloadManagerGUI() { 51 | mTableModel = new DownloadTableModel(); 52 | initComponents(); 53 | initialize(); 54 | } 55 | 56 | private void initialize() { 57 | // Set up table 58 | jtbDownload.getSelectionModel().addListSelectionListener(new 59 | ListSelectionListener() { 60 | public void valueChanged(ListSelectionEvent e) { 61 | tableSelectionChanged(); 62 | } 63 | }); 64 | 65 | // Allow only one row at a time to be selected. 66 | jtbDownload.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 67 | 68 | // Set up ProgressBar as renderer for progress column. 69 | ProgressRenderer renderer = new ProgressRenderer(0, 100); 70 | renderer.setStringPainted(true); // show progress text 71 | jtbDownload.setDefaultRenderer(JProgressBar.class, renderer); 72 | 73 | // Set table's row height large enough to fit JProgressBar. 74 | jtbDownload.setRowHeight( 75 | (int) renderer.getPreferredSize().getHeight()); 76 | } 77 | 78 | /** This method is called from within the constructor to 79 | * initialize the form. 80 | * WARNING: Do NOT modify this code. The content of this method is 81 | * always regenerated by the Form Editor. 82 | */ 83 | @SuppressWarnings("unchecked") 84 | // //GEN-BEGIN:initComponents 85 | private void initComponents() { 86 | 87 | jtxURL = new javax.swing.JTextField(); 88 | jbnAdd = new javax.swing.JButton(); 89 | jScrollPane1 = new javax.swing.JScrollPane(); 90 | jtbDownload = new javax.swing.JTable(); 91 | jbnPause = new javax.swing.JButton(); 92 | jbnRemove = new javax.swing.JButton(); 93 | jbnCancel = new javax.swing.JButton(); 94 | jbnExit = new javax.swing.JButton(); 95 | jbnResume = new javax.swing.JButton(); 96 | 97 | setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 98 | setTitle("Download Manager"); 99 | setResizable(false); 100 | 101 | jbnAdd.setText("Add Download"); 102 | jbnAdd.addActionListener(new java.awt.event.ActionListener() { 103 | public void actionPerformed(java.awt.event.ActionEvent evt) { 104 | jbnAddActionPerformed(evt); 105 | } 106 | }); 107 | 108 | jtbDownload.setModel(mTableModel); 109 | jScrollPane1.setViewportView(jtbDownload); 110 | 111 | jbnPause.setText("Pause"); 112 | jbnPause.setEnabled(false); 113 | jbnPause.addActionListener(new java.awt.event.ActionListener() { 114 | public void actionPerformed(java.awt.event.ActionEvent evt) { 115 | jbnPauseActionPerformed(evt); 116 | } 117 | }); 118 | 119 | jbnRemove.setText("Remove"); 120 | jbnRemove.setEnabled(false); 121 | jbnRemove.addActionListener(new java.awt.event.ActionListener() { 122 | public void actionPerformed(java.awt.event.ActionEvent evt) { 123 | jbnRemoveActionPerformed(evt); 124 | } 125 | }); 126 | 127 | jbnCancel.setText("Cancel"); 128 | jbnCancel.setEnabled(false); 129 | jbnCancel.addActionListener(new java.awt.event.ActionListener() { 130 | public void actionPerformed(java.awt.event.ActionEvent evt) { 131 | jbnCancelActionPerformed(evt); 132 | } 133 | }); 134 | 135 | jbnExit.setText("Exit"); 136 | jbnExit.addActionListener(new java.awt.event.ActionListener() { 137 | public void actionPerformed(java.awt.event.ActionEvent evt) { 138 | jbnExitActionPerformed(evt); 139 | } 140 | }); 141 | 142 | jbnResume.setText("Resume"); 143 | jbnResume.setEnabled(false); 144 | jbnResume.addActionListener(new java.awt.event.ActionListener() { 145 | public void actionPerformed(java.awt.event.ActionEvent evt) { 146 | jbnResumeActionPerformed(evt); 147 | } 148 | }); 149 | 150 | javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); 151 | getContentPane().setLayout(layout); 152 | layout.setHorizontalGroup( 153 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 154 | .addGroup(layout.createSequentialGroup() 155 | .addContainerGap() 156 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 157 | .addGroup(layout.createSequentialGroup() 158 | .addComponent(jbnPause, javax.swing.GroupLayout.PREFERRED_SIZE, 104, javax.swing.GroupLayout.PREFERRED_SIZE) 159 | .addGap(18, 18, 18) 160 | .addComponent(jbnResume, javax.swing.GroupLayout.PREFERRED_SIZE, 109, javax.swing.GroupLayout.PREFERRED_SIZE) 161 | .addGap(18, 18, 18) 162 | .addComponent(jbnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 104, javax.swing.GroupLayout.PREFERRED_SIZE) 163 | .addGap(18, 18, 18) 164 | .addComponent(jbnRemove, javax.swing.GroupLayout.PREFERRED_SIZE, 104, javax.swing.GroupLayout.PREFERRED_SIZE) 165 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 177, Short.MAX_VALUE) 166 | .addComponent(jbnExit, javax.swing.GroupLayout.PREFERRED_SIZE, 104, javax.swing.GroupLayout.PREFERRED_SIZE)) 167 | .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() 168 | .addComponent(jtxURL, javax.swing.GroupLayout.DEFAULT_SIZE, 654, Short.MAX_VALUE) 169 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 170 | .addComponent(jbnAdd)) 171 | .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 776, Short.MAX_VALUE)) 172 | .addContainerGap()) 173 | ); 174 | 175 | layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {jbnCancel, jbnExit, jbnPause, jbnRemove, jbnResume}); 176 | 177 | layout.setVerticalGroup( 178 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 179 | .addGroup(layout.createSequentialGroup() 180 | .addContainerGap() 181 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) 182 | .addComponent(jtxURL, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) 183 | .addComponent(jbnAdd)) 184 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) 185 | .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 498, Short.MAX_VALUE) 186 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) 187 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) 188 | .addComponent(jbnPause) 189 | .addComponent(jbnResume) 190 | .addComponent(jbnCancel) 191 | .addComponent(jbnRemove) 192 | .addComponent(jbnExit)) 193 | .addContainerGap()) 194 | ); 195 | 196 | pack(); 197 | }// //GEN-END:initComponents 198 | 199 | private void jbnPauseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jbnPauseActionPerformed 200 | mSelectedDownloader.pause(); 201 | updateButtons(); 202 | }//GEN-LAST:event_jbnPauseActionPerformed 203 | 204 | private void jbnResumeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jbnResumeActionPerformed 205 | mSelectedDownloader.resume(); 206 | updateButtons(); 207 | }//GEN-LAST:event_jbnResumeActionPerformed 208 | 209 | private void jbnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jbnCancelActionPerformed 210 | mSelectedDownloader.cancel(); 211 | updateButtons(); 212 | }//GEN-LAST:event_jbnCancelActionPerformed 213 | 214 | private void jbnRemoveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jbnRemoveActionPerformed 215 | mIsClearing = true; 216 | int index = jtbDownload.getSelectedRow(); 217 | DownloadManager.getInstance().removeDownload(index); 218 | mTableModel.clearDownload(index); 219 | mIsClearing = false; 220 | mSelectedDownloader = null; 221 | updateButtons(); 222 | }//GEN-LAST:event_jbnRemoveActionPerformed 223 | 224 | private void jbnExitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jbnExitActionPerformed 225 | setVisible(false); 226 | }//GEN-LAST:event_jbnExitActionPerformed 227 | 228 | private void jbnAddActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jbnAddActionPerformed 229 | URL verifiedUrl = DownloadManager.verifyURL(jtxURL.getText()); 230 | if (verifiedUrl != null) { 231 | Downloader download = DownloadManager.getInstance().createDownload(verifiedUrl, 232 | DownloadManager.DEFAULT_OUTPUT_FOLDER); 233 | mTableModel.addNewDownload(download); 234 | jtxURL.setText(""); // reset add text field 235 | } else { 236 | JOptionPane.showMessageDialog(this, 237 | "Invalid Download URL", "Error", 238 | JOptionPane.ERROR_MESSAGE); 239 | } 240 | }//GEN-LAST:event_jbnAddActionPerformed 241 | 242 | // Called when table row selection changes. 243 | private void tableSelectionChanged() { 244 | // unregister from receiving notifications from the last selected download. 245 | if (mSelectedDownloader != null) 246 | mSelectedDownloader.deleteObserver(DownloadManagerGUI.this); 247 | 248 | // If not in the middle of clearing a download, set the selected download and register to 249 | // receive notifications from it. 250 | if (!mIsClearing) { 251 | int index = jtbDownload.getSelectedRow(); 252 | if (index != -1) { 253 | mSelectedDownloader = DownloadManager.getInstance().getDownload(jtbDownload.getSelectedRow()); 254 | mSelectedDownloader.addObserver(DownloadManagerGUI.this); 255 | } else 256 | mSelectedDownloader = null; 257 | updateButtons(); 258 | } 259 | } 260 | 261 | @Override 262 | public void update(Observable o, Object arg) { 263 | // Update buttons if the selected download has changed. 264 | if (mSelectedDownloader != null && mSelectedDownloader.equals(o)) 265 | updateButtons(); 266 | } 267 | 268 | /** 269 | * Update buttons' state 270 | */ 271 | private void updateButtons() { 272 | if (mSelectedDownloader != null) { 273 | int state = mSelectedDownloader.getState(); 274 | switch (state) { 275 | case Downloader.DOWNLOADING: 276 | jbnPause.setEnabled(true); 277 | jbnResume.setEnabled(false); 278 | jbnCancel.setEnabled(true); 279 | jbnRemove.setEnabled(false); 280 | break; 281 | case Downloader.PAUSED: 282 | jbnPause.setEnabled(false); 283 | jbnResume.setEnabled(true); 284 | jbnCancel.setEnabled(true); 285 | jbnRemove.setEnabled(false); 286 | break; 287 | case Downloader.ERROR: 288 | jbnPause.setEnabled(false); 289 | jbnResume.setEnabled(true); 290 | jbnCancel.setEnabled(false); 291 | jbnRemove.setEnabled(true); 292 | break; 293 | default: // COMPLETE or CANCELLED 294 | jbnPause.setEnabled(false); 295 | jbnResume.setEnabled(false); 296 | jbnCancel.setEnabled(false); 297 | jbnRemove.setEnabled(true); 298 | } 299 | } else { 300 | // No download is selected in table. 301 | jbnPause.setEnabled(false); 302 | jbnResume.setEnabled(false); 303 | jbnCancel.setEnabled(false); 304 | jbnRemove.setEnabled(false); 305 | } 306 | } 307 | 308 | /** 309 | * @param args the command line arguments 310 | */ 311 | public static void main(String args[]) { 312 | // set to user's look and feel 313 | try { 314 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 315 | } catch (Exception e) { 316 | } 317 | 318 | java.awt.EventQueue.invokeLater(new Runnable() { 319 | public void run() { 320 | new DownloadManagerGUI().setVisible(true); 321 | } 322 | }); 323 | } 324 | 325 | // Variables declaration - do not modify//GEN-BEGIN:variables 326 | private javax.swing.JScrollPane jScrollPane1; 327 | private javax.swing.JButton jbnAdd; 328 | private javax.swing.JButton jbnCancel; 329 | private javax.swing.JButton jbnExit; 330 | private javax.swing.JButton jbnPause; 331 | private javax.swing.JButton jbnRemove; 332 | private javax.swing.JButton jbnResume; 333 | private javax.swing.JTable jtbDownload; 334 | private javax.swing.JTextField jtxURL; 335 | // End of variables declaration//GEN-END:variables 336 | } 337 | -------------------------------------------------------------------------------- /src/com/luugiathuy/apps/downloadmanager/DownloadTableModel.java: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2011-present - Luu Gia Thuy 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | package com.luugiathuy.apps.downloadmanager; 27 | 28 | import java.util.Observable; 29 | import java.util.Observer; 30 | 31 | import javax.swing.JProgressBar; 32 | import javax.swing.table.AbstractTableModel; 33 | 34 | /** 35 | * This class manages the download table's data. 36 | * 37 | */ 38 | public class DownloadTableModel extends AbstractTableModel implements Observer { 39 | 40 | private static final long serialVersionUID = -7852567715605820609L; 41 | 42 | // These are the names for the table's columns. 43 | private static final String[] columnNames = {"URL", "Size (KB)", 44 | "Progress", "Status"}; 45 | 46 | // These are the classes for each column's values. 47 | @SuppressWarnings("rawtypes") 48 | private static final Class[] columnClasses = {String.class, 49 | String.class, JProgressBar.class, String.class}; 50 | 51 | /** 52 | * Add a new download to the table. 53 | */ 54 | public void addNewDownload(Downloader download) { 55 | // Register to be notified when the download changes. 56 | download.addObserver(this); 57 | 58 | // Fire table row insertion notification to table. 59 | fireTableRowsInserted(getRowCount() - 1, getRowCount() - 1); 60 | } 61 | 62 | 63 | /** 64 | * Remove a download from the list. 65 | */ 66 | public void clearDownload(int row) { 67 | // Fire table row deletion notification to table. 68 | fireTableRowsDeleted(row, row); 69 | } 70 | 71 | /** 72 | * Get table's column count. 73 | */ 74 | public int getColumnCount() { 75 | return columnNames.length; 76 | } 77 | 78 | /** 79 | * Get a column's name. 80 | */ 81 | public String getColumnName(int col) { 82 | return columnNames[col]; 83 | } 84 | 85 | /** 86 | * Get a column's class. 87 | */ 88 | @SuppressWarnings({ "rawtypes", "unchecked" }) 89 | public Class getColumnClass(int col) { 90 | return columnClasses[col]; 91 | } 92 | 93 | /** 94 | * Get table's row count. 95 | */ 96 | public int getRowCount() { 97 | return DownloadManager.getInstance().getDownloadList().size(); 98 | } 99 | 100 | /** 101 | * Get value for a specific row and column combination. 102 | */ 103 | public Object getValueAt(int row, int col) { 104 | // Get download from download list 105 | Downloader download = DownloadManager.getInstance().getDownloadList().get(row); 106 | 107 | switch (col) { 108 | case 0: // URL 109 | return download.getURL(); 110 | case 1: // Size 111 | int size = download.getFileSize(); 112 | return (size == -1) ? "" : (Integer.toString(size/1000)); 113 | case 2: // Progress 114 | return new Float(download.getProgress()); 115 | case 3: // Status 116 | return Downloader.STATUSES[download.getState()]; 117 | } 118 | return ""; 119 | } 120 | 121 | /** 122 | * Update is called when a Download notifies its observers of any changes 123 | */ 124 | public void update(Observable o, Object arg) { 125 | int index = DownloadManager.getInstance().getDownloadList().indexOf(o); 126 | 127 | // Fire table row update notification to table. 128 | fireTableRowsUpdated(index, index); 129 | } 130 | } -------------------------------------------------------------------------------- /src/com/luugiathuy/apps/downloadmanager/Downloader.java: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2011-present - Luu Gia Thuy 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | package com.luugiathuy.apps.downloadmanager; 27 | 28 | import java.net.URL; 29 | import java.util.ArrayList; 30 | import java.util.Observable; 31 | 32 | public abstract class Downloader extends Observable implements Runnable{ 33 | 34 | // Member variables 35 | /** The URL to download the file */ 36 | protected URL mURL; 37 | 38 | /** Output folder for downloaded file */ 39 | protected String mOutputFolder; 40 | 41 | /** Number of connections (threads) to download the file */ 42 | protected int mNumConnections; 43 | 44 | /** The file name, extracted from URL */ 45 | protected String mFileName; 46 | 47 | /** Size of the downloaded file (in bytes) */ 48 | protected int mFileSize; 49 | 50 | /** The state of the download */ 51 | protected int mState; 52 | 53 | /** downloaded size of the file (in bytes) */ 54 | protected int mDownloaded; 55 | 56 | /** List of download threads */ 57 | protected ArrayList mListDownloadThread; 58 | 59 | // Contants for block and buffer size 60 | protected static final int BLOCK_SIZE = 4096; 61 | protected static final int BUFFER_SIZE = 4096; 62 | protected static final int MIN_DOWNLOAD_SIZE = BLOCK_SIZE * 100; 63 | 64 | // These are the status names. 65 | public static final String STATUSES[] = {"Downloading", 66 | "Paused", "Complete", "Cancelled", "Error"}; 67 | 68 | // Contants for download's state 69 | public static final int DOWNLOADING = 0; 70 | public static final int PAUSED = 1; 71 | public static final int COMPLETED = 2; 72 | public static final int CANCELLED = 3; 73 | public static final int ERROR = 4; 74 | 75 | /** 76 | * Constructor 77 | * @param fileURL 78 | * @param outputFolder 79 | * @param numConnections 80 | */ 81 | protected Downloader(URL url, String outputFolder, int numConnections) { 82 | mURL = url; 83 | mOutputFolder = outputFolder; 84 | mNumConnections = numConnections; 85 | 86 | // Get the file name from url path 87 | String fileURL = url.getFile(); 88 | mFileName = fileURL.substring(fileURL.lastIndexOf('/') + 1); 89 | System.out.println("File name: " + mFileName); 90 | mFileSize = -1; 91 | mState = DOWNLOADING; 92 | mDownloaded = 0; 93 | 94 | mListDownloadThread = new ArrayList(); 95 | } 96 | 97 | /** 98 | * Pause the downloader 99 | */ 100 | public void pause() { 101 | setState(PAUSED); 102 | } 103 | 104 | /** 105 | * Resume the downloader 106 | */ 107 | public void resume() { 108 | setState(DOWNLOADING); 109 | download(); 110 | } 111 | 112 | /** 113 | * Cancel the downloader 114 | */ 115 | public void cancel() { 116 | setState(CANCELLED); 117 | } 118 | 119 | /** 120 | * Get the URL (in String) 121 | */ 122 | public String getURL() { 123 | return mURL.toString(); 124 | } 125 | 126 | /** 127 | * Get the downloaded file's size 128 | */ 129 | public int getFileSize() { 130 | return mFileSize; 131 | } 132 | 133 | /** 134 | * Get the current progress of the download 135 | */ 136 | public float getProgress() { 137 | return ((float)mDownloaded / mFileSize) * 100; 138 | } 139 | 140 | /** 141 | * Get current state of the downloader 142 | */ 143 | public int getState() { 144 | return mState; 145 | } 146 | 147 | /** 148 | * Set the state of the downloader 149 | */ 150 | protected void setState(int value) { 151 | mState = value; 152 | stateChanged(); 153 | } 154 | 155 | /** 156 | * Start or resume download 157 | */ 158 | protected void download() { 159 | Thread t = new Thread(this); 160 | t.start(); 161 | } 162 | 163 | /** 164 | * Increase the downloaded size 165 | */ 166 | protected synchronized void downloaded(int value) { 167 | mDownloaded += value; 168 | stateChanged(); 169 | } 170 | 171 | /** 172 | * Set the state has changed and notify the observers 173 | */ 174 | protected void stateChanged() { 175 | setChanged(); 176 | notifyObservers(); 177 | } 178 | 179 | /** 180 | * Thread to download part of a file 181 | */ 182 | protected abstract class DownloadThread implements Runnable { 183 | protected int mThreadID; 184 | protected URL mURL; 185 | protected String mOutputFile; 186 | protected int mStartByte; 187 | protected int mEndByte; 188 | protected boolean mIsFinished; 189 | protected Thread mThread; 190 | 191 | public DownloadThread(int threadID, URL url, String outputFile, int startByte, int endByte) { 192 | mThreadID = threadID; 193 | mURL = url; 194 | mOutputFile = outputFile; 195 | mStartByte = startByte; 196 | mEndByte = endByte; 197 | mIsFinished = false; 198 | 199 | download(); 200 | } 201 | 202 | /** 203 | * Get whether the thread is finished download the part of file 204 | */ 205 | public boolean isFinished() { 206 | return mIsFinished; 207 | } 208 | 209 | /** 210 | * Start or resume the download 211 | */ 212 | public void download() { 213 | mThread = new Thread(this); 214 | mThread.start(); 215 | } 216 | 217 | /** 218 | * Waiting for the thread to finish 219 | * @throws InterruptedException 220 | */ 221 | public void waitFinish() throws InterruptedException { 222 | mThread.join(); 223 | } 224 | 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /src/com/luugiathuy/apps/downloadmanager/HttpDownloader.java: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2011-present - Luu Gia Thuy 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | package com.luugiathuy.apps.downloadmanager; 27 | 28 | import java.io.BufferedInputStream; 29 | import java.io.IOException; 30 | import java.io.RandomAccessFile; 31 | import java.net.HttpURLConnection; 32 | import java.net.URL; 33 | 34 | public class HttpDownloader extends Downloader{ 35 | 36 | public HttpDownloader(URL url, String outputFolder, int numConnections) { 37 | super(url, outputFolder, numConnections); 38 | download(); 39 | } 40 | 41 | private void error() { 42 | System.out.println("ERROR"); 43 | setState(ERROR); 44 | } 45 | 46 | @Override 47 | public void run() { 48 | HttpURLConnection conn = null; 49 | try { 50 | // Open connection to URL 51 | conn = (HttpURLConnection)mURL.openConnection(); 52 | conn.setConnectTimeout(10000); 53 | 54 | // Connect to server 55 | conn.connect(); 56 | 57 | // Make sure the response code is in the 200 range. 58 | if (conn.getResponseCode() / 100 != 2) { 59 | error(); 60 | } 61 | 62 | // Check for valid content length. 63 | int contentLength = conn.getContentLength(); 64 | if (contentLength < 1) { 65 | error(); 66 | } 67 | 68 | if (mFileSize == -1) { 69 | mFileSize = contentLength; 70 | stateChanged(); 71 | System.out.println("File size: " + mFileSize); 72 | } 73 | 74 | // if the state is DOWNLOADING (no error) -> start downloading 75 | if (mState == DOWNLOADING) { 76 | // check whether we have list of download threads or not, if not -> init download 77 | if (mListDownloadThread.size() == 0) 78 | { 79 | if (mFileSize > MIN_DOWNLOAD_SIZE) { 80 | // downloading size for each thread 81 | int partSize = Math.round(((float)mFileSize / mNumConnections) / BLOCK_SIZE) * BLOCK_SIZE; 82 | System.out.println("Part size: " + partSize); 83 | 84 | // start/end Byte for each thread 85 | int startByte = 0; 86 | int endByte = partSize - 1; 87 | HttpDownloadThread aThread = new HttpDownloadThread(1, mURL, mOutputFolder + mFileName, startByte, endByte); 88 | mListDownloadThread.add(aThread); 89 | int i = 2; 90 | while (endByte < mFileSize) { 91 | startByte = endByte + 1; 92 | endByte += partSize; 93 | aThread = new HttpDownloadThread(i, mURL, mOutputFolder + mFileName, startByte, endByte); 94 | mListDownloadThread.add(aThread); 95 | ++i; 96 | } 97 | } else 98 | { 99 | HttpDownloadThread aThread = new HttpDownloadThread(1, mURL, mOutputFolder + mFileName, 0, mFileSize); 100 | mListDownloadThread.add(aThread); 101 | } 102 | } else { // resume all downloading threads 103 | for (int i=0; i