package org.gudy.azureus2.core3.global.impl;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.download.DownloadManager;
import org.gudy.azureus2.core3.download.DownloadManagerFactory;
import org.gudy.azureus2.core3.download.DownloadManagerInitialisationAdapter;
import org.gudy.azureus2.core3.global.GlobalManager;
import org.gudy.azureus2.core3.global.GlobalManagerDownloadRemovalVetoException;
import org.gudy.azureus2.core3.global.GlobalManagerDownloadWillBeRemovedListener;
import org.gudy.azureus2.core3.global.GlobalManagerListener;
import org.gudy.azureus2.core3.torrent.TOTorrent;
import org.gudy.azureus2.core3.torrent.TOTorrentException;
import org.gudy.azureus2.core3.util.AEMonitor;
import org.gudy.azureus2.core3.util.Constants;
import org.gudy.azureus2.core3.util.FileUtil;
import org.gudy.azureus2.core3.util.HashWrapper;
import org.gudy.azureus2.core3.util.SystemTime;
import org.gudy.azureus2.plugins.dht.mainline.MainlineDHTProvider;
import org.gudy.azureus2.plugins.download.Download;
import org.merapi.helper.messages.DLControlMessage;
import org.millipede.download.AbstractDownloadManager;
import org.millipede.download.TestEventHandler;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;
import org.torrent.data.ProcessInfo;
import org.torrent.internal.client.Client;
import org.torrent.internal.data.MetaInfoFile;
import org.torrent.transfer.Transfer;
public class GlobalManagerImpl implements GlobalManager, BundleActivator {
// private Map<String, String> statusMap = new HashMap<String, String>();
private Map<String, MetaInfoFile> map = new HashMap<String, MetaInfoFile>();
private Map<String, ProcessInfo> statusMap = new HashMap<String, ProcessInfo>();
private Map<String, AbstractDownloadManager> dlmanager = new HashMap<String, AbstractDownloadManager>();
private static ExecutorService executor = new ScheduledThreadPoolExecutor(10);
Future<Transfer> future;
/** Whether loading of existing torrents is done */
boolean loadingComplete = false;
private volatile boolean needsSaving = false;
private List<DownloadManager> managers_cow = new ArrayList<DownloadManager>();
private AEMonitor managers_mon = new AEMonitor("GM:Managers");
private static GlobalManager instance = new GlobalManagerImpl();
/**
* Statische Methode, liefert die einzige Instanz dieser Klasse zur�ck
*/
public static GlobalManager getInstance() {
return instance;
}
/**
* @return the map
*/
public Map<String, MetaInfoFile> getMap() {
return map;
}
/**
* @param map the map to set
*/
public void setMap(Map<String, MetaInfoFile> map) {
this.map = map;
}
/**
* @return the statusMap
*/
public Map<String, ProcessInfo> getStatusMap() {
return statusMap;
}
/**
* @param statusMap the statusMap to set
*/
public void setStatusMap(Map<String, ProcessInfo> statusMap) {
this.statusMap = statusMap;
}
/**
* @return the dlmanager
*/
public Map<String, AbstractDownloadManager> getDlmanager() {
return dlmanager;
}
/**
* @param dlmanager the dlmanager to set
*/
public void setDlmanager(Map<String, AbstractDownloadManager> dlmanager) {
this.dlmanager = dlmanager;
}
private BundleContext bctx;
private ServiceRegistration reg;
private ServiceRegistration global;
@Override
public void start(BundleContext context) throws Exception {
global = context.registerService(GlobalManager.class.getName(), new GlobalManagerImpl(), null);
loadDownloads();
ServiceReference gmRef = context.getServiceReference(GlobalManager.class.getName());
GlobalManager gm = (GlobalManager) context.getService(gmRef);
bctx = context;
Dictionary props = new Hashtable();
// props.put(EventConstants.EVENT_TOPIC, "es/schaaf/*");
props.put(EventConstants.EVENT_TOPIC, DLControlMessage.DL_CONTROL + "/*");
// props.put(EventConstants.EVENT_TOPIC, DLControlRespondMessage.DL_CONTROL_RESPOND+"/*");
reg = bctx.registerService(EventHandler.class.getName(), new TestEventHandler(gm), props);
}
@Override
public void stop(BundleContext context) throws Exception {
stopGlobalManager();
global.unregister();
reg.unregister();
}
@Override
public void addDownloadManager(String fileName, AbstractDownloadManager dlmanager) {
if ((getDownloadManager(fileName) == null) && (dlmanager == null)) {
DownloadManager new_manager = DownloadManagerFactory.create(this);
this.getDlmanager().put(fileName, (AbstractDownloadManager) new_manager);
//Provider external DownloadManager created by another DownloadManagerFactory
} else if ((getDownloadManager(fileName) == null) && (dlmanager != null)) {
this.getDlmanager().put(fileName, dlmanager);
}
}
@Override
public Client addDownloadManager(String fileName) {
DownloadManager new_manager = DownloadManagerFactory.create(this, fileName);
this.getDlmanager().put(fileName, (AbstractDownloadManager) new_manager);
return (Client) new_manager;
}
@Override
public AbstractDownloadManager getDownloadManager(String fileName) {
return this.getDlmanager().get(fileName);
}
@Override
public DownloadManager addDownloadManager(String fileName, String savePath) {
// TODO Auto-generated method stub
return null;
}
@Override
public DownloadManager addDownloadManager(String fileName,
byte[] optionalHash, String savePath, int initialState,
boolean persistent) {
// TODO Auto-generated method stub
return null;
}
@Override
public DownloadManager addDownloadManager(String fileName,
byte[] optionalHash, String savePath, String saveFile,
int initialState, boolean persistent, boolean forSeeding,
DownloadManagerInitialisationAdapter adapter) {
// TODO Auto-generated method stub
return null;
}
@Override
public DownloadManager addDownloadManager(String fileName,
byte[] optionalHash, String savePath, int initialState,
boolean persistent, boolean forSeeding,
DownloadManagerInitialisationAdapter adapter) {
// TODO Auto-generated method stub
return null;
}
@Override
public void addDownloadWillBeRemovedListener(
GlobalManagerDownloadWillBeRemovedListener l) {
// TODO Auto-generated method stub
}
@Override
public void addListener(GlobalManagerListener l) {
// TODO Auto-generated method stub
}
@Override
public MainlineDHTProvider getMainlineDHTProvider() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean pauseDownload(DownloadManager dm) {
// TODO Auto-generated method stub
return false;
}
@Override
public void pauseDownloads() {
// TODO Auto-generated method stub
}
@Override
public void removeDownloadManager(DownloadManager dm)
throws GlobalManagerDownloadRemovalVetoException {
// TODO Auto-generated method stub
}
@Override
public void removeDownloadWillBeRemovedListener(
GlobalManagerDownloadWillBeRemovedListener l) {
// TODO Auto-generated method stub
}
@Override
public void removeListener(GlobalManagerListener l) {
// TODO Auto-generated method stub
}
@Override
public void resumeDownload(DownloadManager dm) {
resumeDownload((Client) dm);
}
private Future<Transfer> resumeDownload(Client dm) {
future = executor.submit(dm);
return future;
}
@Override
public void resumeDownloads() {
Collection<AbstractDownloadManager> c = this.dlmanager.values();
//obtain an Iterator for Collection
Iterator itr = c.iterator();
//iterate through HashMap values iterator
while (itr.hasNext()) {
try {
((Client) itr.next()).call();
} catch (IOException ex) {
Logger.getLogger(GlobalManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
Logger.getLogger(GlobalManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(GlobalManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
@Override
public void setMainlineDHTProvider(MainlineDHTProvider provider) {
// TODO Auto-generated method stub
}
private void loadDownloads() {
try {
ArrayList downloadsAdded = new ArrayList();
try {
Map map = FileUtil.readResilientConfigFile("downloads.config");
boolean debug = Boolean.getBoolean("debug");
Iterator iter = null;
// v2.0.3.0+ vs older mode
List downloads = (List) map.get("downloads");
int nbDownloads;
if (downloads == null) {
// No downloads entry, then use the old way
iter = map.values().iterator();
nbDownloads = map.size();
} else {
// New way, downloads stored in a list
iter = downloads.iterator();
nbDownloads = downloads.size();
}
int currentDownload = 0;
while (iter.hasNext()) {
currentDownload++;
Map mDownload = (Map) iter.next();
try {
byte[] torrent_hash = (byte[]) mDownload.get("torrent_hash");
Long lPersistent = (Long) mDownload.get("persistent");
boolean persistent = lPersistent == null
|| lPersistent.longValue() == 1;
String fileName = new String((byte[]) mDownload.get("torrent"), Constants.DEFAULT_ENCODING);
// if(progress_listener != null &&
// SystemTime.getCurrentTime() - lastListenerUpdate >
// 100) {
// lastListenerUpdate = SystemTime.getCurrentTime();
//
// String shortFileName = fileName;
// try {
// File f = new File(fileName);
// shortFileName = f.getName();
// } catch (Exception e) {
// // TODO: handle exception
// }
//
// progress_listener.reportPercent(100 * currentDownload
// / nbDownloads);
// //
// progress_listener.reportCurrentTask(MessageText.getString("splash.loadingTorrent")
// // + " " + currentDownload + " "
// // + MessageText.getString("splash.of") + " " +
// nbDownloads
// // + " : " + shortFileName );
// }
// migration from using a single savePath to a separate
// dir and file entry
String torrent_save_dir;
String torrent_save_file;
byte[] torrent_save_dir_bytes = (byte[]) mDownload.get("save_dir");
if (torrent_save_dir_bytes != null) {
byte[] torrent_save_file_bytes = (byte[]) mDownload.get("save_file");
torrent_save_dir = new String(
torrent_save_dir_bytes,
Constants.DEFAULT_ENCODING);
if (torrent_save_file_bytes != null) {
torrent_save_file = new String(
torrent_save_file_bytes,
Constants.DEFAULT_ENCODING);
} else {
torrent_save_file = null;
}
} else {
byte[] savePathBytes = (byte[]) mDownload.get("path");
torrent_save_dir = new String(savePathBytes,
Constants.DEFAULT_ENCODING);
torrent_save_file = null;
}
int state = DownloadManager.STATE_WAITING;
// if (debug){
//
// state = DownloadManager.STATE_STOPPED;
//
// }else {
//
if (mDownload.containsKey("state")) {
state = ((Long) mDownload.get("state")).intValue();
// if (state != DownloadManager.STATE_STOPPED &&
// state != DownloadManager.STATE_QUEUED &&
// state != DownloadManager.STATE_WAITING)
//
// state = DownloadManager.STATE_QUEUED;
}
// }else{
//
// int stopped = ((Long)
// mDownload.get("stopped")).intValue();
//
// if (stopped == 1){
//
// state = DownloadManager.STATE_STOPPED;
// }
// }
// }
//
Long seconds_downloading = (Long) mDownload.get("secondsDownloading");
boolean has_ever_been_started = seconds_downloading != null
&& seconds_downloading.longValue() > 0;
//
// if (torrent_hash != null) {
// saved_download_manager_state.put(new
// HashWrapper(torrent_hash),
// mDownload);
// }
// for non-persistent downloads the state will be picked
// up if the download is re-added
// it won't get saved unless it is picked up, hence dead
// data is dropped as required
if (persistent) {
List file_priorities = (List) mDownload.get("file_priorities");
final DownloadManager dm = DownloadManagerFactory.create(this, torrent_hash, fileName,
torrent_save_dir,
torrent_save_file, state, true,
true, has_ever_been_started,
file_priorities);
// if (addDownloadManager(dm, false, false) == dm) {
// downloadsAdded.add(dm);
//
// if (downloadsAdded.size() >= triggerOnCount) {
// triggerOnCount *= 2;
// triggerAddListener(downloadsAdded);
// downloadsAdded.clear();
// }
// }
}
} catch (UnsupportedEncodingException e1) {
// Do nothing and process next.
} catch (Throwable e) {
// Logger.log(new LogEvent(LOGID,
// "Error while loading downloads. " +
// "One download may not have been added to the list.",
// e));
}
}
// // This is set to true by default, but once the downloads
// have been loaded, we have no reason to ever
// // to do this check again - we only want to do it once to
// upgrade the state of existing downloads
// // created before this code was around.
// COConfigurationManager.setParameter("Set Completion Flag For Completed Downloads On Start",
// false);
//
// //load pause/resume state
// ArrayList pause_data = (ArrayList)map.get( "pause_data" );
// if( pause_data != null ) {
// try { paused_list_mon.enter();
// for( int i=0; i < pause_data.size(); i++ ) {
// Object pd = pause_data.get(i);
//
// byte[] key;
// boolean force;
//
// if ( pd instanceof byte[]){
// // old style, migration purposes
// key = (byte[])pause_data.get( i );
// force = false;
// }else{
// Map m = (Map)pd;
//
// key = (byte[])m.get("hash");
// force = ((Long)m.get("force")).intValue() == 1;
// }
// paused_list.add( new Object[]{ new HashWrapper( key ), new
// Boolean( force )} );
// }
// }
// finally { paused_list_mon.exit(); }
// }
// Someone could have mucked with the config file and set weird
// positions,
// so fix them up.
// fixUpDownloadManagerPositions();
// Logger.log(new LogEvent(LOGID, "Loaded " +
// managers_cow.size()
// + " torrents"));
} catch (Throwable e) {
// there's been problems with corrupted download files stopping
// AZ from starting
// added this to try and prevent such foolishness
// Debug.printStackTrace( e );
} finally {
loadingComplete = true;
// triggerAddListener(downloadsAdded);
// loadingSem.releaseForever();
}
} finally {
// DownloadManagerStateFactory.discardGlobalStateCache();
}
}
protected void saveDownloads(boolean immediate) {
// if ( !immediate ){
//
// needsSaving = true;
//
// return;
// }
//
// if (!loadingComplete) {
// needsSaving = true;
// return;
// }
// if(Boolean.getBoolean("debug")) return;
needsSaving = false;
// if (this.cripple_downloads_config) {
// return;
// }
try {
managers_mon.enter();
Collections.sort(managers_cow, new Comparator() {
public final int compare(Object a, Object b) {
return ((DownloadManager) a).getPosition()
- ((DownloadManager) b).getPosition();
}
});
// if (Logger.isEnabled())
// Logger.log(new LogEvent(LOGID, "Saving Download List ("
// + managers_cow.size() + " items)"));
Map map = new HashMap();
List list = new ArrayList(managers_cow.size());
for (int i = 0; i < managers_cow.size(); i++) {
DownloadManager dm = (DownloadManager) managers_cow.get(i);
// DownloadManagerStats dm_stats = dm.getStats();
Map dmMap = new HashMap();
TOTorrent torrent = dm.getTorrent();
if (torrent != null) {
try {
dmMap.put("torrent_hash", torrent.getHash());
} catch (TOTorrentException e) {
// Debug.printStackTrace(e);
}
}
File save_loc = dm.getAbsoluteSaveLocation();
dmMap.put("persistent", new Long(dm.isPersistent() ? 1 : 0));
dmMap.put("torrent", dm.getTorrentFileName());
dmMap.put("save_dir", save_loc.getParent());
dmMap.put("save_file", save_loc.getName());
// dmMap.put("maxdl", new Long(
// dm_stats.getDownloadRateLimitBytesPerSecond() ));
// dmMap.put("maxul", new Long(
// dm_stats.getUploadRateLimitBytesPerSecond() ));
int state = dm.getState();
// if (state == DownloadManager.STATE_ERROR ){
//
// // torrents in error state always come back stopped
//
// state = DownloadManager.STATE_STOPPED;
//
// }else if ( dm.getAssumedComplete() && !dm.isForceStart() &&
// state != DownloadManager.STATE_STOPPED) {
//
// state = DownloadManager.STATE_QUEUED;
//
// }else if ( state != DownloadManager.STATE_STOPPED &&
// state != DownloadManager.STATE_QUEUED &&
// state != DownloadManager.STATE_WAITING){
//
// state = DownloadManager.STATE_WAITING;
//
// }
dmMap.put("state", new Long(state));
dmMap.put("position", new Long(dm.getPosition()));
// dmMap.put("downloaded", new
// Long(dm_stats.getTotalDataBytesReceived()));
// dmMap.put("uploaded", new
// Long(dm_stats.getTotalDataBytesSent()));
// dmMap.put("completed", new
// Long(dm_stats.getDownloadCompleted(true)));
// dmMap.put("discarded", new Long(dm_stats.getDiscarded()));
// dmMap.put("hashfailbytes", new
// Long(dm_stats.getHashFailBytes()));
// dmMap.put("forceStart", new Long(dm.isForceStart() &&
// (dm.getState() != DownloadManager.STATE_CHECKING) ? 1 : 0));
// dmMap.put("secondsDownloading", new
// Long(dm_stats.getSecondsDownloading()));
// dmMap.put("secondsOnlySeeding", new
// Long(dm_stats.getSecondsOnlySeeding()));
// although this has been migrated, keep storing it to allow
// regression for a while
dmMap.put("uploads", new Long(dm.getMaxUploads()));
dmMap.put("creationTime", new Long(dm.getCreationTime()));
// save file priorities
dm.saveDownload();
List file_priorities = (List) dm.getData("file_priorities");
if (file_priorities != null) {
dmMap.put("file_priorities", file_priorities);
}
dmMap.put("allocated", new Long(
dm.isDataAlreadyAllocated() == true ? 1 : 0));
list.add(dmMap);
}
map.put("downloads", list);
// save pause/resume state
// try { paused_list_mon.enter();
// if( !paused_list.isEmpty() ) {
// ArrayList pause_data = new ArrayList();
// for( int i=0; i < paused_list.size(); i++ ) {
// Object[] data = (Object[])paused_list.get(i);
//
// HashWrapper hash = (HashWrapper)data[0];
// Boolean force = (Boolean)data[1];
//
// Map m = new HashMap();
//
// m.put( "hash", hash.getHash());
// m.put( "force", new Long(force.booleanValue()?1:0));
//
// pause_data.add( m );
// }
// map.put( "pause_data", pause_data );
// }
// }
// finally { paused_list_mon.exit(); }
FileUtil.writeResilientConfigFile("downloads.config", map);
} finally {
managers_mon.exit();
}
}
/*
* Puts GlobalManager in a stopped state. Used when closing down Azureus.
*/
public void stopGlobalManager() {
// try {
// managers_mon.enter();
//
// if (isStopping) {
//
// return;
// }
//
// isStopping = true;
//
// } finally {
//
// managers_mon.exit();
// }
// stats.save();
//
// informDestroyInitiated();
//
// if ( host_support != null ){
// host_support.destroy();
// }
//
// torrent_folder_watcher.destroy();
// kick off a non-daemon task. This will ensure that we hang around
// for at least LINGER_PERIOD to run other non-daemon tasks such as
// writing
// torrent resume data...
// try{
// NonDaemonTaskRunner.run(
// new NonDaemonTask()
// {
// public Object
// run()
// {
// return( null );
// }
//
// public String
// getName()
// {
// return( "Stopping global manager" );
// }
// });
// }catch( Throwable e ){
// Debug.printStackTrace( e );
// }
// checker.stopIt();
// if (COConfigurationManager
// .getBooleanParameter("Pause Downloads On Exit")) {
//
// pauseDownloads(true);
//
// // do this before save-downloads so paused state gets saved
//
// stopAllDownloads(true);
//
// saveDownloads(true);
//
// } else {
saveDownloads(true);
// stopAllDownloads(true);
// }
// if ( stats_writer != null ){
//
// stats_writer.destroy();
// }
// DownloadManagerStateFactory.saveGlobalStateCache();
managers_cow = new ArrayList();
// manager_map.clear();
// informDestroyed();
}
}