diff --git a/src/main/java/net/torrent/protocol/peerwire/handler/PeerWireAlgorithmHandler.java b/src/main/java/net/torrent/protocol/peerwire/handler/PeerWireAlgorithmHandler.java index 27e2e10..2713d82 100644 --- a/src/main/java/net/torrent/protocol/peerwire/handler/PeerWireAlgorithmHandler.java +++ b/src/main/java/net/torrent/protocol/peerwire/handler/PeerWireAlgorithmHandler.java @@ -58,6 +58,11 @@ import org.jboss.netty.handler.timeout.IdleStateEvent; /** * Standard handler responsible for forwarding calls to {@link TorrentAlgorithm} * methods. This class handles low-level protocol specific behavior. + *

+ * The general guide line for this handler is to abstract ALL protocol + * specific models and use an abstracted algorithm for download. This will + * obviously limit the complexity of algorithm implementations. If that is the + * case, you are free to implement a new handler. * * @author Rogiel Josias Sulzbach */ diff --git a/src/main/java/net/torrent/protocol/peerwire/manager/ConnectionManager.java b/src/main/java/net/torrent/protocol/peerwire/manager/ConnectionManager.java index 42ee6f7..a2c444c 100644 --- a/src/main/java/net/torrent/protocol/peerwire/manager/ConnectionManager.java +++ b/src/main/java/net/torrent/protocol/peerwire/manager/ConnectionManager.java @@ -25,7 +25,14 @@ import net.torrent.torrent.context.TorrentContext; import org.jboss.netty.channel.Channel; /** - * Connection manager: manages active and inactive connections. + * Connection manager: keep control over active and inactive {@link Channel + * channel} connections. + *

+ * Please note that the manager actually does not make any decision nor create + * or block an connection. + *

+ * You can {@link Iterable iterate} over this manager to get active + * {@link Channel} instances. * * @author Rogiel Josias Sulzbach */ diff --git a/src/main/java/net/torrent/protocol/peerwire/manager/DownloadManager.java b/src/main/java/net/torrent/protocol/peerwire/manager/DownloadManager.java index 9eecd4f..7ef9277 100644 --- a/src/main/java/net/torrent/protocol/peerwire/manager/DownloadManager.java +++ b/src/main/java/net/torrent/protocol/peerwire/manager/DownloadManager.java @@ -28,19 +28,60 @@ import net.torrent.torrent.TorrentPiece; import net.torrent.torrent.context.TorrentContext; import net.torrent.torrent.context.TorrentPeer; +/** + * The download manager keep an track over current parts being downloaded at the + * moment. + *

+ * Please note that the manager actually does not make any decision nor block an + * requested piece. + *

+ * You can {@link Iterable iterate} over this manager to get current + * downloading {@link TorrentPart parts}. + * + * @author Rogiel Josias Sulzbach + */ +// TODO track pieces which have been requested for some time but never got an +// REJECT (fast peer extensions) nor PIECE message (standard torrent +// implementation does nothing when the peer is not uploading the piece) +// TODO allow more then one peer per piece request public class DownloadManager implements Iterable { + /** + * The torrent context + */ private final TorrentContext context; - + /** + * The requested pieces not yet attended. + */ private final Map activeParts = new HashMap(); + /** + * Creates a new instance + * + * @param context + * the torrent context + */ public DownloadManager(TorrentContext context) { this.context = context; } - public boolean isDownloading(TorrentPart torrentPart) { - return activeParts.containsKey(torrentPart); + /** + * Check if the given part has been requested. + * + * @param part + * the torrent part + * @return true if request message have been sent + */ + public boolean isDownloading(TorrentPart part) { + return activeParts.containsKey(part); } + /** + * Test if the given piece has been requested. + * + * @param piece + * the piece + * @return true if request message have been sent + */ public boolean isDownloading(TorrentPiece piece) { for (final TorrentPart part : activeParts.keySet()) { if (part.getPiece().equals(piece)) @@ -49,14 +90,35 @@ public class DownloadManager implements Iterable { return false; } + /** + * Check if the given peer is uploading something. + * + * @param peer + * the peer + * @return true if downloading from this peer + */ public boolean isDownloading(TorrentPeer peer) { return activeParts.containsValue(peer); } - public TorrentPeer getPeer(TorrentPart torrentPart) { - return activeParts.get(torrentPart); + /** + * Get the peer uploading part + * + * @param part + * the part + * @return the peer uploading the part + */ + public TorrentPeer getPeer(TorrentPart part) { + return activeParts.get(part); } + /** + * Get all parts being downloaded from the given peer + * + * @param peer + * the peer + * @return a set of pieces + */ public Set getTorrentParts(TorrentPeer peer) { final Set parts = new HashSet(); for (final Entry entry : activeParts @@ -67,18 +129,50 @@ public class DownloadManager implements Iterable { return parts; } + /** + * Test if there are no active pieces requests. + * + * @return true if no pending parts + */ public boolean isInactive() { return activeParts.isEmpty(); } - public TorrentPeer add(TorrentPart torrentPart, TorrentPeer peer) { - return activeParts.put(torrentPart, peer); + /** + * Add a new part request + * + * @param part + * the part + * @param peer + * the remote peer + * @return the peer (java collections thing) + */ + public TorrentPeer add(TorrentPart part, TorrentPeer peer) { + return activeParts.put(part, peer); } - public TorrentPeer remove(TorrentPart torrentPart) { - return activeParts.remove(torrentPart); + /** + * Removes an part from this manager. + * + * @param part + * the part + * @return true if part was present before remove + */ + public TorrentPeer remove(TorrentPart part) { + return activeParts.remove(part); } + /** + * Remove all pieces request from the given peer. + *

