package com.limegroup.gnutella;
import java.io.IOException;
import java.net.Socket;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpException;
import org.apache.http.params.HttpParams;
import org.limewire.concurrent.ThreadExecutor;
import org.limewire.friend.api.FriendPresence;
import org.limewire.inject.EagerSingleton;
import org.limewire.io.GUID;
import org.limewire.lifecycle.Service;
import org.limewire.net.SocketsManager;
import org.limewire.service.ErrorService;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.name.Named;
import com.limegroup.gnutella.downloader.PushedSocketHandlerRegistry;
import com.limegroup.gnutella.messages.MessageFactory;
@EagerSingleton
class BrowseHostHandlerManagerImpl implements BrowseHostHandlerManager, Service {
private static final Log LOG = LogFactory.getLog(BrowseHostHandlerManagerImpl.class);
/** Map from serventID to BrowseHostHandler instance. */
private final Map<GUID, BrowseHostHandler.PushRequestDetails> _pushedHosts = new HashMap<GUID, BrowseHostHandler.PushRequestDetails>();
private final SocketsManager socketsManager;
private final Provider<ForMeReplyHandler> forMeReplyHandler;
private final ScheduledExecutorService backgroundExecutor;
private final MessageFactory messageFactory;
private final NetworkManager networkManager;
private final PushEndpointFactory pushEndpointFactory;
private final Provider<HttpParams> httpParams;
@Inject
public BrowseHostHandlerManagerImpl(@Named("backgroundExecutor")
ScheduledExecutorService backgroundExecutor,
SocketsManager socketsManager,
Provider<ForMeReplyHandler> forMeReplyHandler,
MessageFactory messageFactory,
NetworkManager networkManager,
PushEndpointFactory pushEndpointFactory,
@Named("defaults")Provider<HttpParams> httpParams) {
this.socketsManager = socketsManager;
this.forMeReplyHandler = forMeReplyHandler;
this.messageFactory = messageFactory;
this.backgroundExecutor = backgroundExecutor;
this.networkManager = networkManager;
this.pushEndpointFactory = pushEndpointFactory;
this.httpParams = httpParams;
}
@Inject
void register(org.limewire.lifecycle.ServiceRegistry registry) {
registry.register(this);
}
public String getServiceName() {
return org.limewire.i18n.I18nMarker.marktr("Browse Host Handler");
}
public void initialize() {
}
public void stop() {
}
public void start() {
backgroundExecutor.scheduleWithFixedDelay(new Expirer(), 0, 5000, TimeUnit.MILLISECONDS);
}
@Inject
public void register(PushedSocketHandlerRegistry registry) {
registry.register(this);
}
/*
* (non-Javadoc)
*
* @see com.limegroup.gnutella.BrowseHostHandlerManager#createBrowseHostHandler(com.limegroup.gnutella.ActivityCallback,
* com.limegroup.gnutella.GUID, com.limegroup.gnutella.GUID)
*/
public BrowseHostHandler createBrowseHostHandler(GUID guid, GUID serventID) {
return new BrowseHostHandler(guid, socketsManager,
forMeReplyHandler, messageFactory, httpParams,
networkManager, pushEndpointFactory);
}
/** @return true if the Push was handled by me. */
public boolean acceptPushedSocket(String file, int index, byte[] clientGUID, final Socket socket) {
GUID serventID = new GUID(clientGUID);
boolean retVal = false;
LOG.trace("BHH.handlePush(): entered.");
// if (index == SPECIAL_INDEX)
// ; // you'd hope, but not necessary...
BrowseHostHandler.PushRequestDetails prd = null;
synchronized (_pushedHosts) {
prd = _pushedHosts.remove(serventID);
}
if (prd != null) {
final BrowseHostHandler browseHostHandler = prd.getBrowseHostHandler();
final FriendPresence friendPresence = prd.getFriendPresence();
ThreadExecutor.startThread(new Runnable() {
public void run() {
try {
browseHostHandler.browseHost(socket, friendPresence);
} catch (IOException e) {
LOG.debug("error while push transfer", e);
browseHostHandler.failed();
} catch (HttpException e) {
LOG.debug("error while push transfer", e);
browseHostHandler.failed();
} catch (URISyntaxException e) {
LOG.debug("error while push transfer", e);
browseHostHandler.failed();
} catch (InterruptedException e) {
LOG.debug("error while push transfer", e);
browseHostHandler.failed();
}
}
}, "BrowseHost");
retVal = true;
} else
LOG.debug("BHH.handlePush(): no matching BHH.");
LOG.trace("BHH.handlePush(): returning.");
return retVal;
}
/** Can be run to invalidate pushes that we are waiting for.... */
private class Expirer implements Runnable {
public void run() {
try {
Set<GUID> toRemove = new HashSet<GUID>();
synchronized (_pushedHosts) {
for (GUID key : _pushedHosts.keySet()) {
BrowseHostHandler.PushRequestDetails currPRD = _pushedHosts
.get(key);
if ((currPRD != null) && (currPRD.isExpired())) {
LOG.debug("Expirer.run(): expiring a badboy.");
toRemove.add(key);
currPRD.getBrowseHostHandler().failed();
}
}
for (GUID key : toRemove)
_pushedHosts.remove(key);
}
} catch (Throwable t) {
ErrorService.error(t);
}
}
}
@Override
public BrowseHostHandler createBrowseHostHandler(GUID browseGuid) {
return new BrowseHostHandler(browseGuid, socketsManager,
forMeReplyHandler, messageFactory, httpParams,
networkManager, pushEndpointFactory);
}
}