extensions/net.sf.basedb.torrent/trunk/src/main/net/sf/basedb/clients/torrent/service/TorrentService.java

Code
Comments
Other
Rev Date Author Line
1246 21 Oct 10 nicklas 1 /**
1246 21 Oct 10 nicklas 2   $Id$
1246 21 Oct 10 nicklas 3
1246 21 Oct 10 nicklas 4   Copyright (C) 2010 Nicklas Nordborg
1246 21 Oct 10 nicklas 5
1246 21 Oct 10 nicklas 6   This file is part of Bittorent download service for BASE.
1246 21 Oct 10 nicklas 7   Available at http://baseplugins.thep.lu.se/
1246 21 Oct 10 nicklas 8
1246 21 Oct 10 nicklas 9   BASE is free software; you can redistribute it and/or
1246 21 Oct 10 nicklas 10   modify it under the terms of the GNU General Public License
1246 21 Oct 10 nicklas 11   as published by the Free Software Foundation; either version 2
1246 21 Oct 10 nicklas 12   of the License, or (at your option) any later version.
1246 21 Oct 10 nicklas 13
1246 21 Oct 10 nicklas 14   BASE is distributed in the hope that it will be useful,
1246 21 Oct 10 nicklas 15   but WITHOUT ANY WARRANTY; without even the implied warranty of
1246 21 Oct 10 nicklas 16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1246 21 Oct 10 nicklas 17   GNU General Public License for more details.
1246 21 Oct 10 nicklas 18
1246 21 Oct 10 nicklas 19   You should have received a copy of the GNU General Public License
1246 21 Oct 10 nicklas 20   along with this program; if not, write to the Free Software
1246 21 Oct 10 nicklas 21   Foundation, Inc., 59 Temple Place - Suite 330,
1246 21 Oct 10 nicklas 22   Boston, MA  02111-1307, USA.
1246 21 Oct 10 nicklas 23 */
1246 21 Oct 10 nicklas 24 package net.sf.basedb.clients.torrent.service;
1246 21 Oct 10 nicklas 25
1246 21 Oct 10 nicklas 26
1251 22 Oct 10 nicklas 27 import hpbtc.protocol.processor.Client;
1255 22 Oct 10 nicklas 28 import hpbtc.protocol.torrent.Torrent;
1251 22 Oct 10 nicklas 29
1255 22 Oct 10 nicklas 30 import java.io.File;
1304 03 Mar 11 nicklas 31 import java.io.FileInputStream;
1251 22 Oct 10 nicklas 32 import java.io.IOException;
1255 22 Oct 10 nicklas 33 import java.io.InputStream;
1304 03 Mar 11 nicklas 34 import java.io.InputStreamReader;
1253 22 Oct 10 nicklas 35 import java.net.InetAddress;
1253 22 Oct 10 nicklas 36 import java.net.InetSocketAddress;
1255 22 Oct 10 nicklas 37 import java.util.ArrayList;
1255 22 Oct 10 nicklas 38 import java.util.Collections;
1255 22 Oct 10 nicklas 39 import java.util.List;
1246 21 Oct 10 nicklas 40 import java.util.Properties;
1255 22 Oct 10 nicklas 41 import java.util.TimerTask;
1246 21 Oct 10 nicklas 42
1255 22 Oct 10 nicklas 43 import net.sf.basedb.core.Application;
1246 21 Oct 10 nicklas 44 import net.sf.basedb.core.Config;
1246 21 Oct 10 nicklas 45 import net.sf.basedb.core.ConfigurationException;
1255 22 Oct 10 nicklas 46 import net.sf.basedb.core.DbControl;
1299 25 Feb 11 nicklas 47 import net.sf.basedb.core.Job;
1255 22 Oct 10 nicklas 48 import net.sf.basedb.core.SessionControl;
1299 25 Feb 11 nicklas 49 import net.sf.basedb.core.Application.Pinger;
1304 03 Mar 11 nicklas 50 import net.sf.basedb.core.signal.LocalSignalReceiver;
1255 22 Oct 10 nicklas 51 import net.sf.basedb.util.FileUtil;
1246 21 Oct 10 nicklas 52 import net.sf.basedb.util.Values;
1246 21 Oct 10 nicklas 53
1246 21 Oct 10 nicklas 54 import org.slf4j.Logger;
1246 21 Oct 10 nicklas 55 import org.slf4j.LoggerFactory;
1246 21 Oct 10 nicklas 56
1246 21 Oct 10 nicklas 57
1246 21 Oct 10 nicklas 58 /**
1246 21 Oct 10 nicklas 59   This is the main service class. It is a singleton. Use {@link #getInstance()} to get
1246 21 Oct 10 nicklas 60   the active instance. The service is initialized by a {@link TorrentServiceController}
1246 21 Oct 10 nicklas 61   by calling {@link #getInstance(Properties)}.
1246 21 Oct 10 nicklas 62   
1246 21 Oct 10 nicklas 63   @author Nicklas
1246 21 Oct 10 nicklas 64   @since 1.0
1246 21 Oct 10 nicklas 65 */
1246 21 Oct 10 nicklas 66 public class TorrentService 
1246 21 Oct 10 nicklas 67 {
1246 21 Oct 10 nicklas 68
1246 21 Oct 10 nicklas 69   private static final Logger log = LoggerFactory.getLogger(TorrentService.class);
1246 21 Oct 10 nicklas 70   
1246 21 Oct 10 nicklas 71   
1246 21 Oct 10 nicklas 72   private static TorrentService service;
1246 21 Oct 10 nicklas 73
1246 21 Oct 10 nicklas 74   /**
1246 21 Oct 10 nicklas 75     Get the currently active torrent service instance.
1246 21 Oct 10 nicklas 76     @throws IllegalStateException If no service has been created
1246 21 Oct 10 nicklas 77     @see #getInstance(Properties)
1246 21 Oct 10 nicklas 78   */
1246 21 Oct 10 nicklas 79   public static TorrentService getInstance()
1246 21 Oct 10 nicklas 80   {
1246 21 Oct 10 nicklas 81     if (service == null) 
1246 21 Oct 10 nicklas 82     {
1246 21 Oct 10 nicklas 83       throw new IllegalStateException("The service has not been initialized");
1246 21 Oct 10 nicklas 84     }
1246 21 Oct 10 nicklas 85     return service;
1246 21 Oct 10 nicklas 86   }
1246 21 Oct 10 nicklas 87   
1246 21 Oct 10 nicklas 88   /**
1246 21 Oct 10 nicklas 89     Initialize the singleton instance. Calling this method multiple times
1246 21 Oct 10 nicklas 90     has no effect.
1246 21 Oct 10 nicklas 91     
1246 21 Oct 10 nicklas 92     @param properties Configuration properties for the service
1246 21 Oct 10 nicklas 93     @return
1246 21 Oct 10 nicklas 94   */
1246 21 Oct 10 nicklas 95   public static synchronized TorrentService getInstance(Properties properties)
1246 21 Oct 10 nicklas 96   {
1246 21 Oct 10 nicklas 97     if (service == null)
1246 21 Oct 10 nicklas 98     {
1246 21 Oct 10 nicklas 99       service = new TorrentService(properties);
1246 21 Oct 10 nicklas 100     }
1246 21 Oct 10 nicklas 101     return service;
1246 21 Oct 10 nicklas 102   }
1246 21 Oct 10 nicklas 103
1246 21 Oct 10 nicklas 104   private final java.io.File workDir;
1253 22 Oct 10 nicklas 105   private final String address;
1246 21 Oct 10 nicklas 106   private final int port;
1255 22 Oct 10 nicklas 107   private final String username;
1255 22 Oct 10 nicklas 108   private final String password;
1255 22 Oct 10 nicklas 109   
1251 22 Oct 10 nicklas 110   private volatile boolean isRunning;
1251 22 Oct 10 nicklas 111   private Client btClient;
1253 22 Oct 10 nicklas 112   private InetSocketAddress listenAddress;
1255 22 Oct 10 nicklas 113   private List<TorrentManager> torrentManagers;
1255 22 Oct 10 nicklas 114   private SessionControl sc;
1299 25 Feb 11 nicklas 115   private Pinger pinger;
1304 03 Mar 11 nicklas 116   private LocalSignalReceiver signalReciever;
1255 22 Oct 10 nicklas 117   private volatile TimerTask serviceTask;
1246 21 Oct 10 nicklas 118   
1246 21 Oct 10 nicklas 119   /**
1246 21 Oct 10 nicklas 120     Create a new Bittorrent download service.     
1246 21 Oct 10 nicklas 121   */
1246 21 Oct 10 nicklas 122   private TorrentService(Properties properties)
1246 21 Oct 10 nicklas 123   {
1246 21 Oct 10 nicklas 124     String dir = Values.getStringOrNull(properties.getProperty("torrents.work-dir"));
1246 21 Oct 10 nicklas 125     if (dir == null) 
1246 21 Oct 10 nicklas 126     {
1246 21 Oct 10 nicklas 127       dir = Config.getString("userfiles") + java.io.File.separator + "torrent-service";
1246 21 Oct 10 nicklas 128     }
1246 21 Oct 10 nicklas 129     this.workDir = new java.io.File(dir);
1253 22 Oct 10 nicklas 130     this.address = Values.getStringOrNull(properties.getProperty("torrents.listen-address"));
1246 21 Oct 10 nicklas 131     this.port = Values.getInt(properties.getProperty("torrents.listen-port"));
1255 22 Oct 10 nicklas 132     this.username = "root";
1255 22 Oct 10 nicklas 133     this.password = "root";
1246 21 Oct 10 nicklas 134   }
1246 21 Oct 10 nicklas 135
1246 21 Oct 10 nicklas 136   /**
1246 21 Oct 10 nicklas 137     Checks if the torrent service core is running
1246 21 Oct 10 nicklas 138   */
1246 21 Oct 10 nicklas 139   public boolean isRunning()
1246 21 Oct 10 nicklas 140   {
1246 21 Oct 10 nicklas 141     return isRunning;
1246 21 Oct 10 nicklas 142   }
1246 21 Oct 10 nicklas 143
1246 21 Oct 10 nicklas 144   /**
1246 21 Oct 10 nicklas 145     Starts the core service if it is not already running.
1246 21 Oct 10 nicklas 146   */
1251 22 Oct 10 nicklas 147   public synchronized void start()
1246 21 Oct 10 nicklas 148   {
1246 21 Oct 10 nicklas 149     if (isRunning()) return;
1246 21 Oct 10 nicklas 150     log.info("Starting Bittorrent Download Service");
1246 21 Oct 10 nicklas 151     log.debug("Working directory: " + workDir);
1253 22 Oct 10 nicklas 152     log.debug("Listen address: " + address);
1246 21 Oct 10 nicklas 153     log.debug("Listen port: " + port);
1255 22 Oct 10 nicklas 154     log.debug("Username: " + username);
1246 21 Oct 10 nicklas 155     
1246 21 Oct 10 nicklas 156     // Check if the working directory exists...
1246 21 Oct 10 nicklas 157     if (!workDir.exists() || !workDir.isDirectory())
1246 21 Oct 10 nicklas 158     {
1246 21 Oct 10 nicklas 159       // ... if not, try to created it.
1246 21 Oct 10 nicklas 160       if (!workDir.mkdirs())
1246 21 Oct 10 nicklas 161       {
1246 21 Oct 10 nicklas 162         throw new ConfigurationException("Working directory doesn't exists: " + workDir);
1246 21 Oct 10 nicklas 163       }
1246 21 Oct 10 nicklas 164       log.info("Working directory didn't exist but could be created: " + workDir);
1246 21 Oct 10 nicklas 165     }
1246 21 Oct 10 nicklas 166     
1251 22 Oct 10 nicklas 167       // Start bittorrent service
1251 22 Oct 10 nicklas 168       Client tmpClient = null;
1251 22 Oct 10 nicklas 169       try
1251 22 Oct 10 nicklas 170       {
1255 22 Oct 10 nicklas 171         // Login to BASE
1255 22 Oct 10 nicklas 172         log.debug("Logging in to BASE as user '" + username + "'");
1255 22 Oct 10 nicklas 173         sc = Application.newSessionControl(null, "local-bittorrent", null);
1636 03 May 12 nicklas 174         sc.login(username, password, "Bittorrent download service");
1299 25 Feb 11 nicklas 175         pinger = Application.newPinger(sc);
1255 22 Oct 10 nicklas 176         log.debug("Login successful");
1255 22 Oct 10 nicklas 177
1255 22 Oct 10 nicklas 178         // Create a bittorrent client
1253 22 Oct 10 nicklas 179         InetAddress tmpAddress = null;
1253 22 Oct 10 nicklas 180         if (address != null) tmpAddress = InetAddress.getByName(address);
1253 22 Oct 10 nicklas 181         InetSocketAddress socketAddress = new InetSocketAddress(tmpAddress, port);
1255 22 Oct 10 nicklas 182         log.debug("Creating bittorrent client on " + socketAddress);
1636 03 May 12 nicklas 183         String peerId = "BASE@" + Application.getHostName();
1636 03 May 12 nicklas 184         if (peerId.length() > 20) peerId = peerId.substring(0,  20);
1636 03 May 12 nicklas 185         tmpClient = new Client(peerId.getBytes());
1253 22 Oct 10 nicklas 186         listenAddress = tmpClient.startProtocol(socketAddress);
1253 22 Oct 10 nicklas 187         log.debug("Connected to: " + listenAddress);
1251 22 Oct 10 nicklas 188       }
1251 22 Oct 10 nicklas 189       catch (IOException ex)
1251 22 Oct 10 nicklas 190       {
1251 22 Oct 10 nicklas 191         log.error("Could not start bittorrent client", ex);
1251 22 Oct 10 nicklas 192         throw new RuntimeException(ex);
1251 22 Oct 10 nicklas 193       }
1251 22 Oct 10 nicklas 194       
1255 22 Oct 10 nicklas 195       this.btClient = tmpClient;
1255 22 Oct 10 nicklas 196     this.torrentManagers = Collections.synchronizedList(new ArrayList<TorrentManager>());
1304 03 Mar 11 nicklas 197     this.signalReciever = new LocalSignalReceiver();
1304 03 Mar 11 nicklas 198     this.signalReciever.init("torrent-service:0");
1304 03 Mar 11 nicklas 199     
1304 03 Mar 11 nicklas 200     loadExistingTorrents();
1304 03 Mar 11 nicklas 201           
1255 22 Oct 10 nicklas 202     this.isRunning = true;
1246 21 Oct 10 nicklas 203     log.info("Bittorrent Download Service has been started");
1246 21 Oct 10 nicklas 204   }
1246 21 Oct 10 nicklas 205   
1246 21 Oct 10 nicklas 206   /**
1246 21 Oct 10 nicklas 207     Stop the Bittorrent service. Before it can be used again a new instance
1246 21 Oct 10 nicklas 208     must be created by calling {@link #getInstance(Properties)}.
1246 21 Oct 10 nicklas 209   */
1251 22 Oct 10 nicklas 210   public synchronized void stop()
1246 21 Oct 10 nicklas 211   {
1246 21 Oct 10 nicklas 212     if (!isRunning()) return;
1246 21 Oct 10 nicklas 213     log.info("Stopping Bittorrent Download Service");
1255 22 Oct 10 nicklas 214
1255 22 Oct 10 nicklas 215     isRunning = false;
1255 22 Oct 10 nicklas 216
1304 03 Mar 11 nicklas 217     if (signalReciever != null) signalReciever.close(1000);
1304 03 Mar 11 nicklas 218     signalReciever = null;
1255 22 Oct 10 nicklas 219     if (serviceTask != null) serviceTask.cancel();
1255 22 Oct 10 nicklas 220     serviceTask = null;
1299 25 Feb 11 nicklas 221     if (pinger != null) pinger.stop();
1299 25 Feb 11 nicklas 222     pinger = null;
1255 22 Oct 10 nicklas 223     if (sc != null) closeSessionControl();
1255 22 Oct 10 nicklas 224     sc = null;
1255 22 Oct 10 nicklas 225     if (btClient != null) closeBtClient();
1255 22 Oct 10 nicklas 226     btClient = null;
1255 22 Oct 10 nicklas 227     torrentManagers.clear();
1255 22 Oct 10 nicklas 228     torrentManagers = null;
1255 22 Oct 10 nicklas 229     service = null;
1255 22 Oct 10 nicklas 230     log.info("Bittorrent Download Service has been stopped");
1255 22 Oct 10 nicklas 231   }
1255 22 Oct 10 nicklas 232
1304 03 Mar 11 nicklas 233   private void loadExistingTorrents()
1304 03 Mar 11 nicklas 234   {
1304 03 Mar 11 nicklas 235     // Iterate all subdirs in workDir
1304 03 Mar 11 nicklas 236     for (File subDir : workDir.listFiles())
1304 03 Mar 11 nicklas 237     {
1304 03 Mar 11 nicklas 238       if (!subDir.isDirectory()) continue; // with next file
1304 03 Mar 11 nicklas 239       
1304 03 Mar 11 nicklas 240       File jobProperties = new File(subDir, "job.properties");
1304 03 Mar 11 nicklas 241       if (!jobProperties.exists()) continue; // with next file
1304 03 Mar 11 nicklas 242       
1304 03 Mar 11 nicklas 243       Properties p = new Properties();
1304 03 Mar 11 nicklas 244       try
1304 03 Mar 11 nicklas 245       {
1304 03 Mar 11 nicklas 246         p.load(new InputStreamReader(new FileInputStream(jobProperties), "UTF-8"));
1304 03 Mar 11 nicklas 247       }
1304 03 Mar 11 nicklas 248       catch (Exception ex)
1304 03 Mar 11 nicklas 249       {
1304 03 Mar 11 nicklas 250         log.warn("Could not load " + jobProperties, ex);
1304 03 Mar 11 nicklas 251       }
1304 03 Mar 11 nicklas 252       int jobId = Values.getInt(p.getProperty("job.id"));
1304 03 Mar 11 nicklas 253       String name = p.getProperty("original-filename");
1304 03 Mar 11 nicklas 254       if (jobId > 0 && name != null)
1304 03 Mar 11 nicklas 255       {
1304 03 Mar 11 nicklas 256         log.debug("Resuming download: " + name + "; jobId=" +jobId);
1304 03 Mar 11 nicklas 257         registerTorrentManager(new TorrentManager(this, subDir, name, jobId));
1304 03 Mar 11 nicklas 258       }
1304 03 Mar 11 nicklas 259     }
1304 03 Mar 11 nicklas 260   }
1304 03 Mar 11 nicklas 261   
1255 22 Oct 10 nicklas 262   /**
1255 22 Oct 10 nicklas 263     Safely close the session control. Catches all exceptions but log
1255 22 Oct 10 nicklas 264     them to the logger.
1255 22 Oct 10 nicklas 265   */
1255 22 Oct 10 nicklas 266   private void closeSessionControl()
1255 22 Oct 10 nicklas 267   {
1255 22 Oct 10 nicklas 268     try
1255 22 Oct 10 nicklas 269     {
1255 22 Oct 10 nicklas 270       sc.close();
1255 22 Oct 10 nicklas 271     }
1255 22 Oct 10 nicklas 272     catch (Throwable t)
1255 22 Oct 10 nicklas 273     {
1255 22 Oct 10 nicklas 274       log.warn("Exception when closing SessionControl" , t);
1255 22 Oct 10 nicklas 275     }
1255 22 Oct 10 nicklas 276   }
1255 22 Oct 10 nicklas 277   
1255 22 Oct 10 nicklas 278   /**
1255 22 Oct 10 nicklas 279     Safely close the Bittorrent client. Catches all exceptions but log
1255 22 Oct 10 nicklas 280     them to the logger.
1255 22 Oct 10 nicklas 281   */
1255 22 Oct 10 nicklas 282   private void closeBtClient()
1255 22 Oct 10 nicklas 283   {
1255 22 Oct 10 nicklas 284     try
1255 22 Oct 10 nicklas 285     {
1255 22 Oct 10 nicklas 286       btClient.stopProtocol();
1255 22 Oct 10 nicklas 287     }
1255 22 Oct 10 nicklas 288     catch (Throwable t)
1255 22 Oct 10 nicklas 289     {
1255 22 Oct 10 nicklas 290       log.warn("Exception when closing Bittorrent client" , t);
1255 22 Oct 10 nicklas 291     }
1255 22 Oct 10 nicklas 292   }
1255 22 Oct 10 nicklas 293
1255 22 Oct 10 nicklas 294   
1255 22 Oct 10 nicklas 295   /**
1255 22 Oct 10 nicklas 296     Create a new torrent manager for the torrent with the given name.
1255 22 Oct 10 nicklas 297     This method will create a new temporary working directory for the
1255 22 Oct 10 nicklas 298     torrent manager to store the torrent, the downloaded files and
1255 22 Oct 10 nicklas 299     other data.
1251 22 Oct 10 nicklas 300     
1255 22 Oct 10 nicklas 301     @param torrentName Usually the filename of the torrent file
1255 22 Oct 10 nicklas 302     @return A new torrent manager
1255 22 Oct 10 nicklas 303     @throws IOException If the temporary working directory can't be
1255 22 Oct 10 nicklas 304       created
1255 22 Oct 10 nicklas 305     @throws IllegalStateException If the service has not been started
1255 22 Oct 10 nicklas 306   */
1255 22 Oct 10 nicklas 307   public synchronized TorrentManager newTorrentManager(String torrentName)
1255 22 Oct 10 nicklas 308     throws IOException
1255 22 Oct 10 nicklas 309   {
1255 22 Oct 10 nicklas 310     if (!isRunning()) throw new IllegalStateException("The service has not been started.");
1255 22 Oct 10 nicklas 311     
1304 03 Mar 11 nicklas 312     log.debug("Creating torrent manager for torrent: " + torrentName);
1255 22 Oct 10 nicklas 313     // Create a sub-dir for this torrent
1255 22 Oct 10 nicklas 314     String tmpDir = torrentName;
1255 22 Oct 10 nicklas 315     if (torrentName.endsWith(".torrent"))
1255 22 Oct 10 nicklas 316     {
1255 22 Oct 10 nicklas 317       tmpDir = torrentName.substring(0, torrentName.length()-8);
1255 22 Oct 10 nicklas 318     }
1255 22 Oct 10 nicklas 319     File subDir = FileUtil.createTempDirectory(tmpDir, ".torrent", workDir);
1255 22 Oct 10 nicklas 320     
1255 22 Oct 10 nicklas 321     // Create a Torrent manager
1255 22 Oct 10 nicklas 322     TorrentManager manager = new TorrentManager(this, subDir, torrentName);
1304 03 Mar 11 nicklas 323     registerTorrentManager(manager);
1304 03 Mar 11 nicklas 324     log.debug("Created torrent manager for torrent: " + torrentName);
1304 03 Mar 11 nicklas 325     return manager;
1304 03 Mar 11 nicklas 326   }
1304 03 Mar 11 nicklas 327
1304 03 Mar 11 nicklas 328   /**
1304 03 Mar 11 nicklas 329     Register a new torrent manager
1304 03 Mar 11 nicklas 330   */
1304 03 Mar 11 nicklas 331   private void registerTorrentManager(TorrentManager manager)
1304 03 Mar 11 nicklas 332   {
1255 22 Oct 10 nicklas 333     torrentManagers.add(manager);
1255 22 Oct 10 nicklas 334     // Create the service task if needed
1255 22 Oct 10 nicklas 335        if (serviceTask == null)
1255 22 Oct 10 nicklas 336        {
1255 22 Oct 10 nicklas 337            serviceTask = Application.getScheduler().schedule(new TorrentServiceStateCheckerTask(this), 10000, 10000, false);
1255 22 Oct 10 nicklas 338        }
1255 22 Oct 10 nicklas 339   }
1304 03 Mar 11 nicklas 340   
1255 22 Oct 10 nicklas 341   /**
1304 03 Mar 11 nicklas 342     Remove an existing torrent manager. 
1255 22 Oct 10 nicklas 343   */
1304 03 Mar 11 nicklas 344   synchronized void removeTorrentManager(TorrentManager manager)
1255 22 Oct 10 nicklas 345   {
1304 03 Mar 11 nicklas 346     log.debug("Stopping torrent manager: " + manager.getName() + "; jobId=" + manager.getJobId());
1299 25 Feb 11 nicklas 347     try
1299 25 Feb 11 nicklas 348     {
1299 25 Feb 11 nicklas 349       btClient.stopTorrent(manager.getTorrent());
1304 03 Mar 11 nicklas 350       log.debug("Stopped torrent manager: " + manager.getName() + "; jobId=" + manager.getJobId());
1299 25 Feb 11 nicklas 351     }
1299 25 Feb 11 nicklas 352     catch (Exception ex)
1299 25 Feb 11 nicklas 353     {
1299 25 Feb 11 nicklas 354       log.warn("Could not stop download of " + manager.getName(), ex);
1299 25 Feb 11 nicklas 355     }
1255 22 Oct 10 nicklas 356     torrentManagers.remove(manager);
1304 03 Mar 11 nicklas 357     
1304 03 Mar 11 nicklas 358     // Cancel the service task if there are no more torrents
1255 22 Oct 10 nicklas 359     if (torrentManagers.size() == 0)
1255 22 Oct 10 nicklas 360     {
1255 22 Oct 10 nicklas 361       serviceTask.cancel();
1255 22 Oct 10 nicklas 362       serviceTask = null;
1255 22 Oct 10 nicklas 363     }
1255 22 Oct 10 nicklas 364   }
1255 22 Oct 10 nicklas 365
1255 22 Oct 10 nicklas 366   /**
1255 22 Oct 10 nicklas 367     Get a cloned list of torrent managers since the original list
1255 22 Oct 10 nicklas 368     may be modified at any time by other threads.
1255 22 Oct 10 nicklas 369   */
1299 25 Feb 11 nicklas 370   synchronized List<TorrentManager> getManagers()
1255 22 Oct 10 nicklas 371   {
1255 22 Oct 10 nicklas 372     return new ArrayList<TorrentManager>(torrentManagers);
1255 22 Oct 10 nicklas 373   }
1255 22 Oct 10 nicklas 374   
1255 22 Oct 10 nicklas 375   /**
1255 22 Oct 10 nicklas 376     Create a new DbControl.
1255 22 Oct 10 nicklas 377   */
1255 22 Oct 10 nicklas 378   DbControl newDbControl()
1255 22 Oct 10 nicklas 379   {
1255 22 Oct 10 nicklas 380     return sc.newDbControl();
1255 22 Oct 10 nicklas 381   }
1255 22 Oct 10 nicklas 382   
1255 22 Oct 10 nicklas 383   /**
1255 22 Oct 10 nicklas 384     Start the actual download of a torrent. Called by the {@link TorrentServiceStateCheckerTask} 
1255 22 Oct 10 nicklas 385     when it has detected a {@link TorrentManager} with {@link TorrentState#READY_TO_DOWNLOAD}
1255 22 Oct 10 nicklas 386     state.
1255 22 Oct 10 nicklas 387   */
1255 22 Oct 10 nicklas 388   void startDownload(TorrentManager manager)
1255 22 Oct 10 nicklas 389   {
1304 03 Mar 11 nicklas 390     log.debug("Starting download: " + manager.getName() + "; jobId=" + manager.getJobId());
1299 25 Feb 11 nicklas 391     // Start the job + register signal receiver
1299 25 Feb 11 nicklas 392     DbControl dc = sc.newDbControl();
1251 22 Oct 10 nicklas 393     try
1251 22 Oct 10 nicklas 394     {
1299 25 Feb 11 nicklas 395       // Load the job and register it as started
1299 25 Feb 11 nicklas 396       Job job = manager.getJob(dc);
1304 03 Mar 11 nicklas 397       String handlerId = signalReciever.registerSignalHandler(manager);
1304 03 Mar 11 nicklas 398       job.setSignalTransporter(signalReciever.getSignalTransporterClass(), handlerId);
1304 03 Mar 11 nicklas 399       if (job.getStatus() != Job.Status.EXECUTING)
1304 03 Mar 11 nicklas 400       {
1304 03 Mar 11 nicklas 401         job.start("Starting download...", "torrent-service@" + Application.getHostName(), null);
1304 03 Mar 11 nicklas 402       }
1299 25 Feb 11 nicklas 403       dc.commit();
1299 25 Feb 11 nicklas 404     }
1299 25 Feb 11 nicklas 405     finally
1299 25 Feb 11 nicklas 406     {
1299 25 Feb 11 nicklas 407       if (dc != null) dc.close();
1299 25 Feb 11 nicklas 408     }
1299 25 Feb 11 nicklas 409     
1299 25 Feb 11 nicklas 410     try
1299 25 Feb 11 nicklas 411     {
1255 22 Oct 10 nicklas 412       // Register torrent with btClient
1255 22 Oct 10 nicklas 413       File downloadDir = manager.getDownloadDir();
1255 22 Oct 10 nicklas 414       downloadDir.mkdir();
1255 22 Oct 10 nicklas 415       InputStream in = FileUtil.getInputStream(manager.getTorrentFile());
1255 22 Oct 10 nicklas 416       Torrent torrent = btClient.download(in, downloadDir.getAbsolutePath());
1255 22 Oct 10 nicklas 417       
1255 22 Oct 10 nicklas 418       // Set torrent manager state to DOWNLOADING
1255 22 Oct 10 nicklas 419       manager.setTorrent(torrent);
1304 03 Mar 11 nicklas 420       log.debug("Started download: " + manager.getName() + "; jobId=" + manager.getJobId());
1251 22 Oct 10 nicklas 421     }
1255 22 Oct 10 nicklas 422     catch (Exception ex)
1251 22 Oct 10 nicklas 423     {
1255 22 Oct 10 nicklas 424       // Close the torrent manager
1255 22 Oct 10 nicklas 425       manager.close(ex);
1255 22 Oct 10 nicklas 426       log.warn("Could not start download of " + manager.getName(), ex);
1251 22 Oct 10 nicklas 427     }
1246 21 Oct 10 nicklas 428   }
1246 21 Oct 10 nicklas 429 }