+ * Note that since this implementation is decoupled from any protocol + * implementation, it will not cancel the request! This piece might arrive + * some time later. + * + * @param peer + * the peer + * @return a set containing pieces removed + */ public Set remove(TorrentPeer peer) { final Set parts = new HashSet(); for (TorrentPart part : getTorrentParts(peer)) { @@ -88,10 +182,20 @@ public class DownloadManager implements Iterable { return parts; } + /** + * Get the current active requests + * + * @return the current active requests + */ public int getActiveDownloadsCount() { return activeParts.size(); } + /** + * Get an map containing each piece mapped to the peer uploading it. + * + * @return the map containing each piece mapped to the peer uploading it. + */ public Map getActiveDownloads() { return Collections.unmodifiableMap(activeParts); } @@ -101,6 +205,11 @@ public class DownloadManager implements Iterable { return activeParts.keySet().iterator(); } + /** + * Get the torrent context + * + * @return the torrent context + */ public TorrentContext getContext() { return context; } diff --git a/src/main/java/net/torrent/protocol/peerwire/manager/PeerManager.java b/src/main/java/net/torrent/protocol/peerwire/manager/PeerManager.java index bd621c5..5420dd3 100644 --- a/src/main/java/net/torrent/protocol/peerwire/manager/PeerManager.java +++ b/src/main/java/net/torrent/protocol/peerwire/manager/PeerManager.java @@ -29,19 +29,56 @@ import net.torrent.util.PeerCallback; import org.jboss.netty.channel.Channel; +/** + * The peer manager is used to keep control over active peers and they + * {@link Channel Netty Channel} used to write or read messages. + *

+ * Please note that the manager actually does not make any decision nor block an + * requested piece. + *

+ * You can {@link Iterable iterate} over this manager to get active + * {@link PeerWirePeer peers}. + */ public class PeerManager implements Iterable { + /** + * The torrent context + */ private final TorrentContext context; + /** + * The {@link ConnectionManager} instance + */ private final ConnectionManager connectionManager; + /** + * The map of active channel-peer mapping + */ private final Map activePeers = new HashMap(); + /** + * The map of inactive channel-peer mapping + */ private final Map inactivePeers = new HashMap(); + /** + * Creates a new instance + * + * @param context + * the torrent context + * @param connectionManager + * the connection manager instance + */ public PeerManager(TorrentContext context, ConnectionManager connectionManager) { this.context = context; this.connectionManager = connectionManager; } + /** + * Tests if the given channel has an peer attached to it. + * + * @param channel + * the channel + * @return true if an peer is attached + */ public boolean contains(Channel channel) { if (activePeers.containsKey(channel)) return true; @@ -50,6 +87,15 @@ public class PeerManager implements Iterable { return false; } + /** + * Tests if the current {@link PeerWirePeer} is registered in this manager. + * You will normally not have access to {@link PeerWirePeer} object, thus + * whis method might not be very useful outside handlers. + * + * @param peer + * the {@link PeerWirePeer} peer + * @return true if this peer is registered in this manager + */ public boolean contains(PeerWirePeer peer) { if (activePeers.containsValue(peer)) return true; @@ -58,6 +104,13 @@ public class PeerManager implements Iterable { return false; } + /** + * Get the {@link PeerWirePeer} registered in the given channel. + * + * @param channel + * the channel + * @return the peer instance. + */ public PeerWirePeer getPeer(Channel channel) { PeerWirePeer peer = activePeers.get(channel); if (peer == null) @@ -65,6 +118,13 @@ public class PeerManager implements Iterable { return peer; } + /** + * Lookup for the {@link Channel} in which the peer is attached to. + * + * @param peer + * the peer + * @return the {@link Channel} for the given peer + */ public Channel getChannel(PeerWirePeer peer) { for (final Entry entry : activePeers.entrySet()) { if (entry.getValue().equals(peer)) @@ -78,10 +138,24 @@ public class PeerManager implements Iterable { return null; } + /** + * Test if there are no active peers in this manager. + * + * @return true if no active peers + */ public boolean isEmpty() { return activePeers.isEmpty(); } + /** + * Adds a new peer to this manager. + * + * @param channel + * the channel + * @param peer + * the peer + * @return the {@link PeerWirePeer} created instance. + */ public PeerWirePeer add(Channel channel, TorrentPeer peer) { if (channel.isConnected()) { return activePeers.put(channel, new PeerWirePeer(channel, peer)); @@ -90,6 +164,13 @@ public class PeerManager implements Iterable { } } + /** + * Removes an {@link Channel} and its {@link TorrentPeer} from this manager. + * + * @param channel + * the channel + * @return the, now removed, {@link PeerWirePeer} instance + */ public PeerWirePeer remove(Channel channel) { PeerWirePeer peer; if ((peer = activePeers.remove(channel)) != null) @@ -99,6 +180,13 @@ public class PeerManager implements Iterable { return null; } + /** + * Removes an {@link PeerWirePeer} from this manager. + * + * @param peer + * the peer + * @return the, now removed, {@link PeerWirePeer} instance + */ public PeerWirePeer remove(PeerWirePeer peer) { final Channel channel = getChannel(peer); PeerWirePeer peerRemoved; @@ -109,6 +197,13 @@ public class PeerManager implements Iterable { return null; } + /** + * Updates this {@link Channel} peer state (i.e. active or inactive) + * + * @param channel + * the channel + * @return the {@link PeerWirePeer} instance updated + */ public PeerWirePeer update(Channel channel) { PeerWirePeer peer; if ((peer = remove(channel)) == null) @@ -116,30 +211,66 @@ public class PeerManager implements Iterable { return add(channel, peer.getTorrentPeer()); } + /** + * Get the total active peers + * + * @return the active peers count + */ public int getActivePeersCount() { return activePeers.size(); } + /** + * Get the total inactive peers + * + * @return the inactive peers count + */ public int getImactivePeersCount() { return activePeers.size(); } + /** + * Get an {@link Map} of all active peers + * + * @return the {@link Map} of all active peers + */ public Map getActivePeers() { return Collections.unmodifiableMap(activePeers); } + /** + * Get an {@link Map} of all inactive peers + * + * @return the {@link Map} of all inactive peers + */ public Map getInactivePeers() { return Collections.unmodifiableMap(inactivePeers); } + /** + * Get an {@link Set} of all active {@link Channel channels} + * + * @return the {@link Set} of all active {@link Channel channels} + */ public Set getActiveChannels() { return Collections.unmodifiableSet(activePeers.keySet()); } + /** + * Get an {@link Set} of all inactive {@link Channel channels} + * + * @return the {@link Set} of all inactive {@link Channel channels} + */ public Set getInactiveChannels() { return Collections.unmodifiableSet(inactivePeers.keySet()); } + /** + * Executes the callback for each active peer in this manager. + * + * @param callback + * the callback + */ public void executeActive(PeerCallback callback) { for (final Entry entry : this.activePeers .entrySet()) { @@ -147,6 +278,12 @@ public class PeerManager implements Iterable { } } + /** + * Executes the callback for each inactive peer in this manager. + * + * @param callback + * the callback + */ public void executeInactive(PeerCallback callback) { for (final Entry entry : this.inactivePeers .entrySet()) { @@ -154,6 +291,14 @@ public class PeerManager implements Iterable { } } + /** + * Executes the callback for each active and inactive peer in this + * manager. This method call firstly {@link #executeActive(PeerCallback)} + * and later {@link #executeInactive(PeerCallback)}. + * + * @param callback + * the callback + */ public void execute(PeerCallback callback) { executeActive(callback); executeInactive(callback); @@ -164,10 +309,20 @@ public class PeerManager implements Iterable { return activePeers.values().iterator(); } + /** + * Get the torrent context + * + * @return the torrent context + */ public TorrentContext getContext() { return context; } + /** + * Get the connection manager + * + * @return the connection manager + */ public ConnectionManager getConnectionManager() { return connectionManager; } diff --git a/src/main/java/net/torrent/protocol/peerwire/manager/TorrentManager.java b/src/main/java/net/torrent/protocol/peerwire/manager/TorrentManager.java index 7adb839..afc13cc 100644 --- a/src/main/java/net/torrent/protocol/peerwire/manager/TorrentManager.java +++ b/src/main/java/net/torrent/protocol/peerwire/manager/TorrentManager.java @@ -19,6 +19,13 @@ import net.torrent.protocol.datastore.TorrentDatastore; import net.torrent.torrent.Torrent; import net.torrent.torrent.context.TorrentContext; +/** + * This is an simple class used to group up all managers for a single torrent. + * It does not do nothing special is just used to avoid incompatibility with + * handlers once a new manager is created. + * + * @author Rogiel Josias Sulzbach + */ public class TorrentManager { private final TorrentContext context; diff --git a/src/main/java/net/torrent/protocol/peerwire/manager/UploadManager.java b/src/main/java/net/torrent/protocol/peerwire/manager/UploadManager.java index a0863ad..bfc239b 100644 --- a/src/main/java/net/torrent/protocol/peerwire/manager/UploadManager.java +++ b/src/main/java/net/torrent/protocol/peerwire/manager/UploadManager.java @@ -27,27 +27,99 @@ import net.torrent.torrent.TorrentPart; import net.torrent.torrent.context.TorrentContext; import net.torrent.torrent.context.TorrentPeer; +/** + * The upload manager keep an track over current parts being uploaded at the + * moment. Notice that the part is remove right after the last byte is written, + * this is not a guarantee that the peer has received data nor that it is still + * alive. + *

+ * Please note that the manager actually does not make any decision nor declines + * an requested piece. + *

+ * You can {@link Iterable iterate} over this manager to get current + * uploading {@link TorrentPart parts}. + *

+ * FIXME BUG NOTICE: Note that this manager has an huge issue. When two + * or more peers request the very same part, only the latter will be maintained + * under control by this manager. This should be fixed soon and changes to the + * manager signature can occur. The affected methods are: + * {@link UploadManager#getPeer(TorrentPart)}, + * {@link UploadManager#remove(TorrentPart)} and + * {@link UploadManager#getActiveUploads()}. + * + * @author Rogiel Josias Sulzbach + */ +// TODO track pieces which have been requested but the upload is not interesting +// right now, but might be later. +// FIXME this manager has an issue: if two peers request the same piece, only +// the latter one will be managed! UploadManager#getPeer(TorrentPart part) needs +// a fix. public class UploadManager implements Iterable { + /** + * The torrent context + */ private final TorrentContext context; - + /** + * An map of requested pieces. Only accepted pieces are registered. + */ private final Map activeParts = new HashMap(); + /** + * Creates a new instance + * + * @param context + * the torrent context + */ public UploadManager(TorrentContext context) { this.context = context; } - public boolean isUploading(TorrentPart torrentPart) { - return activeParts.containsKey(torrentPart); + /** + * Test if the given part is being uploaded. + * + * @param part + * the part + * @return true if piece has been requested AND accepted. + */ + public boolean isUploading(TorrentPart part) { + return activeParts.containsKey(part); } + /** + * Test if uploads are being made to the given peer + * + * @param peer + * the peer + * @return true if at least one piece has been requested an piece AND + * the request was accepted + */ public boolean isUploading(TorrentPeer peer) { return activeParts.containsValue(peer); } - public TorrentPeer getPeer(TorrentPart torrentPart) { - return activeParts.get(torrentPart); + /** + * This method retrieve the peer which has requested the given + * piece. + *

+ * Note that this method has an huge issue: when two or more peers request + * the very same part (whichever piece), only the latter will be maintained + * under control by this manager. This need to be fixed soon and this method + * deprecated. You should avoid relying on it! + * + * @param part + * @return + */ + public TorrentPeer getPeer(TorrentPart part) { + return activeParts.get(part); } + /** + * Get the pieces being uploaded to the given peer + * + * @param peer + * the peer + * @return an {@link Set} of all parts being uploaded to this peer. + */ public Set getTorrentParts(TorrentPeer peer) { final Set parts = new HashSet(); for (final Entry entry : activeParts @@ -58,18 +130,51 @@ public class UploadManager implements Iterable { return parts; } + /** + * Tests if this manager has no active uploads. + * + * @return true if no uploads are being done + */ public boolean isInactive() { return activeParts.isEmpty(); } - public TorrentPeer add(TorrentPart torrentPart, TorrentPeer peer) { - return activeParts.put(torrentPart, peer); + /** + * Adds a new part to this manager + * + * @param part + * the uploaded part + * @param peer + * the downloading peer + * @return the downloding {@link TorrentPeer} + */ + public TorrentPeer add(TorrentPart part, TorrentPeer peer) { + return activeParts.put(part, peer); } - public TorrentPeer remove(TorrentPart torrentPart) { - return activeParts.remove(torrentPart); + /** + * Removes the given part from this manager + *

+ * Note that this method has an huge issue: when two or more peers request + * the very same part (whichever piece), only the latter will be maintained + * under control by this manager. This need to be fixed soon and this method + * deprecated. You should avoid relying on it! + * + * @param part + * the part + * @return the downloading peer for the part + */ + public TorrentPeer remove(TorrentPart part) { + return activeParts.remove(part); } + /** + * Removes all uploads for the given peer + * + * @param peer + * the peer + * @return the set of {@link TorrentPart parts} being uploaded to that peer + */ public Set remove(TorrentPeer peer) { final Set parts = new HashSet(); for (TorrentPart part : getTorrentParts(peer)) { @@ -79,10 +184,25 @@ public class UploadManager implements Iterable { return parts; } + /** + * Get the amount of active uploads + * + * @return the count of active uploads + */ public int getActiveUploadsCount() { return activeParts.size(); } + /** + * Get an {@link Map} of active uploads + *

+ * Note that this method has an huge issue: when two or more peers request + * the very same part (whichever piece), only the latter will be maintained + * under control by this manager. This need to be fixed soon and this method + * deprecated. You should avoid relying on it! + * + * @return an {@link Map} of active uploads + */ public Map getActiveUploads() { return Collections.unmodifiableMap(activeParts); } @@ -92,6 +212,11 @@ public class UploadManager implements Iterable { return activeParts.keySet().iterator(); } + /** + * Get the torrent context + * + * @return the torrent context + */ public TorrentContext getContext() { return context; }