1
0
mirror of https://github.com/Rogiel/torrent4j synced 2025-12-05 23:22:49 +00:00

Manager javadoc

Change-Id: I431ac866b1b55dbf570c231d90129d89e522d0b9
This commit is contained in:
rogiel
2011-05-01 20:34:58 -03:00
parent 209cfb9deb
commit e9c8b7247d
6 changed files with 427 additions and 19 deletions

View File

@@ -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.
* <p>
* The general guide line for this handler is to abstract <b>ALL</b> 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 <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/

View File

@@ -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.
* <p>
* Please note that the manager actually does not make any decision nor create
* or block an connection.
* <p>
* You can {@link Iterable iterate} over this manager to get <b>active</b>
* {@link Channel} instances.
*
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/

View File

@@ -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.
* <p>
* Please note that the manager actually does not make any decision nor block an
* requested piece.
* <p>
* You can {@link Iterable iterate} over this manager to get <b>current</b>
* downloading {@link TorrentPart parts}.
*
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
// 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<TorrentPart> {
/**
* The torrent context
*/
private final TorrentContext context;
/**
* The requested pieces not yet attended.
*/
private final Map<TorrentPart, TorrentPeer> activeParts = new HashMap<TorrentPart, TorrentPeer>();
/**
* 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 <tt>part</tt> 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 <tt>piece</tt> 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<TorrentPart> {
return false;
}
/**
* Check if the given <tt>peer</tt> 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 <tt>part</tt>
*
* @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 <tt>peer</tt>
*
* @param peer
* the peer
* @return a set of pieces
*/
public Set<TorrentPart> getTorrentParts(TorrentPeer peer) {
final Set<TorrentPart> parts = new HashSet<TorrentPart>();
for (final Entry<TorrentPart, TorrentPeer> entry : activeParts
@@ -67,18 +129,50 @@ public class DownloadManager implements Iterable<TorrentPart> {
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 <tt>peer</tt>.
* <p>
* 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<TorrentPart> remove(TorrentPeer peer) {
final Set<TorrentPart> parts = new HashSet<TorrentPart>();
for (TorrentPart part : getTorrentParts(peer)) {
@@ -88,10 +182,20 @@ public class DownloadManager implements Iterable<TorrentPart> {
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<TorrentPart, TorrentPeer> getActiveDownloads() {
return Collections.unmodifiableMap(activeParts);
}
@@ -101,6 +205,11 @@ public class DownloadManager implements Iterable<TorrentPart> {
return activeParts.keySet().iterator();
}
/**
* Get the torrent context
*
* @return the torrent context
*/
public TorrentContext getContext() {
return context;
}

View File

@@ -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.
* <p>
* Please note that the manager actually does not make any decision nor block an
* requested piece.
* <p>
* You can {@link Iterable iterate} over this manager to get <b>active</b>
* {@link PeerWirePeer peers}.
*/
public class PeerManager implements Iterable<PeerWirePeer> {
/**
* 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<Channel, PeerWirePeer> activePeers = new HashMap<Channel, PeerWirePeer>();
/**
* The map of inactive channel-peer mapping
*/
private final Map<Channel, PeerWirePeer> inactivePeers = new HashMap<Channel, PeerWirePeer>();
/**
* 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 <tt>channel</tt> 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<PeerWirePeer> {
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 <tt>peer</tt> 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<PeerWirePeer> {
return false;
}
/**
* Get the {@link PeerWirePeer} registered in the given <tt>channel</tt>.
*
* @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<PeerWirePeer> {
return peer;
}
/**
* Lookup for the {@link Channel} in which the <tt>peer</tt> is attached to.
*
* @param peer
* the peer
* @return the {@link Channel} for the given <tt>peer</tt>
*/
public Channel getChannel(PeerWirePeer peer) {
for (final Entry<Channel, PeerWirePeer> entry : activePeers.entrySet()) {
if (entry.getValue().equals(peer))
@@ -78,10 +138,24 @@ public class PeerManager implements Iterable<PeerWirePeer> {
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<PeerWirePeer> {
}
}
/**
* 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<PeerWirePeer> {
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<PeerWirePeer> {
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<PeerWirePeer> {
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<Channel, PeerWirePeer> getActivePeers() {
return Collections.unmodifiableMap(activePeers);
}
/**
* Get an {@link Map} of all inactive peers
*
* @return the {@link Map} of all inactive peers
*/
public Map<Channel, PeerWirePeer> 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<Channel> 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<Channel> getInactiveChannels() {
return Collections.unmodifiableSet(inactivePeers.keySet());
}
/**
* Executes the <tt>callback</tt> for each active peer in this manager.
*
* @param callback
* the callback
*/
public void executeActive(PeerCallback callback) {
for (final Entry<Channel, PeerWirePeer> entry : this.activePeers
.entrySet()) {
@@ -147,6 +278,12 @@ public class PeerManager implements Iterable<PeerWirePeer> {
}
}
/**
* Executes the <tt>callback</tt> for each inactive peer in this manager.
*
* @param callback
* the callback
*/
public void executeInactive(PeerCallback callback) {
for (final Entry<Channel, PeerWirePeer> entry : this.inactivePeers
.entrySet()) {
@@ -154,6 +291,14 @@ public class PeerManager implements Iterable<PeerWirePeer> {
}
}
/**
* Executes the <tt>callback</tt> 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<PeerWirePeer> {
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;
}

View File

@@ -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 <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
public class TorrentManager {
private final TorrentContext context;

View File

@@ -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.
* <p>
* Please note that the manager actually does not make any decision nor declines
* an requested piece.
* <p>
* You can {@link Iterable iterate} over this manager to get <b>current</b>
* uploading {@link TorrentPart parts}.
* <p>
* FIXME <b>BUG NOTICE</b>: 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 <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
// 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<TorrentPart> {
/**
* The torrent context
*/
private final TorrentContext context;
/**
* An map of requested pieces. Only accepted pieces are registered.
*/
private final Map<TorrentPart, TorrentPeer> activeParts = new HashMap<TorrentPart, TorrentPeer>();
/**
* 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 <tt>part</tt> is being uploaded.
*
* @param part
* the part
* @return true if piece has been requested <b>AND</b> accepted.
*/
public boolean isUploading(TorrentPart part) {
return activeParts.containsKey(part);
}
/**
* Test if uploads are being made to the given <tt>peer</tt>
*
* @param peer
* the peer
* @return true if at least one piece has been requested an piece <b>AND</b>
* 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
* <tt>piece</tt>.
* <p>
* 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 <tt>peer</tt>
*
* @param peer
* the peer
* @return an {@link Set} of all parts being uploaded to this peer.
*/
public Set<TorrentPart> getTorrentParts(TorrentPeer peer) {
final Set<TorrentPart> parts = new HashSet<TorrentPart>();
for (final Entry<TorrentPart, TorrentPeer> entry : activeParts
@@ -58,18 +130,51 @@ public class UploadManager implements Iterable<TorrentPart> {
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 <tt>part</tt> from this manager
* <p>
* 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 <tt>part</tt>
*/
public TorrentPeer remove(TorrentPart part) {
return activeParts.remove(part);
}
/**
* Removes all uploads for the given <tt>peer</tt>
*
* @param peer
* the peer
* @return the set of {@link TorrentPart parts} being uploaded to that peer
*/
public Set<TorrentPart> remove(TorrentPeer peer) {
final Set<TorrentPart> parts = new HashSet<TorrentPart>();
for (TorrentPart part : getTorrentParts(peer)) {
@@ -79,10 +184,25 @@ public class UploadManager implements Iterable<TorrentPart> {
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
* <p>
* 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<TorrentPart, TorrentPeer> getActiveUploads() {
return Collections.unmodifiableMap(activeParts);
}
@@ -92,6 +212,11 @@ public class UploadManager implements Iterable<TorrentPart> {
return activeParts.keySet().iterator();
}
/**
* Get the torrent context
*
* @return the torrent context
*/
public TorrentContext getContext() {
return context;
}