package org.limewire.core.impl; import java.io.File; import java.util.List; import java.util.Set; import java.util.SortedMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.CopyOnWriteArrayList; import org.limewire.bittorrent.Torrent; import org.limewire.core.api.callback.GuiCallback; import org.limewire.core.api.callback.GuiCallbackService; import org.limewire.core.api.download.DownloadAction; import org.limewire.core.api.download.DownloadException; import org.limewire.core.impl.download.DownloadListener; import org.limewire.core.impl.download.DownloadListenerList; import org.limewire.core.impl.magnet.MagnetLinkImpl; import org.limewire.core.impl.monitor.IncomingSearchListener; import org.limewire.core.impl.monitor.IncomingSearchListenerList; import org.limewire.core.impl.search.QueryReplyListener; import org.limewire.core.impl.search.QueryReplyListenerList; import org.limewire.core.impl.upload.UploadListener; import org.limewire.core.impl.upload.UploadListenerList; import org.limewire.i18n.I18nMarker; import org.limewire.io.GUID; import org.limewire.io.IpPort; import org.limewire.service.ErrorService; import org.limewire.service.MessageService; import com.google.inject.Inject; import com.google.inject.Singleton; import com.limegroup.gnutella.ActivityCallback; import com.limegroup.gnutella.DownloadManager; import com.limegroup.gnutella.Downloader; import com.limegroup.gnutella.RemoteFileDesc; import com.limegroup.gnutella.Uploader; import com.limegroup.gnutella.browser.MagnetOptions; import com.limegroup.gnutella.messages.QueryReply; import com.limegroup.gnutella.messages.QueryRequest; /** * An implementation of the UI callback to handle notifications about * asynchronous backend events. */ @Singleton class GlueActivityCallback implements ActivityCallback, QueryReplyListenerList, DownloadListenerList, UploadListenerList, IncomingSearchListenerList, GuiCallbackService { private final SortedMap<byte[], List<QueryReplyListener>> queryReplyListeners; private final List<DownloadListener> downloadListeners = new CopyOnWriteArrayList<DownloadListener>(); private final List<UploadListener> uploadListeners = new CopyOnWriteArrayList<UploadListener>(); private final List<IncomingSearchListener> monitorListeners = new CopyOnWriteArrayList<IncomingSearchListener>(); private final DownloadManager downloadManager; private GuiCallback guiCallback = null; @Inject public GlueActivityCallback(DownloadManager downloadManager) { this.downloadManager = downloadManager; queryReplyListeners = new ConcurrentSkipListMap<byte[], List<QueryReplyListener>>( GUID.GUID_BYTE_COMPARATOR); } @Override public void addQueryReplyListener(byte[] guid, QueryReplyListener listener) { synchronized (queryReplyListeners) { List<QueryReplyListener> listeners = queryReplyListeners.get(guid); if (listeners == null) { listeners = new CopyOnWriteArrayList<QueryReplyListener>(); queryReplyListeners.put(guid, listeners); } listeners.add(listener); } } @Override public void removeQueryReplyListener(byte[] guid, QueryReplyListener listener) { synchronized (queryReplyListeners) { List<QueryReplyListener> listeners = queryReplyListeners.get(guid); if (listeners != null) { listeners.remove(listener); if (listeners.isEmpty()) { queryReplyListeners.remove(guid); } } } } @Override public void addDownloadListener(DownloadListener listener) { downloadListeners.add(listener); } @Override public void removeDownloadListener(DownloadListener listener) { downloadListeners.remove(listener); } @Override public void handleMagnets(MagnetOptions[] magnets) { if(guiCallback != null) { for(MagnetOptions magnetOption : magnets) { guiCallback.handleMagnet(new MagnetLinkImpl(magnetOption)); } } } @Override public void handleQueryResult(RemoteFileDesc rfd, QueryReply queryReply, Set<? extends IpPort> locs) { List<QueryReplyListener> listeners = queryReplyListeners.get(queryReply.getGUID()); if (listeners != null) { for (QueryReplyListener listener : listeners) { listener.handleQueryReply(rfd, queryReply, locs); } } } // TODO: address and port - are ignored @Override public void handleQuery(QueryRequest query, String address, int port) { for (IncomingSearchListener listener : monitorListeners) { listener.handleQueryString(query.getQuery()); } } public void handleSharedFileUpdate(File file) { //TODO PJV this looks like it is supposed to update the gui with the meta data changes about how many hits this file received in searches and how many times it has been uploaded. //Can we get rid of this now and use a property listener when we need this data again? could fireProperty events when incrementHitcount etc. are called } @Override public void handleTorrent(final File torrentFile) { if(torrentFile != null && torrentFile.exists() && torrentFile.length() > 0) { try { downloadManager.downloadTorrent(torrentFile, null, false); } catch (DownloadException e) { handleDownloadException(new DownloadAction() { @Override public void download(File saveDirectory, boolean overwrite) throws DownloadException { downloadManager.downloadTorrent(torrentFile, saveDirectory, overwrite); } @Override public void downloadCanceled(DownloadException ignored) { //nothing to do } },e,false); } } } @Override public void installationCorrupted() { MessageService.showError(I18nMarker.marktr("<html><b>Your LimeWire may have been corrupted by a virus or trojan!</b></html>")); } @Override public boolean isQueryAlive(GUID guid) { return queryReplyListeners.containsKey(guid.bytes()); } @Override public void addUpload(Uploader u) { for (UploadListener listener : uploadListeners) { listener.uploadAdded(u); } } @Override public void uploadComplete(Uploader u) { for (UploadListener listener : uploadListeners) { listener.uploadComplete(u); } } @Override public void restoreApplication() { if(guiCallback != null) { guiCallback.restoreApplication(); } } @Override public String translate(String s) { if(guiCallback != null) { return guiCallback.translate(s); } return s; } @Override public void uploadsComplete() { for (UploadListener listener : uploadListeners) { listener.uploadsCompleted(); } } @Override public void addDownload(Downloader d) { for (DownloadListener listener : downloadListeners) { listener.downloadAdded(d); } } @Override public void downloadsComplete() { for (DownloadListener listener : downloadListeners) { listener.downloadsCompleted(); } } @Override public void promptAboutUnscannedPreview(Downloader dloader) { if(guiCallback == null) { dloader.discardUnscannedPreview(true); } else { // FIXME: replace this with a proper warning message String msg = I18nMarker.marktr("The file could not be scanned for viruses. Preview anyway?"); boolean previewAnyway = guiCallback.promptUserQuestion(msg); dloader.discardUnscannedPreview(!previewAnyway); } } @Override public void removeDownload(Downloader d) { for (DownloadListener listener : downloadListeners) { listener.downloadRemoved(d); } } public void setGuiCallback(GuiCallback guiCallback) { this.guiCallback = guiCallback; } @Override public void handleDownloadException(DownloadAction downLoadAction, DownloadException e, boolean supportsNewSaveDir) { if(guiCallback != null) { guiCallback.handleDownloadException(downLoadAction, e, supportsNewSaveDir); } else { ErrorService.error(e, "Error handling DownloadException. GuiCallBack not yet initialized."); } } @Override public void addUploadListener(UploadListener listener) { uploadListeners.add(listener); } @Override public void removeUploadListener(UploadListener listener) { uploadListeners.remove(listener); } @Override public void addIncomingSearchListener(IncomingSearchListener listener) { monitorListeners.add(listener); } @Override public void removeIncomingSearchListener(IncomingSearchListener listener) { monitorListeners.remove(listener); } @Override public boolean promptTorrentFilePriorities(Torrent torrent) { if(guiCallback != null && torrent.hasMetaData()) { return guiCallback.promptTorrentFilePriorities(torrent); } return true; } /** * Asks the user whether to continue with a torrent download that contains * files with banned extensions. * @return true if the download should continue. */ @Override public boolean promptAboutTorrentWithBannedExtensions(Torrent torrent, Set<String> bannedExtensions) { if(guiCallback != null) return guiCallback.promptAboutTorrentWithBannedExtensions(torrent, bannedExtensions); return true; } /** * Asks the user whether to continue with a torrent if scanning the torrent file failed. * @return true if the download should continue. */ @Override public boolean promptAboutTorrentDownloadWithFailedScan() { if (guiCallback != null) return guiCallback.promptAboutTorrentDownloadWithFailedScan(); return true; } }